1<?php
2/**
3 * ODT Plugin: Exports to ODT
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
7 * @author Aurelien Bompard <aurelien@bompard.org>
8 */
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12require_once DOKU_PLUGIN . 'odt/helper/cssimport.php';
13require_once DOKU_PLUGIN . 'odt/ODT/ODTDefaultStyles.php';
14
15// Central class for ODT export
16require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
17
18/**
19 * The Page Renderer
20 *
21 * @package DokuWiki\Renderer\Page
22 */
23class renderer_plugin_odt_page extends Doku_Renderer {
24    /** @var helper_plugin_odt_cssimport */
25    protected $import = null;
26    /** @var helper_plugin_odt_config */
27    protected $config = null;
28    protected $document = null;
29    /** @var string */
30    protected $css;
31    /** @var bool */
32    protected $init_ok;
33
34    /**
35     * Constructor. Loads helper plugins.
36     */
37    public function __construct() {
38        // Set up empty array with known config parameters
39        $this->config = plugin_load('helper', 'odt_config');
40
41        // Create and initialize document
42        $this->document = new ODTDocument();
43        $this->init_ok = $this->document->initialize ();
44    }
45
46    /**
47     * Set a config parameter from extern.
48     */
49    public function setConfigParam($name, $value) {
50        $this->config->setParam($name, $value);
51    }
52
53    /**
54     * Is the $string specified the name of a ODT plugin config parameter?
55     *
56     * @return bool Is it a config parameter?
57     */
58    public function isConfigParam($string) {
59        return $this->config->isParam($string);
60    }
61
62    /**
63     * Returns the format produced by this renderer.
64     */
65    function getFormat(){
66        return "odt";
67    }
68
69    /**
70     * Do not make multiple instances of this class
71     */
72    function isSingleton(){
73        return true;
74    }
75
76    public function replaceURLPrefixesCallback ($property, $value, $url) {
77        if (strncmp($url, '/lib/plugins', strlen('/lib/plugins')) == 0) {
78            return DOKU_INC.substr($url,1);
79        }
80        return $url;
81    }
82
83    /**
84     * Load and imports CSS.
85     */
86    protected function load_css() {
87        global $conf, $lang;
88
89        /** @var helper_plugin_odt_dwcssloader $loader */
90        $loader = plugin_load('helper', 'odt_dwcssloader');
91        if ( $loader != NULL ) {
92            $this->css = $loader->load
93                ('odt', 'odt', $this->config->getParam('css_template'));
94        }
95
96        // Import CSS (old API, deprecated)
97        $this->import = plugin_load('helper', 'odt_cssimport');
98        if ( $this->import != NULL ) {
99            $this->import->importFromString ($this->css);
100
101            // Call adjustLengthValues to make our callback function being called for every
102            // length value imported. This gives us the chance to convert it once from
103            // pixel to points.
104            $this->import->adjustLengthValues (array($this, 'adjustLengthCallback'));
105        }
106
107        // Set CSS usage according to configuration
108        switch ($this->config->getParam('css_usage')) {
109            case 'basic style import':
110                $this->document->setCSSUsage('basic');
111                break;
112            case 'full':
113                $this->document->setCSSUsage('full');
114                break;
115            default:
116                $this->document->setCSSUsage('off');
117                break;
118        }
119        $this->document->setMediaSelector ($this->config->getParam('media_sel'));
120
121        // Put some root element on the HTML stack which should always
122        // be present for our CSS matching
123        $this->document->addHTMLElement ('html', 'lang="'.$conf['lang'].'" dir="'.$lang['direction'].'"');
124        $this->document->addHTMLElement ('body');
125        $this->document->addHTMLElement ('div', 'id="dokuwiki__site"');
126        $this->document->addHTMLElement ('div', 'id="dokuwiki__top" class="site dokuwiki mode_show tpl_adoradark loggedIn"');
127        $this->document->addHTMLElement ('div', 'id="dokuwiki__content"');
128        $this->document->addHTMLElement ('div', 'class="page group"');
129
130        // Import CSS (new API)
131        $this->document->importCSSFromString
132            ($this->css, $this->config->getParam('media_sel'), array($this, 'replaceURLPrefixesCallback'), false, $this->config->getParam('olist_label_align'));
133    }
134
135    /**
136     * Configure units to our configuration values.
137     */
138    protected function setupUnits()
139    {
140        $this->document->setPixelPerEm($this->config->getParam ('css_font_size'));
141        $this->document->setTwipsPerPixelX($this->config->getParam ('twips_per_pixel_x'));
142        $this->document->setTwipsPerPixelY($this->config->getParam ('twips_per_pixel_y'));
143    }
144
145    /**
146     * Initialize the document,
147     * Do the things that are common to all documents regardless of the
148     * output format (ODT or PDF).
149     */
150    function document_setup()
151    {
152        global $ID;
153
154        // First, get export mode.
155        $warning = '';
156        $mode = $this->config->load($warning);
157
158        // Setup Units before CSS import!
159        $this->setupUnits();
160
161        switch($mode) {
162            case 'ODT template':
163            case 'CSS template':
164                break;
165            default:
166                // Set ordered list alignment before calling load_css().
167                // load_css() will eventually overwrite the list settings!
168                $this->document->setOrderedListParams(NULL, $this->config->getParam('olist_label_align'));
169                $this->document->setUnorderedListParams(NULL, $this->config->getParam('olist_label_align'));
170                break;
171        }
172
173        // Import CSS files
174        $this->load_css();
175
176        switch($mode) {
177            case 'ODT template':
178                // Document based on ODT template.
179                $this->buildODTPathes ($ODTtemplate, $temp_dir);
180                $this->document->importODTStyles($ODTtemplate, $temp_dir);
181
182                if ($this->config->getParam ('apply_fs_to_non_css')) {
183                    $this->document->adjustFontSizes($this->config->getParam('css_font_size').'pt');
184                }
185                break;
186
187            case 'CSS template':
188                // Document based on DokuWiki CSS template.
189                $media_sel = $this->config->getParam ('media_sel');
190                $template = $this->config->getParam ('odt_template');
191                $directory = $this->config->getParam ('tpl_dir');
192                $template_path = $this->config->getParam('mediadir').'/'.$directory."/".$template;
193                $this->document->importCSSFromFile
194                    ($template_path, $media_sel, array($this, 'replaceURLPrefixesCallback'), $this->config->getParam('olist_label_align'));
195
196                // Set outline style.
197                $this->document->setOutlineStyle($this->config->getParam('outline_list_style'));
198                break;
199
200            default:
201                // Document from scratch.
202
203                // Set outline style.
204                $this->document->setOutlineStyle($this->config->getParam('outline_list_style'));
205
206                if ($this->config->getParam ('apply_fs_to_non_css')) {
207                    $this->document->adjustFontSizes($this->config->getParam('css_font_size').'pt');
208                }
209                break;
210        }
211
212        // If we are using ODT for style import (a template or the default 'styles.xml')
213        // then adjust the pixel per em value to the font-size of the default paragraph style
214        // otherwise plugins might inherit a wrong font-size on CSS import!
215        if ($mode != 'CSS template') {
216            $default = $this->document->getDefaultStyle ('paragraph');
217            if ($default != NULL) {
218                $fontFize = $default->getProperty('font-size');
219                if (!empty($fontFize)) {
220                    $fontFizeInPx = $this->document->toPixel($fontFize);
221                    if (!empty($fontFizeInPx)) {
222                        $this->document->setPixelPerEm($fontFizeInPx);
223                    }
224                }
225            }
226        }
227
228        // Setup page format.
229        $this->document->setStartPageFormat ($this->config->getParam ('format'),
230                                             $this->config->getParam ('orientation'),
231                                             $this->config->getParam ('margin_top'),
232                                             $this->config->getParam ('margin_right'),
233                                             $this->config->getParam ('margin_bottom'),
234                                             $this->config->getParam ('margin_left'));
235
236        // Set title in meta info.
237        // FIXME article title != book title  SOLUTION: overwrite at the end for book
238        $this->document->setTitle($ID);
239
240        // Enable/disable links according to configuration
241        $disabled = $this->config->getParam ('disable_links');
242        if ($disabled) {
243            $this->document->disableLinks();
244        } else {
245            $this->document->enableLinks();
246        }
247
248        $this->set_page_bookmark($ID);
249    }
250
251    /**
252     * Initialize the rendering
253     */
254    function document_start() {
255        global $ID;
256
257        if (!$this->init_ok) {
258            // Initialization of the ODT document failed!
259            // Send "Internal Server Error"
260            http_status(500);
261            $message = $this->getLang('init_failed_msg');
262            $message = str_replace('%DWVERSION%', getVersion(), $message);
263            $instructions = p_get_instructions($message);
264            print p_render('xhtml', $instructions, $info);
265
266            exit;
267        }
268
269        // Initialize the document
270        $this->document_setup();
271
272        // Create HTTP headers
273        $output_filename = str_replace(':','-',$ID).'.odt';
274        $headers = array(
275            'Content-Type' => 'application/vnd.oasis.opendocument.text',
276            'Content-Disposition' => 'attachment; filename="'.$output_filename.'";',
277        );
278
279        // store the content type headers in metadata
280        p_set_metadata($ID,array('format' => array('odt_page' => $headers) ));
281    }
282
283    /**
284     * Closes the document
285     */
286    function document_end(){
287        // Build the document
288        $this->finalize_ODTfile();
289
290        // Refresh certain config parameters e.g. 'disable_links'
291        $this->config->refresh();
292
293        // Reset state.
294        $this->document->state->reset();
295    }
296
297    /**
298     * This function sets the page format.
299     * The format, orientation and page margins can be changed.
300     * See function queryFormat() in ODT/page.php for supported formats.
301     *
302     * @param string  $format         e.g. 'A4', 'A3'
303     * @param string  $orientation    e.g. 'portrait' or 'landscape'
304     * @param numeric $margin_top     Top-Margin in cm, default 2
305     * @param numeric $margin_right   Right-Margin in cm, default 2
306     * @param numeric $margin_bottom  Bottom-Margin in cm, default 2
307     * @param numeric $margin_left    Left-Margin in cm, default 2
308     * @see ODTDocument::setPageFormat
309     */
310    public function setPageFormat ($format=NULL, $orientation=NULL, $margin_top=NULL, $margin_right=NULL, $margin_bottom=NULL, $margin_left=NULL) {
311        $this->document->setPageFormat ($format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left);
312    }
313
314    /**
315     * Completes the ODT file.
316     */
317    public function finalize_ODTfile() {
318        global $ID;
319
320        $this->buildODTPathes ($ODTtemplate, $temp_dir);
321
322        // Build/assign the document
323        $this->doc = $this->document->getODTFileAsString ($ODTtemplate, $temp_dir);
324    }
325
326    /**
327     * Simple setter to enable creating links.
328     */
329    function enable_links() {
330        $this->config->setParam ('disable_links', false);
331        $this->document->enableLinks();
332    }
333
334    /**
335     * Simple setter to disable creating links.
336     */
337    function disable_links() {
338        $this->config->setParam ('disable_links', true);
339        $this->document->disableLinks();
340    }
341
342    /**
343     * Dummy function.
344     *
345     * @return string
346     */
347    function render_TOC() {
348        return '';
349    }
350
351    /**
352     * This function does not really render an index but inserts a placeholder.
353     *
354     * @return string
355     * @see ODTDocument::insertIndex for API wrapper function
356     * @see ODTIndex::insertIndex for more information
357     */
358    function render_index($type='toc', $settings=NULL) {
359        $data = array();
360        $data = $this->get_index_settings($type, $settings);
361        $this->document->insertIndex($type, $data);
362        return '';
363    }
364
365    /**
366     * This function detmerines the settings for a TOC or chapter index.
367     * The layout settings are taken from the configuration and $settings.
368     * The result is returned as an array.
369     *
370     * $settings can include the following options syntax:
371     * - Title e.g. 'title=Example;'.
372     *   Default is 'Table of Contents' (for english, see language files for other languages default value).
373     * - Leader sign, e.g. 'leader-sign=.;'.
374     *   Default is '.'.
375     * - Indents (in cm), e.g. 'indents=indents=0,0.5,1,1.5,2,2.5,3;'.
376     *   Default is 0.5 cm indent more per level.
377     * - Maximum outline/TOC level, e.g. 'maxtoclevel=5;'.
378     *   Default is taken from DokuWiki config setting 'maxtoclevel'.
379     * - Insert pagebreak after TOC, e.g. 'pagebreak=1;'.
380     *   Default is '1', means insert pagebreak after TOC.
381     * - Set style per outline/TOC level, e.g. 'styleL2="color:red;font-weight:900;";'.
382     *   Default is 'color:black'.
383     *
384     * It is allowed to use defaults for all settings by omitting $settings.
385     * Multiple settings can be combined, e.g. 'leader-sign=.;indents=0,0.5,1,1.5,2,2.5,3;'.
386     */
387    protected function get_index_settings($type, $settings) {
388        $matches = array();
389        $data = array();
390
391        $data ['numbered_headings'] = false;
392        if ($this->config->getParam('outline_list_style') == 'Numbers') {
393            $data ['numbered_headings'] = true;
394        }
395
396        // It seems to be not supported in ODT to have a different start
397        // outline level than 1.
398        $data ['maxlevel'] = $this->config->getParam('toc_maxlevel');
399        if ( preg_match('/maxlevel=[^;]+;/', $settings, $matches) === 1 ) {
400            $temp = substr ($matches [0], 9);
401            $temp = trim ($temp, ';');
402            $data ['maxlevel'] = $temp;
403        }
404
405        // Determine title, default for table of contents is 'Table of Contents'.
406        // Default for chapter index is empty.
407        // Syntax for 'Test' as title would be "title=test;".
408        $data ['title'] = '';
409        if ($type == 'toc') {
410            $data ['title'] = $this->getLang('toc_title');
411        }
412        if ( preg_match('/title=[^;]+;/', $settings, $matches) === 1 ) {
413            $temp = substr ($matches [0], 6);
414            $temp = trim ($temp, ';');
415            $data ['title'] = $temp;
416        }
417
418        // Determine leader-sign, default is '.'.
419        // Syntax for '.' as leader-sign would be "leader_sign=.;".
420        $data ['leader_sign'] = $this->config->getParam('toc_leader_sign');
421        if ( preg_match('/leader_sign=[^;]+;/', $settings, $matches) === 1 ) {
422            $temp = substr ($matches [0], 12);
423            $temp = trim ($temp, ';');
424            $data ['leader_sign'] = $temp [0];
425        }
426
427        // Determine indents, default is '0.5' (cm) per level.
428        // Syntax for a indent of '0.5' for 5 levels would be "indents=0,0.5,1,1.5,2;".
429        // The values are absolute for each level, not relative to the higher level.
430        $data ['indents'] = explode (',', $this->config->getParam('toc_indents'));
431        if ( preg_match('/indents=[^;]+;/', $settings, $matches) === 1 ) {
432            $temp = substr ($matches [0], 8);
433            $temp = trim ($temp, ';');
434            $data ['indents'] = explode (',', $temp);
435        }
436
437        // Determine pagebreak, default is on '1'.
438        // Syntax for pagebreak off would be "pagebreak=0;".
439        $data ['pagebreak'] = $this->config->getParam('toc_pagebreak');
440        if ( preg_match('/pagebreak=[^;]+;/', $settings, $matches) === 1 ) {
441            $temp = substr ($matches [0], 10);
442            $temp = trim ($temp, ';');
443            $data ['pagebreak'] = 'false';
444            if ( $temp == '1' ) {
445                $data ['pagebreak'] = 'true';
446            } else if ( strcasecmp($temp, 'true') == 0 ) {
447                $data ['pagebreak'] = 'true';
448            }
449        }
450
451        // Determine text style for the index heading.
452        $data ['style_heading'] = NULL;
453        if ( preg_match('/styleH="[^"]+";/', $settings, $matches) === 1 ) {
454            $quote = strpos ($matches [0], '"');
455            $temp = substr ($matches [0], $quote+1);
456            $temp = trim ($temp, '";');
457            $data ['style_heading'] = $temp.';';
458        }
459
460        // Determine text styles per level.
461        // Syntax for a style level 1 is "styleL1="color:black;"".
462        // The default style is just 'color:black;'.
463        for ( $count = 0 ; $count < $data ['maxlevel'] ; $count++ ) {
464            $data ['styleL'.($count + 1)] = $this->config->getParam('toc_style');
465            if ( preg_match('/styleL'.($count + 1).'="[^"]+";/', $settings, $matches) === 1 ) {
466                $quote = strpos ($matches [0], '"');
467                $temp = substr ($matches [0], $quote+1);
468                $temp = trim ($temp, '";');
469                $data ['styleL'.($count + 1)] = $temp.';';
470            }
471        }
472
473        return $data;
474    }
475
476    /**
477     * Add an item to the TOC
478     * (Dummy function required by the Doku_Renderer class)
479     *
480     * @param string $id       the hash link
481     * @param string $text     the text to display
482     * @param int    $level    the nesting level
483     */
484    function toc_additem($id, $text, $level) {}
485
486    /**
487     * Return total page width in centimeters
488     * (margins are included)
489     *
490     * @see ODTDocument::getWidth for API wrapper function
491     * @see pageFormat::getWidth for more information
492     * @author LarsDW223
493     */
494    function _getPageWidth(){
495        return $this->document->getWidth();
496    }
497
498    /**
499     * Return total page height in centimeters
500     * (margins are included)
501     *
502     * @see ODTDocument::getHeight for API wrapper function
503     * @see pageFormat::getHeight for more information
504     * @author LarsDW223
505     */
506    function _getPageHeight(){
507        return $this->document->getHeight();
508    }
509
510    /**
511     * Return left margin in centimeters
512     *
513     * @see ODTDocument::getMarginLeft for API wrapper function
514     * @see pageFormat::getMarginLeft for more information
515     * @author LarsDW223
516     */
517    function _getLeftMargin(){
518        return $this->document->getMarginLeft();
519    }
520
521    /**
522     * Return right margin in centimeters
523     *
524     * @see ODTDocument::getMarginRight for API wrapper function
525     * @see pageFormat::getMarginRight for more information
526     * @author LarsDW223
527     */
528    function _getRightMargin(){
529        return $this->document->getMarginRight();
530    }
531
532    /**
533     * Return top margin in centimeters
534     *
535     * @see ODTDocument::getMarginTop for API wrapper function
536     * @see pageFormat::getMarginTop for more information
537     * @author LarsDW223
538     */
539    function _getTopMargin(){
540        return $this->document->getMarginTop();
541    }
542
543    /**
544     * Return bottom margin in centimeters
545     *
546     * @see ODTDocument::getMarginBottom for API wrapper function
547     * @see pageFormat::getMarginBottom for more information
548     * @author LarsDW223
549     */
550    function _getBottomMargin(){
551        return $this->document->getMarginBottom();
552    }
553
554    /**
555     * Return width percentage value if margins are taken into account.
556     * Usually "100%" means 21cm in case of A4 format.
557     * But usually you like to take care of margins. This function
558     * adjusts the percentage to the value which should be used for margins.
559     * So 100% == 21cm e.g. becomes 80.9% == 17cm (assuming a margin of 2 cm on both sides).
560     *
561     * @param int|string $percentage
562     * @return int|string
563     *
564     * @see ODTDocument::getRelWidthMindMargins for API wrapper function
565     * @see pageFormat::getRelWidthMindMargins for more information
566     * @author LarsDW223
567     */
568    function _getRelWidthMindMargins ($percentage = '100'){
569        return $this->document->getRelWidthMindMargins($percentage);
570    }
571
572    /**
573     * Like _getRelWidthMindMargins but returns the absulute width
574     * in centimeters.
575     *
576     * @param string|int|float $percentage
577     * @return float
578     *
579     * @see ODTDocument::getAbsWidthMindMargins for API wrapper function
580     * @see pageFormat::getAbsWidthMindMargins for more information
581     * @author LarsDW223
582     */
583    function _getAbsWidthMindMargins ($percentage = '100'){
584        return $this->document->getAbsWidthMindMargins($percentage);
585    }
586
587    /**
588     * Return height percentage value if margins are taken into account.
589     * Usually "100%" means 29.7cm in case of A4 format.
590     * But usually you like to take care of margins. This function
591     * adjusts the percentage to the value which should be used for margins.
592     * So 100% == 29.7cm e.g. becomes 86.5% == 25.7cm (assuming a margin of 2 cm on top and bottom).
593     *
594     * @param string|float|int $percentage
595     * @return float|string
596     *
597     * @see ODTDocument::getRelHeightMindMargins for API wrapper function
598     * @see pageFormat::getRelHeightMindMargins for more information
599     * @author LarsDW223
600     */
601    function _getRelHeightMindMargins ($percentage = '100'){
602        return $this->document->getRelHeightMindMargins($percentage);
603    }
604
605    /**
606     * Like _getRelHeightMindMargins but returns the absulute width
607     * in centimeters.
608     *
609     * @param string|int|float $percentage
610     * @return float
611     *
612     * @see ODTDocument::getAbsHeightMindMargins for API wrapper function
613     * @see pageFormat::getAbsHeightMindMargins for more information
614     * @author LarsDW223
615     */
616    function _getAbsHeightMindMargins ($percentage = '100'){
617        return $this->document->getAbsHeightMindMargins($percentage);
618    }
619
620    /**
621     * Render plain text data.
622     *
623     * @param string $text
624     * @see ODTDocument::addPlainText for more information
625     */
626    function cdata($text) {
627        $this->document->addPlainText($text);
628    }
629
630    /**
631     * Open a paragraph.
632     *
633     * @param string $style Name of the style to use for the paragraph
634     *
635     * @see ODTDocument::paragraphOpen for API wrapper function
636     * @see ODTParagraph::paragraphOpen for more information
637     */
638    function p_open($style=NULL){
639        $this->document->paragraphOpen($style);
640    }
641
642    /**
643     * Close a paragraph.
644     *
645     * @see ODTDocument::paragraphClose for API wrapper function
646     * @see ODTParagraph::paragraphClose for more information
647     */
648    function p_close(){
649        $this->document->paragraphClose();
650    }
651
652    /**
653     * Set bookmark for the start of the page. This just saves the title temporarily.
654     * It is then to be inserted in the first header or paragraph.
655     *
656     * @param string $id    ID of the bookmark
657     */
658    function set_page_bookmark($id){
659        $this->document->setPageBookmark($id);
660    }
661
662    /**
663     * Render a heading
664     *
665     * @param string $text  the text to display
666     * @param int    $level header level
667     * @param int    $pos   byte position in the original source
668     */
669    function header($text, $level, $pos){
670        $this->document->heading($text, $level);
671    }
672
673    function hr() {
674        $this->document->horizontalRule();
675    }
676
677    function linebreak() {
678        $this->document->linebreak();
679    }
680
681    function pagebreak() {
682        $this->document->pagebreak();
683    }
684
685    function strong_open() {
686        $this->document->spanOpen($this->document->getStyleName('strong'));
687    }
688
689    function strong_close() {
690        $this->document->spanClose();
691    }
692
693    function emphasis_open() {
694        $this->document->spanOpen($this->document->getStyleName('emphasis'));
695    }
696
697    function emphasis_close() {
698        $this->document->spanClose();
699    }
700
701    function underline_open() {
702        $this->document->spanOpen($this->document->getStyleName('underline'));
703    }
704
705    function underline_close() {
706        $this->document->spanClose();
707    }
708
709    function monospace_open() {
710        $this->document->spanOpen($this->document->getStyleName('monospace'));
711    }
712
713    function monospace_close() {
714        $this->document->spanClose();
715    }
716
717    function subscript_open() {
718        $this->document->spanOpen($this->document->getStyleName('sub'));
719    }
720
721    function subscript_close() {
722        $this->document->spanClose();
723    }
724
725    function superscript_open() {
726        $this->document->spanOpen($this->document->getStyleName('sup'));
727    }
728
729    function superscript_close() {
730        $this->document->spanClose();
731    }
732
733    function deleted_open() {
734        $this->document->spanOpen($this->document->getStyleName('del'));
735    }
736
737    function deleted_close() {
738        $this->document->spanClose();
739    }
740
741    function generateSpansfromHTMLCode($HTMLCode){
742        $this->document->generateSpansfromHTMLCode($HTMLCode);
743    }
744
745    /*
746     * Tables
747     */
748
749    /**
750     * Start a table
751     *
752     * @param int $maxcols maximum number of columns
753     * @param int $numrows NOT IMPLEMENTED
754     */
755    function table_open($maxcols = NULL, $numrows = NULL, $pos = NULL){
756        $this->document->tableOpen($maxcols, $numrows);
757    }
758
759    function table_close($pos = NULL){
760        $this->document->tableClose();
761    }
762
763    function tablecolumn_add(){
764        $this->document->tableAddColumn();
765    }
766
767    function tablerow_open(){
768        $this->document->tableRowOpen();
769    }
770
771    function tablerow_close(){
772        $this->document->tableRowClose();
773    }
774
775    /**
776     * Open a table header cell
777     *
778     * @param int    $colspan
779     * @param string $align left|center|right
780     * @param int    $rowspan
781     */
782    function tableheader_open($colspan = 1, $align = "left", $rowspan = 1){
783        $this->document->tableHeaderOpen($colspan, $rowspan, $align);
784    }
785
786    function tableheader_close(){
787        $this->document->tableHeaderClose();
788    }
789
790    /**
791     * Open a table cell
792     *
793     * @param int    $colspan
794     * @param string $align left|center|right
795     * @param int    $rowspan
796     */
797    function tablecell_open($colspan = 1, $align = "left", $rowspan = 1){
798        $this->document->tableCellOpen($colspan, $rowspan, $align);
799    }
800
801    function tablecell_close(){
802        $this->document->tableCellClose();
803    }
804
805    /**
806     * Callback for footnote start syntax.
807     *
808     * @author Andreas Gohr <andi@splitbrain.org>
809     */
810    function footnote_open() {
811        $this->document->footnoteOpen();
812    }
813
814    /**
815     * Callback for footnote end syntax.
816     *
817     * @author Andreas Gohr
818     */
819    function footnote_close() {
820        $this->document->footnoteClose();
821    }
822
823    function listu_open($continue=false) {
824        $this->document->listOpen($continue, $this->document->getStyleName('list'), 'ul');
825    }
826
827    function listu_close() {
828        $this->document->listClose();
829    }
830
831    function listo_open($continue=false) {
832        $this->document->listOpen($continue, $this->document->getStyleName('numbering'), 'ol');
833    }
834
835    function listo_close() {
836        $this->document->listClose();
837    }
838
839    function list_close() {
840        $this->document->listClose();
841    }
842
843    /**
844     * Open a list item
845     *
846     * @param int $level the nesting level
847     */
848    function listitem_open($level, $node = false) {
849        $this->document->listItemOpen($level);
850    }
851
852    function listitem_close() {
853        $this->document->listItemClose();
854    }
855
856    /**
857     * Open a list header
858     *
859     * @param int $level the nesting level
860     */
861    function listheader_open($level) {
862        $this->document->listHeaderOpen($level);
863    }
864
865    function listheader_close() {
866        $this->document->listHeaderClose();
867    }
868
869    function listcontent_open() {
870        $this->document->listContentOpen();
871    }
872
873    function listcontent_close() {
874        $this->document->listContentClose();
875    }
876
877    /**
878     * Output unformatted $text
879     *
880     * @param string $text
881     */
882    function unformatted($text) {
883        $this->document->addPlainText($text);
884    }
885
886    /**
887     * Format an acronym
888     *
889     * @param string $acronym
890     */
891    function acronym($acronym) {
892        $this->document->addPlainText($acronym);
893    }
894
895    /**
896     * @param string $smiley
897     */
898    function smiley($smiley) {
899        if ( array_key_exists($smiley, $this->smileys) ) {
900            $src = DOKU_INC."lib/images/smileys/".$this->smileys[$smiley];
901            $this->_odtAddImage($src);
902        } else {
903            $this->document->addPlainText($smiley);
904        }
905    }
906
907    /**
908     * Format an entity
909     *
910     * @param string $entity
911     */
912    function entity($entity) {
913        // Add plain text will replace entities
914        $this->document->addPlainText($entity);
915    }
916
917    /**
918     * Typographically format a multiply sign
919     *
920     * Example: ($x=640, $y=480) should result in "640×480"
921     *
922     * @param string|int $x first value
923     * @param string|int $y second value
924     */
925    function multiplyentity($x, $y) {
926        $text .= $x.'×'.$y;
927        $this->document->addPlainText($text);
928    }
929
930    function singlequoteopening() {
931        global $lang;
932        $text .= $lang['singlequoteopening'];
933        $this->document->addPlainText($text);
934    }
935
936    function singlequoteclosing() {
937        global $lang;
938        $text .= $lang['singlequoteclosing'];
939        $this->document->addPlainText($text);
940    }
941
942    function apostrophe() {
943        global $lang;
944        $text .= $lang['apostrophe'];
945        $this->document->addPlainText($text);
946    }
947
948    function doublequoteopening() {
949        global $lang;
950        $text .= $lang['doublequoteopening'];
951        $this->document->addPlainText($text);
952    }
953
954    function doublequoteclosing() {
955        global $lang;
956        $text .= $lang['doublequoteclosing'];
957        $this->document->addPlainText($text);
958    }
959
960    /**
961     * Output inline PHP code
962     *
963     * @param string $text The PHP code
964     */
965    function php($text) {
966        $this->monospace_open();
967        $this->document->addPlainText($text);
968        $this->monospace_close();
969    }
970
971    /**
972     * Output block level PHP code
973     *
974     * @param string $text The PHP code
975     */
976    function phpblock($text) {
977        $this->file($text);
978    }
979
980    /**
981     * Output raw inline HTML
982     *
983     * @param string $text The HTML
984     */
985    function html($text) {
986        $this->monospace_open();
987        $this->document->addPlainText($text);
988        $this->monospace_close();
989    }
990
991    /**
992     * Output raw block-level HTML
993     *
994     * @param string $text The HTML
995     */
996    function htmlblock($text) {
997        $this->file($text);
998    }
999
1000    /**
1001     * Output preformatted text
1002     *
1003     * @param string $text
1004     */
1005    function preformatted($text) {
1006        $this->_preformatted($text);
1007    }
1008
1009    /**
1010     * Display text as file content, optionally syntax highlighted
1011     *
1012     * @param string $text text to show
1013     * @param string $language programming language to use for syntax highlighting
1014     * @param string $filename file path label
1015     */
1016    function file($text, $language=null, $filename=null, $options=null) {
1017        $this->_highlight('file', $text, $language, $options);
1018    }
1019
1020    function quote_open() {
1021        $this->document->quoteOpen();
1022    }
1023
1024    function quote_close() {
1025        $this->document->quoteClose();
1026    }
1027
1028    /**
1029     * Display text as code content, optionally syntax highlighted
1030     *
1031     * @param string $text text to show
1032     * @param string $language programming language to use for syntax highlighting
1033     * @param string $filename file path label
1034     */
1035    function code($text, $language=null, $filename=null, $options=null) {
1036        $this->_highlight('code', $text, $language, $options);
1037    }
1038
1039    /**
1040     * @param string $text
1041     * @param string $style
1042     * @param bool $notescaped
1043     */
1044    function _preformatted($text, $style=null, $notescaped=true) {
1045        $this->document->addPreformattedText($text, $style, $notescaped);
1046    }
1047
1048    /**
1049     * This function creates the styles required for Geshi-Syntax highlighting.
1050     * We need two non-standard-ODT-Plugin-styles:
1051     * Paragraph-Style: We need a paragraph style without top and bottom margin.
1052     *                  Otherwise there would be a sapce betwwen the source code lines.
1053     * List-Style: Usually lists are indented. Our list shall not be indented.
1054     *             (A list will only be created by Geshi if line numbering is enabled)
1055     */
1056    protected function createGeshiListStyle () {
1057        $style_name = 'highlight_list_paragraph_style';
1058        if (!$this->document->styleExists($style_name)) {
1059            // For the list paragrpah copy body style and remove margins
1060            $body = $this->document->getStyleName('body');
1061            $style = clone($this->document->getStyle($body));
1062            if ($style != NULL) {
1063                $style->setProperty('style-name', $style_name);
1064                $style->setProperty('margin-top', NULL);
1065                $style->setProperty('margin-bottom', NULL);
1066                $this->document->addAutomaticStyle($style);
1067            }
1068        }
1069        $style_name = 'highlight_list_numbers_text_style';
1070        if (!$this->document->styleExists($style_name)) {
1071            $source_code_style = $this->document->getStyleByAlias('source code');
1072            $properties = array();
1073            $properties ['style-name'] = $style_name;
1074            $properties ['style-display-name'] = 'Source Code Numbers style';
1075            $properties ['color'] = $source_code_style->getProperty('color');
1076            if (empty($properties ['color'])) {
1077                $properties ['color'] = '#000000';
1078            }
1079            $this->document->createTextStyle ($properties, true);
1080        }
1081        $style_name = 'highlight_list_ol_style';
1082        if (!$this->document->styleExists($style_name)) {
1083            // For the list style copy numbering list style and
1084            // set indentation for level 1 to '0cm'
1085            $ol = $this->document->getStyleName('numbering');
1086            $style = clone($this->document->getStyle($ol));
1087            if ($style != NULL) {
1088                $style->setProperty('style-name', $style_name);
1089                $style->setPropertyForLevel(1, 'text-style-name', 'highlight_list_numbers_text_style');
1090                $style->setPropertyForLevel(1, 'text-align', 'left');
1091                $style->setPropertyForLevel(1, 'list-level-position-and-space-mode', 'label-alignment');
1092                $style->setPropertyForLevel(1, 'label-followed-by', 'listtab');
1093                $style->setPropertyForLevel(1, 'list-tab-stop-position', '1cm');
1094                $style->setPropertyForLevel(1, 'text-indent', '-1cm');
1095                $style->setPropertyForLevel(1, 'margin-left', '1cm');
1096                $this->document->addAutomaticStyle($style);
1097            }
1098        }
1099    }
1100
1101    /**
1102     * @param string $type
1103     * @param string $text
1104     * @param string $language
1105     */
1106    function _highlight($type, $text, $language=null, $options = null) {
1107
1108        if (is_null($language)) {
1109            $this->_preformatted($text, $style_name);
1110            return;
1111        }
1112
1113        // Use cached geshi
1114        $highlighted_code = p_xhtml_cached_geshi($text, $language, '', $options);
1115
1116        // Create Geshi styles required for ODT and get ODT sourcecode style
1117        $this->createGeshiListStyle ();
1118        $source_code_style = $this->document->getStyleByAlias('source code');
1119
1120        $options = array();
1121        $options ['escape_content'] = 'false';
1122        $options ['space'] = 'preserve';
1123        $options ['media_selector'] = 'screen';
1124        $options ['element'] = 'pre';
1125        $options ['style_names'] = 'prefix_and_class';
1126        $options ['style_names_prefix'] = 'highlight_';
1127        if (empty($language)) {
1128            $options ['attributes'] = 'class="code"';
1129        } else {
1130            $options ['attributes'] = 'class="code '.$language.'"';
1131        }
1132        $options ['list_ol_style'] = 'highlight_list_ol_style';
1133        $options ['list_p_style'] = 'highlight_list_paragraph_style';
1134        $options ['p_style'] = $this->document->getStyleName('preformatted');
1135
1136        // Open table with just one cell
1137        $this->document->tableOpen();
1138        $this->document->tableRowOpen();
1139        $properties = array();
1140        $properties ['border']           = $source_code_style->getProperty('border');
1141        $properties ['border-top']       = $source_code_style->getProperty('border-top');
1142        $properties ['border-right']     = $source_code_style->getProperty('border-right');
1143        $properties ['border-bottom']    = $source_code_style->getProperty('border-bottom');
1144        $properties ['border-left']      = $source_code_style->getProperty('border-left');
1145        $properties ['padding']          = $source_code_style->getProperty('padding');
1146        $properties ['padding-top']      = $source_code_style->getProperty('padding-top');
1147        $properties ['padding-right']    = $source_code_style->getProperty('padding-right');
1148        $properties ['padding-bottom']   = $source_code_style->getProperty('padding-bottom');
1149        $properties ['padding-left']     = $source_code_style->getProperty('padding-left');
1150        $properties ['background-color'] = $source_code_style->getProperty('background-color');
1151
1152        $this->document->tableCellOpenUseProperties($properties);
1153
1154        // Generate ODT content from Geshi's HTML code
1155        $this->document->generateODTfromHTMLCode($highlighted_code, $options);
1156
1157        // Close table
1158        $this->document->tableCellClose();
1159        $this->document->tableRowClose();
1160        $this->document->tableClose();
1161    }
1162
1163    /**
1164     * Render an internal media file
1165     *
1166     * @param string $src       media ID
1167     * @param string $title     descriptive text
1168     * @param string $align     left|center|right
1169     * @param int    $width     width of media in pixel
1170     * @param int    $height    height of media in pixel
1171     * @param string $cache     cache|recache|nocache
1172     * @param string $linking   linkonly|detail|nolink
1173     * @param bool   $returnonly whether to return odt or write to doc attribute
1174     */
1175    function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1176                            $height=NULL, $cache=NULL, $linking=NULL, $returnonly = false) {
1177        global $ID;
1178        resolve_mediaid(getNS($ID),$src, $exists);
1179        list(/* $ext */,$mime) = mimetype($src);
1180
1181        if ($linking == 'linkonly') {
1182            $url = str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true));
1183            if (empty($title)) {
1184                $title = $src;
1185            }
1186            if ($returnonly) {
1187                return $this->externallink($url, $title, true);
1188            } else {
1189                $this->externallink($url, $title);
1190            }
1191            return;
1192        }
1193
1194        if(substr($mime,0,5) == 'image'){
1195            $file = mediaFN($src);
1196            if($returnonly) {
1197              return $this->_odtAddImage($file, $width, $height, $align, $title, NULL, true);
1198            } else {
1199              $this->_odtAddImage($file, $width, $height, $align, $title);
1200            }
1201        }else{
1202/*
1203            // FIXME build absolute medialink and call externallink()
1204            $this->code('FIXME internalmedia: '.$src);
1205*/
1206            //FIX by EPO/Intersel - create a link to the dokuwiki internal resource
1207            if (empty($title)) {$title=explode(':',$src); $title=end($title);}
1208            if($returnonly) {
1209              return $this->externalmedia(str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true)),$title,
1210                                        null, null, null, null, null, true);
1211            } else {
1212              $this->externalmedia(str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true)),$title,
1213                                        null, null, null, null, null);
1214            }
1215            //End of FIX
1216        }
1217    }
1218
1219    /**
1220     * Render an external media file
1221     *
1222     * @param string $src        full media URL
1223     * @param string $title      descriptive text
1224     * @param string $align      left|center|right
1225     * @param int    $width      width of media in pixel
1226     * @param int    $height     height of media in pixel
1227     * @param string $cache      cache|recache|nocache
1228     * @param string $linking    linkonly|detail|nolink
1229     * @param bool   $returnonly whether to return odt or write to doc attribute
1230     */
1231    function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1232                            $height=NULL, $cache=NULL, $linking=NULL, $returnonly = false) {
1233        list($ext,$mime) = mimetype($src);
1234
1235        if ($linking == 'linkonly') {
1236            $url = $src;
1237            if (empty($title)) {
1238                $title = $src;
1239            }
1240            if ($returnonly) {
1241                return $this->externallink($url, $title, true);
1242            } else {
1243                $this->externallink($url, $title);
1244            }
1245            return;
1246        }
1247
1248        if(substr($mime,0,5) == 'image'){
1249            $tmp_dir = $this->config->getParam ('tmpdir')."/odt";
1250            $tmp_name = $tmp_dir."/".md5($src).'.'.$ext;
1251            $client = new DokuHTTPClient;
1252            $img = $client->get($src);
1253            if ($img === FALSE) {
1254                $tmp_name = $src; // fallback to a simple link
1255            } else {
1256                if (!is_dir($tmp_dir)) io_mkdir_p($tmp_dir);
1257                $tmp_img = fopen($tmp_name, "w") or die("Can't create temp file $tmp_img");
1258                fwrite($tmp_img, $img);
1259                fclose($tmp_img);
1260            }
1261
1262            $doc = '';
1263            if ($linking != 'nolink') {
1264                $doc .= $this->document->openImageLink ($src, $returnonly);
1265            }
1266            $doc .= $this->_odtAddImage($tmp_name, $width, $height, $align, $title, $returnonly);
1267            if ($linking != 'nolink') {
1268                $doc .= $this->document->closeImageLink ($returnonly);
1269            }
1270            if (file_exists($tmp_name)) unlink($tmp_name);
1271
1272            return $doc;
1273        }else{
1274            if($returnonly) {
1275              return $this->externallink($src,$title,true);
1276            } else {
1277              $this->externallink($src,$title);
1278            }
1279        }
1280    }
1281
1282    /**
1283     * Render a CamelCase link
1284     *
1285     * @param string $link       The link name
1286     * @param bool   $returnonly whether to return odt or write to doc attribute
1287     * @see http://en.wikipedia.org/wiki/CamelCase
1288     */
1289    function camelcaselink($link, $returnonly = false) {
1290        if($returnonly) {
1291          return $this->internallink($link,$link, null, true);
1292        } else {
1293          $this->internallink($link, $link);
1294        }
1295    }
1296
1297    /**
1298     * This function is only used for the DokuWiki specific
1299     * 'returnonly' behaviour.
1300     *
1301     * @param string $id
1302     * @param string $name
1303     */
1304    function reference($id, $name = NULL) {
1305        $ret = '<text:a xlink:type="simple" xlink:href="#'.$id.'"';
1306        if ($name) {
1307            $ret .= '>'.$this->_xmlEntities($name).'</text:a>';
1308        } else {
1309            $ret .= '/>';
1310        }
1311        return $ret;
1312    }
1313
1314    /**
1315     * Render a wiki internal link
1316     *
1317     * @param string       $id         page ID to link to. eg. 'wiki:syntax'
1318     * @param string|array $name       name for the link, array for media file
1319     * @param bool         $returnonly whether to return odt or write to doc attribute
1320     *
1321     * @author Andreas Gohr <andi@splitbrain.org>
1322     */
1323    function internallink($id, $name = NULL, $returnonly = false) {
1324        global $ID;
1325        // default name is based on $id as given
1326        $default = $this->_simpleTitle($id);
1327        // now first resolve and clean up the $id
1328        resolve_pageid(getNS($ID),$id,$exists);
1329        $name = $this->_getLinkTitle($name, $default, $isImage, $id);
1330
1331        // build the absolute URL (keeping a hash if any)
1332        list($id,$hash) = explode('#',$id,2);
1333        $url = wl($id,'',true);
1334        if($hash) $url .='#'.$hash;
1335
1336        if ($ID == $id) {
1337            if ($hash) {
1338                $id = $hash;
1339            }
1340            if($returnonly) {
1341                return $this->locallink_with_text($hash, $id, $name, $returnonly);
1342            } else {
1343                $this->locallink_with_text($hash, $id, $name, $returnonly);
1344            }
1345        } else {
1346            if($returnonly) {
1347                return $this->_doLink($url, $name, $returnonly);
1348            } else {
1349                $this->_doLink($url, $name, $returnonly);
1350            }
1351        }
1352    }
1353
1354    /**
1355     * Add external link
1356     *
1357     * @param string       $url        full URL with scheme
1358     * @param string|array $name       name for the link, array for media file
1359     * @param bool         $returnonly whether to return odt or write to doc attribute
1360     */
1361    function externallink($url, $name = NULL, $returnonly = false) {
1362        $name = $this->_getLinkTitle($name, $url, $isImage);
1363
1364        if($returnonly) {
1365            return $this->_doLink($url, $name, $returnonly);
1366        } else {
1367            $this->_doLink($url, $name, $returnonly);
1368        }
1369    }
1370
1371    /**
1372     * Inserts a local link with text.
1373     *
1374     * @fixme add image handling
1375     *
1376     * @param string $hash hash link identifier
1377     * @param string $id   name for the link (the reference)
1378     * @param string $text text for the link (text inserted instead of reference)
1379     */
1380    function locallink_with_text($hash, $id = NULL, $text = NULL, $returnonly = false){
1381        if (!$returnonly) {
1382            $id  = $this->_getLinkTitle($id, $hash, $isImage);
1383            $this->document->insertCrossReference($id, $text);
1384        } else {
1385            return reference($hash, $name);
1386        }
1387    }
1388
1389    /**
1390     * Inserts a local link.
1391     *
1392     * @fixme add image handling
1393     *
1394     * @param string $hash hash link identifier
1395     * @param string $name name for the link
1396     */
1397    function locallink($hash, $name = NULL){
1398        $name  = $this->_getLinkTitle($name, $hash, $isImage);
1399        $this->document->insertCrossReference($hash, $name);
1400    }
1401
1402    /**
1403     * Render an interwiki link
1404     *
1405     * You may want to use $this->_resolveInterWiki() here
1406     *
1407     * @param string       $match      original link - probably not much use
1408     * @param string|array $name       name for the link, array for media file
1409     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
1410     * @param string       $wikiUri    the fragment parsed from the original link
1411     * @param bool         $returnonly whether to return odt or write to doc attribute
1412     */
1413    function interwikilink($match, $name = NULL, $wikiName, $wikiUri, $returnonly = false) {
1414        $name  = $this->_getLinkTitle($name, $wikiUri, $isImage);
1415        $url = $this-> _resolveInterWiki($wikiName,$wikiUri);
1416        if($returnonly) {
1417            return $this->_doLink($url, $name, $returnonly);
1418        } else {
1419            $this->_doLink($url, $name, $returnonly);
1420        }
1421    }
1422
1423    /**
1424     * Just print WindowsShare links
1425     *
1426     * @fixme add image handling
1427     *
1428     * @param string       $url        the link
1429     * @param string|array $name       name for the link, array for media file
1430     * @param bool         $returnonly whether to return odt or write to doc attribute
1431     */
1432    function windowssharelink($url, $name = NULL, $returnonly = false) {
1433        $name  = $this->_getLinkTitle($name, $url, $isImage);
1434        if($returnonly) {
1435            return $name;
1436        } else {
1437            $this->document->addPlainText($name);
1438        }
1439    }
1440
1441    /**
1442     * Just print email links
1443     *
1444     * @fixme add image handling
1445     *
1446     * @param string       $address    Email-Address
1447     * @param string|array $name       name for the link, array for media file
1448     * @param bool         $returnonly whether to return odt or write to doc attribute
1449     */
1450    function emaillink($address, $name = NULL, $returnonly = false) {
1451        $name  = $this->_getLinkTitle($name, $address, $isImage);
1452        if($returnonly) {
1453            return $this->_doLink("mailto:".$address, $name, $returnonly);
1454        } else {
1455            $this->_doLink("mailto:".$address, $name, $returnonly);
1456        }
1457    }
1458
1459    /**
1460     * Add a hyperlink, handling Images correctly
1461     *
1462     * @author Andreas Gohr <andi@splitbrain.org>
1463     *
1464     * @param string $url
1465     * @param string|array $name
1466     */
1467    function _doLink($url,$name, $returnonly = false){
1468        $url = $this->_xmlEntities($url);
1469        $doc = '';
1470        if(is_array($name)){
1471            // Images
1472            $doc .= $this->document->openImageLink ($url, $returnonly);
1473
1474            if($name['type'] == 'internalmedia'){
1475                $doc .= $this->internalmedia($name['src'],
1476                                     $name['title'],
1477                                     $name['align'],
1478                                     $name['width'],
1479                                     $name['height'],
1480                                     $name['cache'],
1481                                     $name['linking'],
1482                                     $returnonly);
1483            }
1484
1485            $doc .= $this->document->closeImageLink ($returnonly);
1486        }else{
1487            // Text
1488            $doc .= $this->document->insertHyperlink ($url, $name, NULL, NULL, $returnonly);
1489        }
1490        return $doc;
1491    }
1492
1493    /**
1494     * Construct a title and handle images in titles
1495     *
1496     * @author Harry Fuecks <hfuecks@gmail.com>
1497     *
1498     * @param string|array|null $title
1499     * @param string $default
1500     * @param bool|null $isImage
1501     * @param string $id
1502     * @return mixed
1503     */
1504    function _getLinkTitle($title, $default, & $isImage, $id=null) {
1505        $isImage = false;
1506        if ( is_array($title) ) {
1507            $isImage = true;
1508            return $title;
1509        } elseif (is_null($title) || trim($title) == '') {
1510            if ($this->config->getParam ('useheading') && $id) {
1511                $heading = p_get_first_heading($id);
1512                if ($heading) {
1513                    return $this->_xmlEntities($heading);
1514                }
1515            }
1516            return $this->_xmlEntities($default);
1517        } else {
1518            return $this->_xmlEntities($title);
1519        }
1520    }
1521
1522    /**
1523     * @param string $value
1524     * @return string
1525     */
1526    function _xmlEntities($value) {
1527        return str_replace( array('&','"',"'",'<','>'), array('&#38;','&#34;','&#39;','&#60;','&#62;'), $value);
1528    }
1529
1530    /**
1531     * Render the output of an RSS feed
1532     *
1533     * @param string $url    URL of the feed
1534     * @param array  $params Finetuning of the output
1535     */
1536    function rss ($url,$params){
1537        global $lang;
1538
1539        require_once(DOKU_INC . 'inc/FeedParser.php');
1540        $feed = new FeedParser();
1541        $feed->feed_url($url);
1542
1543        //disable warning while fetching
1544        $elvl = null;
1545        if (!defined('DOKU_E_LEVEL')) { $elvl = error_reporting(E_ERROR); }
1546        $rc = $feed->init();
1547        if (!defined('DOKU_E_LEVEL')) { error_reporting($elvl); }
1548
1549        //decide on start and end
1550        if($params['reverse']){
1551            $mod = -1;
1552            $start = $feed->get_item_quantity()-1;
1553            $end   = $start - ($params['max']);
1554            $end   = ($end < -1) ? -1 : $end;
1555        }else{
1556            $mod   = 1;
1557            $start = 0;
1558            $end   = $feed->get_item_quantity();
1559            $end   = ($end > $params['max']) ? $params['max'] : $end;;
1560        }
1561
1562        $this->listu_open();
1563        if($rc){
1564            for ($x = $start; $x != $end; $x += $mod) {
1565                $item = $feed->get_item($x);
1566                $this->document->listItemOpen(0);
1567                $this->document->listContentOpen();
1568
1569                $this->externallink($item->get_permalink(),
1570                                    $item->get_title());
1571                if($params['author']){
1572                    $author = $item->get_author(0);
1573                    if($author){
1574                        $name = $author->get_name();
1575                        if(!$name) $name = $author->get_email();
1576                        if($name) $this->cdata(' '.$lang['by'].' '.$name);
1577                    }
1578                }
1579                if($params['date']){
1580                    $this->cdata(' ('.$item->get_date($this->config->getParam ('dformat')).')');
1581                }
1582                if($params['details']){
1583                    $this->cdata(strip_tags($item->get_description()));
1584                }
1585                $this->document->listContentClose();
1586                $this->document->listItemClose();
1587            }
1588        }else{
1589            $this->document->listItemOpen(0);
1590            $this->document->listContentOpen();
1591            $this->emphasis_open();
1592            $this->cdata($lang['rssfailed']);
1593            $this->emphasis_close();
1594            $this->externallink($url);
1595            $this->document->listContentClose();
1596            $this->document->listItemClose();
1597        }
1598        $this->listu_close();
1599    }
1600
1601    /**
1602     * Adds the content of $string as a SVG picture to the document.
1603     *
1604     * @see ODTDocument::addStringAsSVGImage for API wrapper function
1605     * @see ODTImage::addStringAsSVGImage for a detailed description
1606     */
1607    function _addStringAsSVGImage($string, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL) {
1608        $this->document->addStringAsSVGImage($string, $width, $height, $align, $title, $style);
1609    }
1610
1611    /**
1612     * The function adds $string as an SVG image file.
1613     * It does NOT insert the image in the document.
1614     *
1615     * @see ODTDocument::addStringAsSVGImageFile for a detailed description
1616     * @see ODTImage::addStringAsSVGImageFile for a detailed description
1617     */
1618    function _addStringAsSVGImageFile($string) {
1619        return $this->document->addStringAsSVGImageFile($string);
1620    }
1621
1622    /**
1623     * Adds the image $src as a picture file without adding it to the content
1624     * of the document. The link name which can be used for the ODT draw:image xlink:href
1625     * is returned. The caller is responsible for creating the frame and image tag
1626     * but therefore has full control over it. This means he can also set parameters
1627     * in the odt frame and image tag which can not be changed using the function _odtAddImage.
1628     *
1629     * @author LarsDW223
1630     *
1631     * @param string $src
1632     * @return string
1633     */
1634    function _odtAddImageAsFileOnly($src){
1635        return $this->document->addFileAsPicture($src);
1636    }
1637
1638    /**
1639     * Adds an image $src to the document.
1640     *
1641     * @param string  $src        The path to the image file
1642     * @param string  $width      Width of the picture (NULL=original size)
1643     * @param string  $height     Height of the picture (NULL=original size)
1644     * @param string  $align      Alignment
1645     * @param string  $title      Title
1646     * @param string  $style      Optional "draw:style-name"
1647     * @param boolean $returnonly Only return code
1648     *
1649     * @see ODTDocument::addImage for API wrapper function
1650     * @see ODTImage::addImage for a detailed description
1651     */
1652    function _odtAddImage($src, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL, $returnonly = false){
1653        if ($returnonly) {
1654            return $this->document->addImage($src, $width, $height, $align, $title, $style, $returnonly);
1655        } else {
1656            $this->document->addImage($src, $width, $height, $align, $title, $style, $returnonly);
1657        }
1658    }
1659
1660    /**
1661     * Adds an image $src to the document using the parameters set in $properties.
1662     *
1663     * @param string  $src        The path to the image file
1664     * @param array   $properties Properties (width, height... see ODTImage::addImageUseProperties)
1665     * @param boolean $returnonly Only return code
1666     *
1667     * @see ODTDocument::addImageUseProperties for API wrapper function
1668     * @see ODTImage::addImageUseProperties for a detailed description
1669     */
1670    function _odtAddImageUseProperties($src, array $properties, $returnonly = false){
1671        if ($returnonly) {
1672            return $this->document->addImageUseProperties($src, $properties, $returnonly);
1673        } else {
1674            $this->document->addImageUseProperties($src, $properties, $returnonly);
1675        }
1676    }
1677
1678    /**
1679     * The function tries to examine the width and height
1680     * of the image stored in file $src.
1681     *
1682     * @see ODTDocument::getImageSize for API wrapper function
1683     * @see ODTUtility::getImageSize for a detailed description
1684     */
1685    public function _odtGetImageSize($src, $maxwidth=NULL, $maxheight=NULL){
1686        return $this->document->getImageSize($src, $maxwidth, $maxheight);
1687    }
1688
1689    /**
1690     * @param string $src
1691     * @param  $width
1692     * @param  $height
1693     * @return array
1694     */
1695    function _odtGetImageSizeString($src, $width = NULL, $height = NULL){
1696        return $this->document->getImageSizeString($src, $width, $height);
1697    }
1698
1699    /**
1700     * Open a span using CSS.
1701     *
1702     * @see ODTDocument::spanOpenUseCSS for API wrapper function
1703     * @see ODTSpan::spanOpenUseCSS for detailed documentation
1704     * @author LarsDW223
1705     */
1706    function _odtSpanOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1707        $this->document->spanOpenUseCSS($element, $attributes, $import);
1708    }
1709
1710    /**
1711     * Open a span using properties.
1712     *
1713     * @see ODTDocument::spanOpenUseProperties for API wrapper function
1714     * @see ODTSpan::spanOpenUseProperties for detailed documentation
1715     * @author LarsDW223
1716     */
1717    function _odtSpanOpenUseProperties($properties){
1718        $this->document->spanOpenUseProperties($properties);
1719    }
1720
1721    function _odtSpanOpen($style_name){
1722        $this->document->spanOpen($style_name);
1723    }
1724
1725    /**
1726     * This function closes a span (previously opened with _odtSpanOpenUseCSS).
1727     *
1728     * @author LarsDW223
1729     */
1730    function _odtSpanClose(){
1731        $this->document->spanClose();
1732    }
1733
1734    /**
1735     * Open a paragraph using CSS.
1736     *
1737     * @see ODTDocument::paragraphOpenUseCSS for API wrapper function
1738     * @see ODTParagraph::paragraphOpenUseCSS for detailed documentation
1739     * @author LarsDW223
1740     */
1741    function _odtParagraphOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1742        $this->document->paragraphOpenUseCSS($element, $attributes, $import);
1743    }
1744
1745    /**
1746     * Open a paragraph using properties.
1747     *
1748     * @see ODTDocument::paragraphOpenUseProperties for API wrapper function
1749     * @see ODTParagraph::paragraphOpenUseProperties for detailed documentation
1750     * @author LarsDW223
1751     */
1752    function _odtParagraphOpenUseProperties($properties){
1753        $this->document->paragraphOpenUseProperties($properties);
1754    }
1755
1756    /**
1757     * Open a text box using CSS.
1758     *
1759     * @see ODTDocument::openTextBoxUseCSS for API wrapper function
1760     * @see ODTFrame::openTextBoxUseCSS for detailed documentation
1761     */
1762    function _odtOpenTextBoxUseCSS ($element=NULL, $attributes=NULL, cssimportnew $import=NULL) {
1763        $this->document->openTextBoxUseCSS ($element, $attributes, $import);
1764    }
1765
1766    /**
1767     * This function opens a div. As divs are not supported by ODT, it will be exported as a frame.
1768     * To be more precise, to frames will be created. One including a picture nad the other including the text.
1769     * A picture frame will only be created if a 'background-image' is set in the CSS style.
1770     *
1771     * The currently supported CSS properties are:
1772     * background-color, color, padding, margin, display, border-radius, min-height.
1773     * The background-image is simulated using a picture frame.
1774     * FIXME: Find a way to successfuly use the background-image in the graphic style (see comments).
1775     *
1776     * The div should be closed by calling '_odtDivCloseAsFrame'.
1777     *
1778     * @author LarsDW223
1779     *
1780     * @param array $properties
1781     */
1782    function _odtDivOpenAsFrameUseProperties ($properties) {
1783        dbg_deprecated('_odtOpenTextBoxUseProperties');
1784        $this->_odtOpenTextBoxUseProperties ($properties);
1785    }
1786
1787    /**
1788     * This function closes a div/frame (previously opened with _odtDivOpenAsFrameUseCSS).
1789     *
1790     * @author LarsDW223
1791     */
1792    function _odtDivCloseAsFrame () {
1793        $this->_odtCloseTextBox();
1794    }
1795
1796    /**
1797     * This function opens a new table using CSS.
1798     *
1799     * @author LarsDW223
1800     * @see ODTDocument::tableOpenUseCSS for API wrapper function
1801     * @see ODTTable::tableOpenUseCSS for detailed documentation
1802     */
1803    function _odtTableOpenUseCSS($maxcols = NULL, $numrows = NULL, $element=NULL, $attributes = NULL, cssimportnew $import = NULL){
1804        $this->document->tableOpenUseCSS($maxcols, $numrows, $element, $attributes, $import);
1805    }
1806
1807    /**
1808     * This function opens a new table using properties.
1809     *
1810     * @author LarsDW223
1811     * @see ODTDocument::tableOpenUseProperties for API wrapper function
1812     * @see ODTTable::tableOpenUseProperties for detailed documentation
1813     */
1814    function _odtTableOpenUseProperties ($properties, $maxcols = 0, $numrows = 0){
1815        $this->document->tableOpenUseProperties ($properties, $maxcols, $numrows);
1816    }
1817
1818    /**
1819     * This function closes a table.
1820     *
1821     * @author LarsDW223
1822     * @see ODTDocument::tableClose for API wrapper function
1823     * @see ODTTable::tableClose for detailed documentation
1824     */
1825    function _odtTableClose () {
1826        $this->document->tableClose();
1827    }
1828
1829    /**
1830     * This function adds a new table column using properties.
1831     *
1832     * @author LarsDW223
1833     * @see ODTDocument::tableAddColumnUseProperties for API wrapper function
1834     * @see ODTTable::tableAddColumnUseProperties for detailed documentation
1835     */
1836    function _odtTableAddColumnUseProperties (array $properties = NULL){
1837        $this->document->tableAddColumnUseProperties($properties);
1838    }
1839
1840    /**
1841     * This function opens a new table header using CSS.
1842     * The header should be closed by calling 'tableheader_close()'.
1843     *
1844     * @author LarsDW223
1845     * @see ODTDocument::tableHeaderOpenUseCSS for API wrapper function
1846     * @see ODTTable::tableHeaderOpenUseCSS for detailed documentation
1847     */
1848    function _odtTableHeaderOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1849        $this->document->tableHeaderOpenUseCSS($colspan, $rowspan, $element, $attributes, $import);
1850    }
1851
1852    /**
1853     * This function opens a new table header using properties.
1854     * The header should be closed by calling 'tableheader_close()'.
1855     *
1856     * @author LarsDW223
1857     * @see ODTDocument::tableHeaderOpenUseProperties for API wrapper function
1858     * @see ODTTable::tableHeaderOpenUseProperties for detailed documentation
1859     */
1860    function _odtTableHeaderOpenUseProperties ($properties = NULL, $colspan = 1, $rowspan = 1){
1861        $this->document->tableHeaderOpenUseProperties($properties, $colspan = 1, $rowspan = 1);
1862    }
1863
1864    /**
1865     * This function opens a new table row using CSS.
1866     * The row should be closed by calling 'tablerow_close()'.
1867     *
1868     * @author LarsDW223
1869     * @see ODTDocument::tableRowOpenUseCSS for API wrapper function
1870     * @see ODTTable::tableRowOpenUseCSS for detailed documentation
1871     */
1872    function _odtTableRowOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1873        $this->document->tableRowOpenUseCSS($element, $attributes, $import);
1874    }
1875
1876    /**
1877     * This function opens a new table row using properties.
1878     * The row should be closed by calling 'tablerow_close()'.
1879     *
1880     * @author LarsDW223
1881     * @see ODTDocument::tableRowOpenUseProperties for API wrapper function
1882     * @see ODTTable::tableRowOpenUseProperties for detailed documentation
1883     */
1884    function _odtTableRowOpenUseProperties ($properties){
1885        $this->document->tableRowOpenUseProperties($properties);
1886    }
1887
1888    /**
1889     * This function opens a new table cell using CSS.
1890     * The cell should be closed by calling 'tablecell_close()'.
1891     *
1892     * @author LarsDW223
1893     * @see ODTDocument::tableCellOpenUseCSS for API wrapper function
1894     * @see ODTTable::tableCellOpenUseCSS for detailed documentation
1895     */
1896    function _odtTableCellOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1897        $this->document->tableCellOpenUseCSS($colspan, $rowspan, $element, $attributes, $import);
1898    }
1899
1900    /**
1901     * This function opens a new table cell using properties.
1902     * The cell should be closed by calling 'tablecell_close()'.
1903     *
1904     * @author LarsDW223
1905     * @see ODTDocument::tableCellOpenUseProperties for API wrapper function
1906     * @see ODTTable::tableCellOpenUseProperties for detailed documentation
1907     */
1908    function _odtTableCellOpenUseProperties ($properties, $colspan = 1, $rowspan = 1){
1909        $this->document->tableCellOpenUseProperties($properties, $colspan, $rowspan);
1910    }
1911
1912    /**
1913     * Open a multi column text box in a frame using properties.
1914     *
1915     * @see ODTDocument::openMultiColumnTextBoxUseProperties for API wrapper function
1916     * @see ODTFrame::openMultiColumnTextBoxUseProperties for detailed documentation
1917     */
1918    function _odtOpenMultiColumnFrame ($properties) {
1919        $this->document->openMultiColumnTextBoxUseProperties($properties);
1920    }
1921
1922    /**
1923     * This function closes a multi column frame (previously opened with _odtOpenMultiColumnFrame).
1924     *
1925     * @see ODTDocument::closeTextBox for API wrapper function
1926     * @see ODTFrame::closeTextBox for detailed documentation
1927     * @author LarsDW223
1928     */
1929    function _odtCloseMultiColumnFrame () {
1930        $this->document->closeMultiColumnTextBox();
1931    }
1932
1933    /**
1934     * Open a text box in a frame using properties.
1935     *
1936     * @see ODTDocument::openTextBoxUseProperties for API wrapper function
1937     * @see ODTFrame::openTextBoxUseProperties for detailed documentation
1938     */
1939    function _odtOpenTextBoxUseProperties ($properties) {
1940        $this->document->openTextBoxUseProperties ($properties);
1941    }
1942
1943    /**
1944     * This function closes a textbox.
1945     *
1946     * @see ODTDocument::closeTextBox for API wrapper function
1947     * @see ODTFrame::closeTextBox for detailed documentation
1948     * @author LarsDW223
1949     */
1950    function _odtCloseTextBox () {
1951        $this->document->closeTextBox();
1952    }
1953
1954    /**
1955     * Open a frame using properties.
1956     *
1957     * @see ODTDocument::openFrameUseProperties for API wrapper function
1958     * @see ODTFrame::openFrameUseProperties for detailed documentation
1959     */
1960    function _odtOpenFrameUseProperties ($properties) {
1961        $this->document->openFrameUseProperties ($properties);
1962    }
1963
1964    /**
1965     * This function closes a frame.
1966     *
1967     * @see ODTDocument::closeFrame for API wrapper function
1968     * @see ODTFrame::closeFrame for detailed documentation
1969     * @author LarsDW223
1970     */
1971    function _odtCloseFrame () {
1972        $this->document->closeFrame();
1973    }
1974
1975    /**
1976     * @param array $dest
1977     * @param $element
1978     * @param $classString
1979     * @param $inlineStyle
1980     */
1981    public function getODTProperties (&$dest, $element, $classString, $inlineStyle, $media_sel=NULL, $cssId=NULL) {
1982        if ($media_sel === NULL) {
1983            $media_sel = $this->config->getParam ('media_sel');
1984        }
1985        // Get properties for our class/element from imported CSS
1986        $this->import->getPropertiesForElement($dest, $element, $classString, $media_sel, $cssId);
1987
1988        // Interpret and add values from style to our properties
1989        $this->document->getCSSStylePropertiesForODT($dest, $inlineStyle);
1990
1991        // Adjust values for ODT
1992        //foreach ($dest as $property => $value) {
1993        //    $dest [$property] = $this->adjustValueForODT ($property, $value, 14);
1994        //}
1995        $this->document->adjustValuesForODT($dest);
1996    }
1997
1998    /**
1999     * Replace a CSS URL value with the given path.
2000     *
2001     * @param $URL CSS URL e.g. 'url(images/xyz.png);'
2002     * @param $replacement The local path
2003     * @return string The resulting complete file path
2004     */
2005    public function replaceURLPrefix ($URL, $replacement) {
2006        return $this->import->replaceURLPrefix ($URL, $replacement);
2007    }
2008
2009    /**
2010     * Convert pixel to points (X axis).
2011     *
2012     * @param $pixel value to convert
2013     * @return float The converted value in points
2014     * @see ODTDocument::toPoints for API wrapper function
2015     * @see ODTUnits::toPoints for detailed documentation
2016     */
2017    public function pixelToPointsX ($pixel) {
2018        return $this->document->toPoints($pixel, 'x');
2019    }
2020
2021    /**
2022     * Convert pixel to points (Y axis).
2023     *
2024     * @param $pixel value to convert
2025     * @return float The converted value in points
2026     * @see ODTDocument::toPoints for API wrapper function
2027     * @see ODTUnits::toPoints for detailed documentation
2028     */
2029    public function pixelToPointsY ($pixel) {
2030        return $this->document->toPoints($pixel, 'y');
2031    }
2032
2033    /**
2034     * Adjust the given property for ODT.
2035     *
2036     * @param $property The property name
2037     * @param $value The property value
2038     * @param int $emValue The conversion value for 'em' units
2039     * @return string The new, adjusted value
2040     * @see ODTUtility::adjustValueForODT for detailed documentation
2041     */
2042    public function adjustValueForODT ($property, $value) {
2043        return $this->document->adjustValueForODT ($property, $value);
2044    }
2045
2046    /**
2047     * Callback function which adjusts all CSS length values to point.
2048     *
2049     * @param $property The name of the current CSS property, e.g. 'border-left'
2050     * @param $value The current value from the original CSS code
2051     * @param $type There are 3 possible values:
2052     *              - LengthValueXAxis: the property represents a value on the X axis
2053     *              - LengthValueYAxis: the property represents a value on the Y axis
2054     *              - CSSValueType::StrokeOrBorderWidth: the property represents a stroke
2055     *                or border width
2056     * @return string The new, adjusted value for the property
2057     */
2058    public function adjustLengthCallback ($property, $value, $type) {
2059        // Replace px with pt (px does not seem to be supported by ODT)
2060        $length = strlen ($value);
2061        if ( $length > 2 && $value [$length-2] == 'p' && $value [$length-1] == 'x' ) {
2062            $number = trim($value, 'px');
2063            switch ($type) {
2064                case CSSValueType::LengthValueXAxis:
2065                    $adjusted = $this->pixelToPointsX($number).'pt';
2066                break;
2067
2068                case CSSValueType::StrokeOrBorderWidth:
2069                    switch ($property) {
2070                        case 'border':
2071                        case 'border-left':
2072                        case 'border-right':
2073                        case 'border-top':
2074                        case 'border-bottom':
2075                            // border in ODT spans does not support 'px' units, so we convert it.
2076                            $adjusted = $this->pixelToPointsY($number).'pt';
2077                        break;
2078
2079                        default:
2080                            $adjusted = $value;
2081                        break;
2082                    }
2083                break;
2084
2085                case CSSValueType::LengthValueYAxis:
2086                default:
2087                    $adjusted = $this->pixelToPointsY($number).'pt';
2088                break;
2089            }
2090            return $adjusted;
2091        }
2092        return $value;
2093    }
2094
2095    /**
2096     * This function read the template page and imports all cdata and code content
2097     * as additional CSS. ATTENTION: this might overwrite already imported styles
2098     * from an ODT or CSS template file.
2099     *
2100     * @param $pagename The name of the template page
2101     */
2102    public function read_templatepage ($pagename) {
2103        $instructions = p_cached_instructions(wikiFN($pagename));
2104        $text = '';
2105        foreach($instructions as $instruction) {
2106            if($instruction[0] == 'code') {
2107                $text .= $instruction[1][0];
2108            } elseif ($instruction[0] == 'cdata') {
2109                $text .= $instruction[1][0];
2110            }
2111        }
2112
2113        $this->document->importCSSFromString
2114            ($text, $this->config->getParam('media_sel'), array($this, 'replaceURLPrefixesCallback'), true, $this->config->getParam('olist_label_align'));
2115    }
2116
2117    /**
2118     * Get CSS properties for a given element and adjust them for ODT.
2119     *
2120     * @see ODTDocument::getODTProperties for more information
2121     */
2122    public function getODTPropertiesNew (&$dest, $element, $attributes=NULL, $media_sel=NULL, $inherit=true) {
2123        if ($media_sel === NULL) {
2124            $media_sel = $this->config->getParam ('media_sel');
2125        }
2126        $this->document->getODTProperties ($dest, $element, $attributes, $media_sel, $inherit);
2127    }
2128
2129    public function getODTPropertiesFromElement (&$dest, iElementCSSMatchable $element, $media_sel=NULL, $inherit=true) {
2130        if ($media_sel === NULL) {
2131            $media_sel = $this->config->getParam ('media_sel');
2132        }
2133        $this->document->getODTPropertiesFromElement ($dest, $element, $media_sel, $inherit);
2134    }
2135
2136    /**
2137     * This function creates a text style.
2138     *
2139     * @see ODTDocument::createTextStyle for detailed desciption.
2140     */
2141    public function createTextStyle ($properties, $common=true) {
2142        $this->document->createTextStyle ($properties, $common);
2143    }
2144
2145    /**
2146     * This function creates a paragraph style.
2147     *
2148     * @see ODTDocument::createParagraphStyle for detailed desciption.
2149     */
2150    public function createParagraphStyle ($properties, $common=true) {
2151        $this->document->createParagraphStyle ($properties, $common);
2152    }
2153
2154    /**
2155     * This function creates a table style.
2156     *
2157     * @see ODTDocument::createTableStyle for detailed desciption.
2158     */
2159    public function createTableStyle ($properties, $common=true) {
2160        $this->document->createTableStyle ($properties, $common);
2161    }
2162
2163    /**
2164     * This function creates a table row style.
2165     *
2166     * @see ODTDocument::createTableRowStyle for detailed desciption.
2167     */
2168    public function createTableRowStyle ($properties, $common=true) {
2169        $this->document->createTableRowStyle ($properties, $common);
2170    }
2171
2172    /**
2173     * This function creates a table cell style.
2174     *
2175     * @see ODTDocument::createTableCellStyle for detailed  desciption.
2176     */
2177    public function createTableCellStyle ($properties, $common=true) {
2178        $this->document->createTableCellStyle ($properties, $common);
2179    }
2180
2181    /**
2182     * This function creates a table column style.
2183     *
2184     * @see ODTDocument::createTableColumnStyle for detailed desciption.
2185     */
2186    public function createTableColumnStyle ($properties, $common=true) {
2187        $this->document->createTableColumnStyle ($properties, $common);
2188    }
2189
2190    public function styleExists ($style_name) {
2191        return $this->document->styleExists($style_name);
2192    }
2193
2194    /**
2195     * Add a user field.
2196     * (Code has been adopted from the fields plugin)
2197     *
2198     * @param string $name The name of the field
2199     * @param string $value The value of the field
2200     * @author Aurelien Bompard <aurelien@bompard.org>
2201     * @see ODTDocument::addUserField for detailed desciption.
2202     */
2203    public function addUserField($name, $value) {
2204        $this->document->addUserField($name, $value);
2205    }
2206
2207    /**
2208     * Insert a user field reference.
2209     * (Code has been adopted from the fields plugin)
2210     *
2211     * @param string $name The name of the field
2212     * @author Aurelien Bompard <aurelien@bompard.org>
2213     * @see ODTDocument::insertUserField for detailed desciption.
2214     */
2215    public function insertUserField($name) {
2216        $this->document->insertUserField($name);
2217    }
2218
2219    protected function buildODTPathes (&$ODTTemplatePath, &$tempDirPath) {
2220        global $ID;
2221
2222        // Temp dir
2223        if (is_dir($this->config->getParam('tmpdir'))) {
2224            $tempDirPath = $this->config->getParam('tmpdir');
2225        }
2226        $tempDirPath = $tempDirPath."/odt/".str_replace(':','-',$ID);
2227
2228        // Eventually determine ODT template file
2229        $ODTTemplatePath = NULL;
2230        $template = $this->config->getParam ('odt_template');
2231        if (!empty($template)) {
2232            $ODTTemplatePath = $this->config->getParam('mediadir').'/'.$this->config->getParam ('tpl_dir')."/".$this->config->getParam ('odt_template');
2233        }
2234    }
2235
2236    public function addToValue ($value, $add) {
2237        return $this->document->addToValue ($value, $add);
2238    }
2239
2240    public function subFromValue ($value, $sub) {
2241        return $this->document->subFromValue ($value, $sub);
2242    }
2243
2244    public function getHTMLStack () {
2245        return $this->document->getHTMLStack ();
2246    }
2247
2248    public function dumpHTMLStack () {
2249        $this->document->dumpHTMLStack ();
2250    }
2251
2252    public function setOrderedListParams ($setLevel, $align, $paddingLeft=0, $marginLeft=1) {
2253        $this->document->setOrderedListParams($setLevel, $align, $paddingLeft, $marginLeft);
2254    }
2255
2256    public function setUnorderedListParams ($setLevel, $align, $paddingLeft=0, $marginLeft=1) {
2257        $this->document->setUnorderedListParams($setLevel, $align, $paddingLeft, $marginLeft);
2258    }
2259
2260    /**
2261     * Insert a bookmark.
2262     *
2263     * @param string $id    ID of the bookmark
2264     * @param string $now   Insert bookmark immediately?
2265     * @see ODTDocument::insertBookmark for detailed desciption.
2266     */
2267    public function insertBookmark($id, $now=true) {
2268        $this->document->insertBookmark($id, $now);
2269    }
2270
2271    /**
2272     * Automatically generate ODT elements from HTML code.
2273     *
2274     * @param string $html_code The HTML code to convert
2275     * @param array  $options   Options array (FIXME: documentation needed)
2276     * @see ODTUtility::generateODTfromHTMLCode for detailed desciption.
2277     */
2278    public function generateODTfromHTMLCode($html_code, $options=null) {
2279        // Generate ODT content from Geshi's HTML code
2280        $this->document->generateODTfromHTMLCode($html_code, $options);
2281    }
2282}
2283
2284//Setup VIM: ex: et ts=4 enc=utf-8 :
2285