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 ( isset($loader) ) {
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 ( isset($this->import) ) {
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 (isset($default)) {
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        if (array_key_exists($entity, $this->entities)) {
914            $entity = $this->entities[$entity];
915        }
916
917        // Add plain text will replace XML entities
918        $this->document->addPlainText($entity);
919    }
920
921    /**
922     * Typographically format a multiply sign
923     *
924     * Example: ($x=640, $y=480) should result in "640×480"
925     *
926     * @param string|int $x first value
927     * @param string|int $y second value
928     */
929    function multiplyentity($x, $y) {
930        $text .= $x.'×'.$y;
931        $this->document->addPlainText($text);
932    }
933
934    function singlequoteopening() {
935        global $lang;
936        $text .= $lang['singlequoteopening'];
937        $this->document->addPlainText($text);
938    }
939
940    function singlequoteclosing() {
941        global $lang;
942        $text .= $lang['singlequoteclosing'];
943        $this->document->addPlainText($text);
944    }
945
946    function apostrophe() {
947        global $lang;
948        $text .= $lang['apostrophe'];
949        $this->document->addPlainText($text);
950    }
951
952    function doublequoteopening() {
953        global $lang;
954        $text .= $lang['doublequoteopening'];
955        $this->document->addPlainText($text);
956    }
957
958    function doublequoteclosing() {
959        global $lang;
960        $text .= $lang['doublequoteclosing'];
961        $this->document->addPlainText($text);
962    }
963
964    /**
965     * Output inline PHP code
966     *
967     * @param string $text The PHP code
968     */
969    function php($text) {
970        $this->monospace_open();
971        $this->document->addPlainText($text);
972        $this->monospace_close();
973    }
974
975    /**
976     * Output block level PHP code
977     *
978     * @param string $text The PHP code
979     */
980    function phpblock($text) {
981        $this->file($text);
982    }
983
984    /**
985     * Output raw inline HTML
986     *
987     * @param string $text The HTML
988     */
989    function html($text) {
990        $this->monospace_open();
991        $this->document->addPlainText($text);
992        $this->monospace_close();
993    }
994
995    /**
996     * Output raw block-level HTML
997     *
998     * @param string $text The HTML
999     */
1000    function htmlblock($text) {
1001        $this->file($text);
1002    }
1003
1004    /**
1005     * Output preformatted text
1006     *
1007     * @param string $text
1008     */
1009    function preformatted($text) {
1010        $this->_preformatted($text);
1011    }
1012
1013    /**
1014     * Display text as file content, optionally syntax highlighted
1015     *
1016     * @param string $text text to show
1017     * @param string $language programming language to use for syntax highlighting
1018     * @param string $filename file path label
1019     */
1020    function file($text, $language=null, $filename=null, $options=null) {
1021        $this->_highlight('file', $text, $language, $options);
1022    }
1023
1024    function quote_open() {
1025        $this->document->quoteOpen();
1026    }
1027
1028    function quote_close() {
1029        $this->document->quoteClose();
1030    }
1031
1032    /**
1033     * Display text as code content, optionally syntax highlighted
1034     *
1035     * @param string $text text to show
1036     * @param string $language programming language to use for syntax highlighting
1037     * @param string $filename file path label
1038     */
1039    function code($text, $language=null, $filename=null, $options=null) {
1040        $this->_highlight('code', $text, $language, $options);
1041    }
1042
1043    /**
1044     * @param string $text
1045     * @param string $style
1046     * @param bool $notescaped
1047     */
1048    function _preformatted($text, $style=null, $notescaped=true) {
1049        $this->document->addPreformattedText($text, $style, $notescaped);
1050    }
1051
1052    /**
1053     * This function creates the styles required for Geshi-Syntax highlighting.
1054     * We need two non-standard-ODT-Plugin-styles:
1055     * Paragraph-Style: We need a paragraph style without top and bottom margin.
1056     *                  Otherwise there would be a sapce betwwen the source code lines.
1057     * List-Style: Usually lists are indented. Our list shall not be indented.
1058     *             (A list will only be created by Geshi if line numbering is enabled)
1059     */
1060    protected function createGeshiListStyle () {
1061        $style_name = 'highlight_list_paragraph_style';
1062        if (!$this->document->styleExists($style_name)) {
1063            // For the list paragrpah copy body style and remove margins
1064            $body = $this->document->getStyleName('body');
1065            $style = clone($this->document->getStyle($body));
1066            if (isset($style)) {
1067                $style->setProperty('style-name', $style_name);
1068                $style->setProperty('margin-top', NULL);
1069                $style->setProperty('margin-bottom', NULL);
1070                $this->document->addAutomaticStyle($style);
1071            }
1072        }
1073        $style_name = 'highlight_list_numbers_text_style';
1074        if (!$this->document->styleExists($style_name)) {
1075            $source_code_style = $this->document->getStyleByAlias('source code');
1076            $properties = array();
1077            $properties ['style-name'] = $style_name;
1078            $properties ['style-display-name'] = 'Source Code Numbers style';
1079            $properties ['color'] = $source_code_style->getProperty('color');
1080            if (empty($properties ['color'])) {
1081                $properties ['color'] = '#000000';
1082            }
1083            $this->document->createTextStyle ($properties, true);
1084        }
1085        $style_name = 'highlight_list_ol_style';
1086        if (!$this->document->styleExists($style_name)) {
1087            // For the list style copy numbering list style and
1088            // set indentation for level 1 to '0cm'
1089            $ol = $this->document->getStyleName('numbering');
1090            $style = clone($this->document->getStyle($ol));
1091            if (isset($style)) {
1092                $style->setProperty('style-name', $style_name);
1093                $style->setPropertyForLevel(1, 'text-style-name', 'highlight_list_numbers_text_style');
1094                $style->setPropertyForLevel(1, 'text-align', 'left');
1095                $style->setPropertyForLevel(1, 'list-level-position-and-space-mode', 'label-alignment');
1096                $style->setPropertyForLevel(1, 'label-followed-by', 'listtab');
1097                $style->setPropertyForLevel(1, 'list-tab-stop-position', '1cm');
1098                $style->setPropertyForLevel(1, 'text-indent', '-1cm');
1099                $style->setPropertyForLevel(1, 'margin-left', '1cm');
1100                $this->document->addAutomaticStyle($style);
1101            }
1102        }
1103    }
1104
1105    /**
1106     * @param string $type
1107     * @param string $text
1108     * @param string $language
1109     */
1110    function _highlight($type, $text, $language=null, $options = null) {
1111
1112        if (is_null($language)) {
1113            $this->_preformatted($text, $style_name);
1114            return;
1115        }
1116
1117        // Use cached geshi
1118        $highlighted_code = p_xhtml_cached_geshi($text, $language, '', $options);
1119
1120        // Create Geshi styles required for ODT and get ODT sourcecode style
1121        $this->createGeshiListStyle ();
1122        $source_code_style = $this->document->getStyleByAlias('source code');
1123
1124        $options = array();
1125        $options ['escape_content'] = 'false';
1126        $options ['space'] = 'preserve';
1127        $options ['media_selector'] = 'screen';
1128        $options ['element'] = 'pre';
1129        $options ['style_names'] = 'prefix_and_class';
1130        $options ['style_names_prefix'] = 'highlight_';
1131        if (empty($language)) {
1132            $options ['attributes'] = 'class="code"';
1133        } else {
1134            $options ['attributes'] = 'class="code '.$language.'"';
1135        }
1136        $options ['list_ol_style'] = 'highlight_list_ol_style';
1137        $options ['list_p_style'] = 'highlight_list_paragraph_style';
1138        $options ['p_style'] = $this->document->getStyleName('preformatted');
1139
1140        // Open table with just one cell
1141        $this->document->tableOpen();
1142        $this->document->tableRowOpen();
1143        $properties = array();
1144        $properties ['border']           = $source_code_style->getProperty('border');
1145        $properties ['border-top']       = $source_code_style->getProperty('border-top');
1146        $properties ['border-right']     = $source_code_style->getProperty('border-right');
1147        $properties ['border-bottom']    = $source_code_style->getProperty('border-bottom');
1148        $properties ['border-left']      = $source_code_style->getProperty('border-left');
1149        $properties ['padding']          = $source_code_style->getProperty('padding');
1150        $properties ['padding-top']      = $source_code_style->getProperty('padding-top');
1151        $properties ['padding-right']    = $source_code_style->getProperty('padding-right');
1152        $properties ['padding-bottom']   = $source_code_style->getProperty('padding-bottom');
1153        $properties ['padding-left']     = $source_code_style->getProperty('padding-left');
1154        $properties ['background-color'] = $source_code_style->getProperty('background-color');
1155
1156        $this->document->tableCellOpenUseProperties($properties);
1157
1158        // Generate ODT content from Geshi's HTML code
1159        $this->document->generateODTfromHTMLCode($highlighted_code, $options);
1160
1161        // Close table
1162        $this->document->tableCellClose();
1163        $this->document->tableRowClose();
1164        $this->document->tableClose();
1165    }
1166
1167    /**
1168     * Render an internal media file
1169     *
1170     * @param string $src       media ID
1171     * @param string $title     descriptive text
1172     * @param string $align     left|center|right
1173     * @param int    $width     width of media in pixel
1174     * @param int    $height    height of media in pixel
1175     * @param string $cache     cache|recache|nocache
1176     * @param string $linking   linkonly|detail|nolink
1177     * @param bool   $returnonly whether to return odt or write to doc attribute
1178     */
1179    function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1180                            $height=NULL, $cache=NULL, $linking=NULL, $returnonly = false) {
1181        global $ID;
1182        resolve_mediaid(getNS($ID),$src, $exists);
1183        list(/* $ext */,$mime) = mimetype($src);
1184
1185        if ($linking == 'linkonly') {
1186            $url = str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true));
1187            if (empty($title)) {
1188                $title = $src;
1189            }
1190            if ($returnonly) {
1191                return $this->externallink($url, $title, true);
1192            } else {
1193                $this->externallink($url, $title);
1194            }
1195            return;
1196        }
1197
1198        if(substr($mime,0,5) == 'image'){
1199            $file = mediaFN($src);
1200            if($returnonly) {
1201              return $this->_odtAddImage($file, $width, $height, $align, $title, NULL, true);
1202            } else {
1203              $this->_odtAddImage($file, $width, $height, $align, $title);
1204            }
1205        }else{
1206/*
1207            // FIXME build absolute medialink and call externallink()
1208            $this->code('FIXME internalmedia: '.$src);
1209*/
1210            //FIX by EPO/Intersel - create a link to the dokuwiki internal resource
1211            if (empty($title)) {$title=explode(':',$src); $title=end($title);}
1212            if($returnonly) {
1213              return $this->externalmedia(str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true)),$title,
1214                                        null, null, null, null, null, true);
1215            } else {
1216              $this->externalmedia(str_replace('doku.php?id=','lib/exe/fetch.php?media=',wl($src,'',true)),$title,
1217                                        null, null, null, null, null);
1218            }
1219            //End of FIX
1220        }
1221    }
1222
1223    /**
1224     * Render an external media file
1225     *
1226     * @param string $src        full media URL
1227     * @param string $title      descriptive text
1228     * @param string $align      left|center|right
1229     * @param int    $width      width of media in pixel
1230     * @param int    $height     height of media in pixel
1231     * @param string $cache      cache|recache|nocache
1232     * @param string $linking    linkonly|detail|nolink
1233     * @param bool   $returnonly whether to return odt or write to doc attribute
1234     */
1235    function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1236                            $height=NULL, $cache=NULL, $linking=NULL, $returnonly = false) {
1237        list($ext,$mime) = mimetype($src);
1238
1239        if ($linking == 'linkonly') {
1240            $url = $src;
1241            if (empty($title)) {
1242                $title = $src;
1243            }
1244            if ($returnonly) {
1245                return $this->externallink($url, $title, true);
1246            } else {
1247                $this->externallink($url, $title);
1248            }
1249            return;
1250        }
1251
1252        if(substr($mime,0,5) == 'image'){
1253            $tmp_dir = $this->config->getParam ('tmpdir')."/odt";
1254            $tmp_name = $tmp_dir."/".md5($src).'.'.$ext;
1255            $client = new DokuHTTPClient;
1256            $img = $client->get($src);
1257            if ($img === FALSE) {
1258                $tmp_name = $src; // fallback to a simple link
1259            } else {
1260                if (!is_dir($tmp_dir)) io_mkdir_p($tmp_dir);
1261                $tmp_img = fopen($tmp_name, "w") or die("Can't create temp file $tmp_img");
1262                fwrite($tmp_img, $img);
1263                fclose($tmp_img);
1264            }
1265
1266            $doc = '';
1267            if ($linking != 'nolink') {
1268                $doc .= $this->document->openImageLink ($src, $returnonly);
1269            }
1270            $doc .= $this->_odtAddImage($tmp_name, $width, $height, $align, $title, $returnonly);
1271            if ($linking != 'nolink') {
1272                $doc .= $this->document->closeImageLink ($returnonly);
1273            }
1274            if (file_exists($tmp_name)) unlink($tmp_name);
1275
1276            return $doc;
1277        }else{
1278            if($returnonly) {
1279              return $this->externallink($src,$title,true);
1280            } else {
1281              $this->externallink($src,$title);
1282            }
1283        }
1284    }
1285
1286    /**
1287     * Render a CamelCase link
1288     *
1289     * @param string $link       The link name
1290     * @param bool   $returnonly whether to return odt or write to doc attribute
1291     * @see http://en.wikipedia.org/wiki/CamelCase
1292     */
1293    function camelcaselink($link, $returnonly = false) {
1294        if($returnonly) {
1295          return $this->internallink($link,$link, null, true);
1296        } else {
1297          $this->internallink($link, $link);
1298        }
1299    }
1300
1301    /**
1302     * This function is only used for the DokuWiki specific
1303     * 'returnonly' behaviour.
1304     *
1305     * @param string $id
1306     * @param string $name
1307     */
1308    function reference($id, $name = NULL) {
1309        $ret = '<text:a xlink:type="simple" xlink:href="#'.$id.'"';
1310        if ($name) {
1311            $ret .= '>'.$this->_xmlEntities($name).'</text:a>';
1312        } else {
1313            $ret .= '/>';
1314        }
1315        return $ret;
1316    }
1317
1318    /**
1319     * Render a wiki internal link
1320     *
1321     * @param string       $id         page ID to link to. eg. 'wiki:syntax'
1322     * @param string|array $name       name for the link, array for media file
1323     * @param bool         $returnonly whether to return odt or write to doc attribute
1324     *
1325     * @author Andreas Gohr <andi@splitbrain.org>
1326     */
1327    function internallink($id, $name = NULL, $returnonly = false) {
1328        global $ID;
1329        // default name is based on $id as given
1330        $default = $this->_simpleTitle($id);
1331        // now first resolve and clean up the $id
1332        resolve_pageid(getNS($ID),$id,$exists);
1333        $name = $this->_getLinkTitle($name, $default, $isImage, $id);
1334
1335        // build the absolute URL (keeping a hash if any)
1336        list($id,$hash) = explode('#',$id,2);
1337        $url = wl($id,'',true);
1338        if($hash) $url .='#'.$hash;
1339
1340        if ($ID == $id) {
1341            if ($hash) {
1342                $id = $hash;
1343            }
1344            if($returnonly) {
1345                return $this->locallink_with_text($hash, $id, $name, $returnonly);
1346            } else {
1347                $this->locallink_with_text($hash, $id, $name, $returnonly);
1348            }
1349        } else {
1350            if($returnonly) {
1351                return $this->_doLink($url, $name, $returnonly);
1352            } else {
1353                $this->_doLink($url, $name, $returnonly);
1354            }
1355        }
1356    }
1357
1358    /**
1359     * Add external link
1360     *
1361     * @param string       $url        full URL with scheme
1362     * @param string|array $name       name for the link, array for media file
1363     * @param bool         $returnonly whether to return odt or write to doc attribute
1364     */
1365    function externallink($url, $name = NULL, $returnonly = false) {
1366        $name = $this->_getLinkTitle($name, $url, $isImage);
1367
1368        if($returnonly) {
1369            return $this->_doLink($url, $name, $returnonly);
1370        } else {
1371            $this->_doLink($url, $name, $returnonly);
1372        }
1373    }
1374
1375    /**
1376     * Inserts a local link with text.
1377     *
1378     * @fixme add image handling
1379     *
1380     * @param string $hash hash link identifier
1381     * @param string $id   name for the link (the reference)
1382     * @param string $text text for the link (text inserted instead of reference)
1383     */
1384    function locallink_with_text($hash, $id = NULL, $text = NULL, $returnonly = false){
1385        if (!$returnonly) {
1386            $id  = $this->_getLinkTitle($id, $hash, $isImage);
1387            $this->document->insertCrossReference($id, $text);
1388        } else {
1389            return reference($hash, $name);
1390        }
1391    }
1392
1393    /**
1394     * Inserts a local link.
1395     *
1396     * @fixme add image handling
1397     *
1398     * @param string $hash hash link identifier
1399     * @param string $name name for the link
1400     */
1401    function locallink($hash, $name = NULL){
1402        $name  = $this->_getLinkTitle($name, $hash, $isImage);
1403        $this->document->insertCrossReference($hash, $name);
1404    }
1405
1406    /**
1407     * Render an interwiki link
1408     *
1409     * You may want to use $this->_resolveInterWiki() here
1410     *
1411     * @param string       $match      original link - probably not much use
1412     * @param string|array $name       name for the link, array for media file
1413     * @param string       $wikiName   indentifier (shortcut) for the remote wiki
1414     * @param string       $wikiUri    the fragment parsed from the original link
1415     * @param bool         $returnonly whether to return odt or write to doc attribute
1416     */
1417    function interwikilink($match, $name = NULL, $wikiName, $wikiUri, $returnonly = false) {
1418        $name  = $this->_getLinkTitle($name, $wikiUri, $isImage);
1419        $url = $this-> _resolveInterWiki($wikiName,$wikiUri);
1420        if($returnonly) {
1421            return $this->_doLink($url, $name, $returnonly);
1422        } else {
1423            $this->_doLink($url, $name, $returnonly);
1424        }
1425    }
1426
1427    /**
1428     * Just print WindowsShare links
1429     *
1430     * @fixme add image handling
1431     *
1432     * @param string       $url        the link
1433     * @param string|array $name       name for the link, array for media file
1434     * @param bool         $returnonly whether to return odt or write to doc attribute
1435     */
1436    function windowssharelink($url, $name = NULL, $returnonly = false) {
1437        $name  = $this->_getLinkTitle($name, $url, $isImage);
1438        if($returnonly) {
1439            return $name;
1440        } else {
1441            $this->document->addPlainText($name);
1442        }
1443    }
1444
1445    /**
1446     * Just print email links
1447     *
1448     * @fixme add image handling
1449     *
1450     * @param string       $address    Email-Address
1451     * @param string|array $name       name for the link, array for media file
1452     * @param bool         $returnonly whether to return odt or write to doc attribute
1453     */
1454    function emaillink($address, $name = NULL, $returnonly = false) {
1455        $name  = $this->_getLinkTitle($name, $address, $isImage);
1456        if($returnonly) {
1457            return $this->_doLink("mailto:".$address, $name, $returnonly);
1458        } else {
1459            $this->_doLink("mailto:".$address, $name, $returnonly);
1460        }
1461    }
1462
1463    /**
1464     * Add a hyperlink, handling Images correctly
1465     *
1466     * @author Andreas Gohr <andi@splitbrain.org>
1467     *
1468     * @param string $url
1469     * @param string|array $name
1470     */
1471    function _doLink($url,$name, $returnonly = false){
1472        $url = $this->_xmlEntities($url);
1473        $doc = '';
1474        if(is_array($name)){
1475            // Images
1476            $doc .= $this->document->openImageLink ($url, $returnonly);
1477
1478            if($name['type'] == 'internalmedia'){
1479                $doc .= $this->internalmedia($name['src'],
1480                                     $name['title'],
1481                                     $name['align'],
1482                                     $name['width'],
1483                                     $name['height'],
1484                                     $name['cache'],
1485                                     $name['linking'],
1486                                     $returnonly);
1487            }
1488
1489            $doc .= $this->document->closeImageLink ($returnonly);
1490        }else{
1491            // Text
1492            $doc .= $this->document->insertHyperlink ($url, $name, NULL, NULL, $returnonly);
1493        }
1494        return $doc;
1495    }
1496
1497    /**
1498     * Construct a title and handle images in titles
1499     *
1500     * @author Harry Fuecks <hfuecks@gmail.com>
1501     *
1502     * @param string|array|null $title
1503     * @param string $default
1504     * @param bool|null $isImage
1505     * @param string $id
1506     * @return mixed
1507     */
1508    function _getLinkTitle($title, $default, & $isImage, $id=null) {
1509        $isImage = false;
1510        if ( is_array($title) ) {
1511            $isImage = true;
1512            return $title;
1513        } elseif (is_null($title) || trim($title) == '') {
1514            if ($this->config->getParam ('useheading') && $id) {
1515                $heading = p_get_first_heading($id);
1516                if ($heading) {
1517                    return $this->_xmlEntities($heading);
1518                }
1519            }
1520            return $this->_xmlEntities($default);
1521        } else {
1522            return $this->_xmlEntities($title);
1523        }
1524    }
1525
1526    /**
1527     * @param string $value
1528     * @return string
1529     */
1530    function _xmlEntities($value) {
1531        return str_replace( array('&','"',"'",'<','>'), array('&#38;','&#34;','&#39;','&#60;','&#62;'), $value);
1532    }
1533
1534    /**
1535     * Render the output of an RSS feed
1536     *
1537     * @param string $url    URL of the feed
1538     * @param array  $params Finetuning of the output
1539     */
1540    function rss ($url,$params){
1541        global $lang;
1542
1543        require_once(DOKU_INC . 'inc/FeedParser.php');
1544        $feed = new FeedParser();
1545        $feed->feed_url($url);
1546
1547        //disable warning while fetching
1548        $elvl = null;
1549        if (!defined('DOKU_E_LEVEL')) { $elvl = error_reporting(E_ERROR); }
1550        $rc = $feed->init();
1551        if (!defined('DOKU_E_LEVEL')) { error_reporting($elvl); }
1552
1553        //decide on start and end
1554        if($params['reverse']){
1555            $mod = -1;
1556            $start = $feed->get_item_quantity()-1;
1557            $end   = $start - ($params['max']);
1558            $end   = ($end < -1) ? -1 : $end;
1559        }else{
1560            $mod   = 1;
1561            $start = 0;
1562            $end   = $feed->get_item_quantity();
1563            $end   = ($end > $params['max']) ? $params['max'] : $end;;
1564        }
1565
1566        $this->listu_open();
1567        if($rc){
1568            for ($x = $start; $x != $end; $x += $mod) {
1569                $item = $feed->get_item($x);
1570                $this->document->listItemOpen(0);
1571                $this->document->listContentOpen();
1572
1573                $this->externallink($item->get_permalink(),
1574                                    $item->get_title());
1575                if($params['author']){
1576                    $author = $item->get_author(0);
1577                    if($author){
1578                        $name = $author->get_name();
1579                        if(!$name) $name = $author->get_email();
1580                        if($name) $this->cdata(' '.$lang['by'].' '.$name);
1581                    }
1582                }
1583                if($params['date']){
1584                    $this->cdata(' ('.$item->get_date($this->config->getParam ('dformat')).')');
1585                }
1586                if($params['details']){
1587                    $this->cdata(strip_tags($item->get_description()));
1588                }
1589                $this->document->listContentClose();
1590                $this->document->listItemClose();
1591            }
1592        }else{
1593            $this->document->listItemOpen(0);
1594            $this->document->listContentOpen();
1595            $this->emphasis_open();
1596            $this->cdata($lang['rssfailed']);
1597            $this->emphasis_close();
1598            $this->externallink($url);
1599            $this->document->listContentClose();
1600            $this->document->listItemClose();
1601        }
1602        $this->listu_close();
1603    }
1604
1605    /**
1606     * Adds the content of $string as a SVG picture to the document.
1607     *
1608     * @see ODTDocument::addStringAsSVGImage for API wrapper function
1609     * @see ODTImage::addStringAsSVGImage for a detailed description
1610     */
1611    function _addStringAsSVGImage($string, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL) {
1612        $this->document->addStringAsSVGImage($string, $width, $height, $align, $title, $style);
1613    }
1614
1615    /**
1616     * The function adds $string as an SVG image file.
1617     * It does NOT insert the image in the document.
1618     *
1619     * @see ODTDocument::addStringAsSVGImageFile for a detailed description
1620     * @see ODTImage::addStringAsSVGImageFile for a detailed description
1621     */
1622    function _addStringAsSVGImageFile($string) {
1623        return $this->document->addStringAsSVGImageFile($string);
1624    }
1625
1626    /**
1627     * Adds the image $src as a picture file without adding it to the content
1628     * of the document. The link name which can be used for the ODT draw:image xlink:href
1629     * is returned. The caller is responsible for creating the frame and image tag
1630     * but therefore has full control over it. This means he can also set parameters
1631     * in the odt frame and image tag which can not be changed using the function _odtAddImage.
1632     *
1633     * @author LarsDW223
1634     *
1635     * @param string $src
1636     * @return string
1637     */
1638    function _odtAddImageAsFileOnly($src){
1639        return $this->document->addFileAsPicture($src);
1640    }
1641
1642    /**
1643     * Adds an image $src to the document.
1644     *
1645     * @param string  $src        The path to the image file
1646     * @param string  $width      Width of the picture (NULL=original size)
1647     * @param string  $height     Height of the picture (NULL=original size)
1648     * @param string  $align      Alignment
1649     * @param string  $title      Title
1650     * @param string  $style      Optional "draw:style-name"
1651     * @param boolean $returnonly Only return code
1652     *
1653     * @see ODTDocument::addImage for API wrapper function
1654     * @see ODTImage::addImage for a detailed description
1655     */
1656    function _odtAddImage($src, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL, $returnonly = false){
1657        if ($returnonly) {
1658            return $this->document->addImage($src, $width, $height, $align, $title, $style, $returnonly);
1659        } else {
1660            $this->document->addImage($src, $width, $height, $align, $title, $style, $returnonly);
1661        }
1662    }
1663
1664    /**
1665     * Adds an image $src to the document using the parameters set in $properties.
1666     *
1667     * @param string  $src        The path to the image file
1668     * @param array   $properties Properties (width, height... see ODTImage::addImageUseProperties)
1669     * @param boolean $returnonly Only return code
1670     *
1671     * @see ODTDocument::addImageUseProperties for API wrapper function
1672     * @see ODTImage::addImageUseProperties for a detailed description
1673     */
1674    function _odtAddImageUseProperties($src, array $properties, $returnonly = false){
1675        if ($returnonly) {
1676            return $this->document->addImageUseProperties($src, $properties, $returnonly);
1677        } else {
1678            $this->document->addImageUseProperties($src, $properties, $returnonly);
1679        }
1680    }
1681
1682    /**
1683     * The function tries to examine the width and height
1684     * of the image stored in file $src.
1685     *
1686     * @see ODTDocument::getImageSize for API wrapper function
1687     * @see ODTUtility::getImageSize for a detailed description
1688     */
1689    public function _odtGetImageSize($src, $maxwidth=NULL, $maxheight=NULL){
1690        return $this->document->getImageSize($src, $maxwidth, $maxheight);
1691    }
1692
1693    /**
1694     * @param string $src
1695     * @param  $width
1696     * @param  $height
1697     * @return array
1698     */
1699    function _odtGetImageSizeString($src, $width = NULL, $height = NULL){
1700        return $this->document->getImageSizeString($src, $width, $height);
1701    }
1702
1703    /**
1704     * Open a span using CSS.
1705     *
1706     * @see ODTDocument::spanOpenUseCSS for API wrapper function
1707     * @see ODTSpan::spanOpenUseCSS for detailed documentation
1708     * @author LarsDW223
1709     */
1710    function _odtSpanOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1711        $this->document->spanOpenUseCSS($element, $attributes, $import);
1712    }
1713
1714    /**
1715     * Open a span using properties.
1716     *
1717     * @see ODTDocument::spanOpenUseProperties for API wrapper function
1718     * @see ODTSpan::spanOpenUseProperties for detailed documentation
1719     * @author LarsDW223
1720     */
1721    function _odtSpanOpenUseProperties($properties){
1722        $this->document->spanOpenUseProperties($properties);
1723    }
1724
1725    function _odtSpanOpen($style_name){
1726        $this->document->spanOpen($style_name);
1727    }
1728
1729    /**
1730     * This function closes a span (previously opened with _odtSpanOpenUseCSS).
1731     *
1732     * @author LarsDW223
1733     */
1734    function _odtSpanClose(){
1735        $this->document->spanClose();
1736    }
1737
1738    /**
1739     * Open a paragraph using CSS.
1740     *
1741     * @see ODTDocument::paragraphOpenUseCSS for API wrapper function
1742     * @see ODTParagraph::paragraphOpenUseCSS for detailed documentation
1743     * @author LarsDW223
1744     */
1745    function _odtParagraphOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1746        $this->document->paragraphOpenUseCSS($element, $attributes, $import);
1747    }
1748
1749    /**
1750     * Open a paragraph using properties.
1751     *
1752     * @see ODTDocument::paragraphOpenUseProperties for API wrapper function
1753     * @see ODTParagraph::paragraphOpenUseProperties for detailed documentation
1754     * @author LarsDW223
1755     */
1756    function _odtParagraphOpenUseProperties($properties){
1757        $this->document->paragraphOpenUseProperties($properties);
1758    }
1759
1760    /**
1761     * Open a text box using CSS.
1762     *
1763     * @see ODTDocument::openTextBoxUseCSS for API wrapper function
1764     * @see ODTFrame::openTextBoxUseCSS for detailed documentation
1765     */
1766    function _odtOpenTextBoxUseCSS ($element=NULL, $attributes=NULL, cssimportnew $import=NULL) {
1767        $this->document->openTextBoxUseCSS ($element, $attributes, $import);
1768    }
1769
1770    /**
1771     * This function opens a div. As divs are not supported by ODT, it will be exported as a frame.
1772     * To be more precise, to frames will be created. One including a picture nad the other including the text.
1773     * A picture frame will only be created if a 'background-image' is set in the CSS style.
1774     *
1775     * The currently supported CSS properties are:
1776     * background-color, color, padding, margin, display, border-radius, min-height.
1777     * The background-image is simulated using a picture frame.
1778     * FIXME: Find a way to successfuly use the background-image in the graphic style (see comments).
1779     *
1780     * The div should be closed by calling '_odtDivCloseAsFrame'.
1781     *
1782     * @author LarsDW223
1783     *
1784     * @param array $properties
1785     */
1786    function _odtDivOpenAsFrameUseProperties ($properties) {
1787        dbg_deprecated('_odtOpenTextBoxUseProperties');
1788        $this->_odtOpenTextBoxUseProperties ($properties);
1789    }
1790
1791    /**
1792     * This function closes a div/frame (previously opened with _odtDivOpenAsFrameUseCSS).
1793     *
1794     * @author LarsDW223
1795     */
1796    function _odtDivCloseAsFrame () {
1797        $this->_odtCloseTextBox();
1798    }
1799
1800    /**
1801     * This function opens a new table using CSS.
1802     *
1803     * @author LarsDW223
1804     * @see ODTDocument::tableOpenUseCSS for API wrapper function
1805     * @see ODTTable::tableOpenUseCSS for detailed documentation
1806     */
1807    function _odtTableOpenUseCSS($maxcols = NULL, $numrows = NULL, $element=NULL, $attributes = NULL, cssimportnew $import = NULL){
1808        $this->document->tableOpenUseCSS($maxcols, $numrows, $element, $attributes, $import);
1809    }
1810
1811    /**
1812     * This function opens a new table using properties.
1813     *
1814     * @author LarsDW223
1815     * @see ODTDocument::tableOpenUseProperties for API wrapper function
1816     * @see ODTTable::tableOpenUseProperties for detailed documentation
1817     */
1818    function _odtTableOpenUseProperties ($properties, $maxcols = 0, $numrows = 0){
1819        $this->document->tableOpenUseProperties ($properties, $maxcols, $numrows);
1820    }
1821
1822    /**
1823     * This function closes a table.
1824     *
1825     * @author LarsDW223
1826     * @see ODTDocument::tableClose for API wrapper function
1827     * @see ODTTable::tableClose for detailed documentation
1828     */
1829    function _odtTableClose () {
1830        $this->document->tableClose();
1831    }
1832
1833    /**
1834     * This function adds a new table column using properties.
1835     *
1836     * @author LarsDW223
1837     * @see ODTDocument::tableAddColumnUseProperties for API wrapper function
1838     * @see ODTTable::tableAddColumnUseProperties for detailed documentation
1839     */
1840    function _odtTableAddColumnUseProperties (array $properties = NULL){
1841        $this->document->tableAddColumnUseProperties($properties);
1842    }
1843
1844    /**
1845     * This function opens a new table header using CSS.
1846     * The header should be closed by calling 'tableheader_close()'.
1847     *
1848     * @author LarsDW223
1849     * @see ODTDocument::tableHeaderOpenUseCSS for API wrapper function
1850     * @see ODTTable::tableHeaderOpenUseCSS for detailed documentation
1851     */
1852    function _odtTableHeaderOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1853        $this->document->tableHeaderOpenUseCSS($colspan, $rowspan, $element, $attributes, $import);
1854    }
1855
1856    /**
1857     * This function opens a new table header using properties.
1858     * The header should be closed by calling 'tableheader_close()'.
1859     *
1860     * @author LarsDW223
1861     * @see ODTDocument::tableHeaderOpenUseProperties for API wrapper function
1862     * @see ODTTable::tableHeaderOpenUseProperties for detailed documentation
1863     */
1864    function _odtTableHeaderOpenUseProperties ($properties = NULL, $colspan = 1, $rowspan = 1){
1865        $this->document->tableHeaderOpenUseProperties($properties, $colspan = 1, $rowspan = 1);
1866    }
1867
1868    /**
1869     * This function opens a new table row using CSS.
1870     * The row should be closed by calling 'tablerow_close()'.
1871     *
1872     * @author LarsDW223
1873     * @see ODTDocument::tableRowOpenUseCSS for API wrapper function
1874     * @see ODTTable::tableRowOpenUseCSS for detailed documentation
1875     */
1876    function _odtTableRowOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1877        $this->document->tableRowOpenUseCSS($element, $attributes, $import);
1878    }
1879
1880    /**
1881     * This function opens a new table row using properties.
1882     * The row should be closed by calling 'tablerow_close()'.
1883     *
1884     * @author LarsDW223
1885     * @see ODTDocument::tableRowOpenUseProperties for API wrapper function
1886     * @see ODTTable::tableRowOpenUseProperties for detailed documentation
1887     */
1888    function _odtTableRowOpenUseProperties ($properties){
1889        $this->document->tableRowOpenUseProperties($properties);
1890    }
1891
1892    /**
1893     * This function opens a new table cell using CSS.
1894     * The cell should be closed by calling 'tablecell_close()'.
1895     *
1896     * @author LarsDW223
1897     * @see ODTDocument::tableCellOpenUseCSS for API wrapper function
1898     * @see ODTTable::tableCellOpenUseCSS for detailed documentation
1899     */
1900    function _odtTableCellOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){
1901        $this->document->tableCellOpenUseCSS($colspan, $rowspan, $element, $attributes, $import);
1902    }
1903
1904    /**
1905     * This function opens a new table cell using properties.
1906     * The cell should be closed by calling 'tablecell_close()'.
1907     *
1908     * @author LarsDW223
1909     * @see ODTDocument::tableCellOpenUseProperties for API wrapper function
1910     * @see ODTTable::tableCellOpenUseProperties for detailed documentation
1911     */
1912    function _odtTableCellOpenUseProperties ($properties, $colspan = 1, $rowspan = 1){
1913        $this->document->tableCellOpenUseProperties($properties, $colspan, $rowspan);
1914    }
1915
1916    /**
1917     * Open a multi column text box in a frame using properties.
1918     *
1919     * @see ODTDocument::openMultiColumnTextBoxUseProperties for API wrapper function
1920     * @see ODTFrame::openMultiColumnTextBoxUseProperties for detailed documentation
1921     */
1922    function _odtOpenMultiColumnFrame ($properties) {
1923        $this->document->openMultiColumnTextBoxUseProperties($properties);
1924    }
1925
1926    /**
1927     * This function closes a multi column frame (previously opened with _odtOpenMultiColumnFrame).
1928     *
1929     * @see ODTDocument::closeTextBox for API wrapper function
1930     * @see ODTFrame::closeTextBox for detailed documentation
1931     * @author LarsDW223
1932     */
1933    function _odtCloseMultiColumnFrame () {
1934        $this->document->closeMultiColumnTextBox();
1935    }
1936
1937    /**
1938     * Open a text box in a frame using properties.
1939     *
1940     * @see ODTDocument::openTextBoxUseProperties for API wrapper function
1941     * @see ODTFrame::openTextBoxUseProperties for detailed documentation
1942     */
1943    function _odtOpenTextBoxUseProperties ($properties) {
1944        $this->document->openTextBoxUseProperties ($properties);
1945    }
1946
1947    /**
1948     * This function closes a textbox.
1949     *
1950     * @see ODTDocument::closeTextBox for API wrapper function
1951     * @see ODTFrame::closeTextBox for detailed documentation
1952     * @author LarsDW223
1953     */
1954    function _odtCloseTextBox () {
1955        $this->document->closeTextBox();
1956    }
1957
1958    /**
1959     * Open a frame using properties.
1960     *
1961     * @see ODTDocument::openFrameUseProperties for API wrapper function
1962     * @see ODTFrame::openFrameUseProperties for detailed documentation
1963     */
1964    function _odtOpenFrameUseProperties ($properties) {
1965        $this->document->openFrameUseProperties ($properties);
1966    }
1967
1968    /**
1969     * This function closes a frame.
1970     *
1971     * @see ODTDocument::closeFrame for API wrapper function
1972     * @see ODTFrame::closeFrame for detailed documentation
1973     * @author LarsDW223
1974     */
1975    function _odtCloseFrame () {
1976        $this->document->closeFrame();
1977    }
1978
1979    /**
1980     * @param array $dest
1981     * @param $element
1982     * @param $classString
1983     * @param $inlineStyle
1984     */
1985    public function getODTProperties (&$dest, $element, $classString, $inlineStyle, $media_sel=NULL, $cssId=NULL) {
1986        if (!isset($media_sel)) {
1987            $media_sel = $this->config->getParam ('media_sel');
1988        }
1989        // Get properties for our class/element from imported CSS
1990        $this->import->getPropertiesForElement($dest, $element, $classString, $media_sel, $cssId);
1991
1992        // Interpret and add values from style to our properties
1993        $this->document->getCSSStylePropertiesForODT($dest, $inlineStyle);
1994
1995        // Adjust values for ODT
1996        //foreach ($dest as $property => $value) {
1997        //    $dest [$property] = $this->adjustValueForODT ($property, $value, 14);
1998        //}
1999        $this->document->adjustValuesForODT($dest);
2000    }
2001
2002    /**
2003     * Replace a CSS URL value with the given path.
2004     *
2005     * @param $URL CSS URL e.g. 'url(images/xyz.png);'
2006     * @param $replacement The local path
2007     * @return string The resulting complete file path
2008     */
2009    public function replaceURLPrefix ($URL, $replacement) {
2010        return $this->import->replaceURLPrefix ($URL, $replacement);
2011    }
2012
2013    /**
2014     * Convert pixel to points (X axis).
2015     *
2016     * @param $pixel value to convert
2017     * @return float The converted value in points
2018     * @see ODTDocument::toPoints for API wrapper function
2019     * @see ODTUnits::toPoints for detailed documentation
2020     */
2021    public function pixelToPointsX ($pixel) {
2022        return $this->document->toPoints($pixel, 'x');
2023    }
2024
2025    /**
2026     * Convert pixel to points (Y axis).
2027     *
2028     * @param $pixel value to convert
2029     * @return float The converted value in points
2030     * @see ODTDocument::toPoints for API wrapper function
2031     * @see ODTUnits::toPoints for detailed documentation
2032     */
2033    public function pixelToPointsY ($pixel) {
2034        return $this->document->toPoints($pixel, 'y');
2035    }
2036
2037    /**
2038     * Adjust the given property for ODT.
2039     *
2040     * @param $property The property name
2041     * @param $value The property value
2042     * @param int $emValue The conversion value for 'em' units
2043     * @return string The new, adjusted value
2044     * @see ODTUtility::adjustValueForODT for detailed documentation
2045     */
2046    public function adjustValueForODT ($property, $value) {
2047        return $this->document->adjustValueForODT ($property, $value);
2048    }
2049
2050    /**
2051     * Callback function which adjusts all CSS length values to point.
2052     *
2053     * @param $property The name of the current CSS property, e.g. 'border-left'
2054     * @param $value The current value from the original CSS code
2055     * @param $type There are 3 possible values:
2056     *              - LengthValueXAxis: the property represents a value on the X axis
2057     *              - LengthValueYAxis: the property represents a value on the Y axis
2058     *              - CSSValueType::StrokeOrBorderWidth: the property represents a stroke
2059     *                or border width
2060     * @return string The new, adjusted value for the property
2061     */
2062    public function adjustLengthCallback ($property, $value, $type) {
2063        // Replace px with pt (px does not seem to be supported by ODT)
2064        $length = strlen ($value);
2065        if ( $length > 2 && $value [$length-2] == 'p' && $value [$length-1] == 'x' ) {
2066            $number = trim($value, 'px');
2067            switch ($type) {
2068                case CSSValueType::LengthValueXAxis:
2069                    $adjusted = $this->pixelToPointsX($number).'pt';
2070                break;
2071
2072                case CSSValueType::StrokeOrBorderWidth:
2073                    switch ($property) {
2074                        case 'border':
2075                        case 'border-left':
2076                        case 'border-right':
2077                        case 'border-top':
2078                        case 'border-bottom':
2079                            // border in ODT spans does not support 'px' units, so we convert it.
2080                            $adjusted = $this->pixelToPointsY($number).'pt';
2081                        break;
2082
2083                        default:
2084                            $adjusted = $value;
2085                        break;
2086                    }
2087                break;
2088
2089                case CSSValueType::LengthValueYAxis:
2090                default:
2091                    $adjusted = $this->pixelToPointsY($number).'pt';
2092                break;
2093            }
2094            return $adjusted;
2095        }
2096        return $value;
2097    }
2098
2099    /**
2100     * This function read the template page and imports all cdata and code content
2101     * as additional CSS. ATTENTION: this might overwrite already imported styles
2102     * from an ODT or CSS template file.
2103     *
2104     * @param $pagename The name of the template page
2105     */
2106    public function read_templatepage ($pagename) {
2107        $instructions = p_cached_instructions(wikiFN($pagename));
2108        $text = '';
2109        foreach($instructions as $instruction) {
2110            if($instruction[0] == 'code') {
2111                $text .= $instruction[1][0];
2112            } elseif ($instruction[0] == 'cdata') {
2113                $text .= $instruction[1][0];
2114            }
2115        }
2116
2117        $this->document->importCSSFromString
2118            ($text, $this->config->getParam('media_sel'), array($this, 'replaceURLPrefixesCallback'), true, $this->config->getParam('olist_label_align'));
2119    }
2120
2121    /**
2122     * Get CSS properties for a given element and adjust them for ODT.
2123     *
2124     * @see ODTDocument::getODTProperties for more information
2125     */
2126    public function getODTPropertiesNew (&$dest, $element, $attributes=NULL, $media_sel=NULL, $inherit=true) {
2127        if (!isset($media_sel)) {
2128            $media_sel = $this->config->getParam ('media_sel');
2129        }
2130        $this->document->getODTProperties ($dest, $element, $attributes, $media_sel, $inherit);
2131    }
2132
2133    public function getODTPropertiesFromElement (&$dest, iElementCSSMatchable $element, $media_sel=NULL, $inherit=true) {
2134        if (!isset($media_sel)) {
2135            $media_sel = $this->config->getParam ('media_sel');
2136        }
2137        $this->document->getODTPropertiesFromElement ($dest, $element, $media_sel, $inherit);
2138    }
2139
2140    /**
2141     * This function creates a text style.
2142     *
2143     * @see ODTDocument::createTextStyle for detailed desciption.
2144     */
2145    public function createTextStyle ($properties, $common=true) {
2146        $this->document->createTextStyle ($properties, $common);
2147    }
2148
2149    /**
2150     * This function creates a paragraph style.
2151     *
2152     * @see ODTDocument::createParagraphStyle for detailed desciption.
2153     */
2154    public function createParagraphStyle ($properties, $common=true) {
2155        $this->document->createParagraphStyle ($properties, $common);
2156    }
2157
2158    /**
2159     * This function creates a table style.
2160     *
2161     * @see ODTDocument::createTableStyle for detailed desciption.
2162     */
2163    public function createTableStyle ($properties, $common=true) {
2164        $this->document->createTableStyle ($properties, $common);
2165    }
2166
2167    /**
2168     * This function creates a table row style.
2169     *
2170     * @see ODTDocument::createTableRowStyle for detailed desciption.
2171     */
2172    public function createTableRowStyle ($properties, $common=true) {
2173        $this->document->createTableRowStyle ($properties, $common);
2174    }
2175
2176    /**
2177     * This function creates a table cell style.
2178     *
2179     * @see ODTDocument::createTableCellStyle for detailed  desciption.
2180     */
2181    public function createTableCellStyle ($properties, $common=true) {
2182        $this->document->createTableCellStyle ($properties, $common);
2183    }
2184
2185    /**
2186     * This function creates a table column style.
2187     *
2188     * @see ODTDocument::createTableColumnStyle for detailed desciption.
2189     */
2190    public function createTableColumnStyle ($properties, $common=true) {
2191        $this->document->createTableColumnStyle ($properties, $common);
2192    }
2193
2194    public function styleExists ($style_name) {
2195        return $this->document->styleExists($style_name);
2196    }
2197
2198    /**
2199     * Add a user field.
2200     * (Code has been adopted from the fields plugin)
2201     *
2202     * @param string $name The name of the field
2203     * @param string $value The value of the field
2204     * @author Aurelien Bompard <aurelien@bompard.org>
2205     * @see ODTDocument::addUserField for detailed desciption.
2206     */
2207    public function addUserField($name, $value) {
2208        $this->document->addUserField($name, $value);
2209    }
2210
2211    /**
2212     * Insert a user field reference.
2213     * (Code has been adopted from the fields plugin)
2214     *
2215     * @param string $name The name of the field
2216     * @author Aurelien Bompard <aurelien@bompard.org>
2217     * @see ODTDocument::insertUserField for detailed desciption.
2218     */
2219    public function insertUserField($name) {
2220        $this->document->insertUserField($name);
2221    }
2222
2223    protected function buildODTPathes (&$ODTTemplatePath, &$tempDirPath) {
2224        global $ID;
2225
2226        // Temp dir
2227        if (is_dir($this->config->getParam('tmpdir'))) {
2228            $tempDirPath = $this->config->getParam('tmpdir');
2229        }
2230        $tempDirPath = $tempDirPath."/odt/".str_replace(':','-',$ID);
2231
2232        // Eventually determine ODT template file
2233        $ODTTemplatePath = NULL;
2234        $template = $this->config->getParam ('odt_template');
2235        if (!empty($template)) {
2236            $ODTTemplatePath = $this->config->getParam('mediadir').'/'.$this->config->getParam ('tpl_dir')."/".$this->config->getParam ('odt_template');
2237        }
2238    }
2239
2240    public function addToValue ($value, $add) {
2241        return $this->document->addToValue ($value, $add);
2242    }
2243
2244    public function subFromValue ($value, $sub) {
2245        return $this->document->subFromValue ($value, $sub);
2246    }
2247
2248    public function getHTMLStack () {
2249        return $this->document->getHTMLStack ();
2250    }
2251
2252    public function dumpHTMLStack () {
2253        $this->document->dumpHTMLStack ();
2254    }
2255
2256    public function setOrderedListParams ($setLevel, $align, $paddingLeft=0, $marginLeft=1) {
2257        $this->document->setOrderedListParams($setLevel, $align, $paddingLeft, $marginLeft);
2258    }
2259
2260    public function setUnorderedListParams ($setLevel, $align, $paddingLeft=0, $marginLeft=1) {
2261        $this->document->setUnorderedListParams($setLevel, $align, $paddingLeft, $marginLeft);
2262    }
2263
2264    /**
2265     * Insert a bookmark.
2266     *
2267     * @param string $id    ID of the bookmark
2268     * @param string $now   Insert bookmark immediately?
2269     * @see ODTDocument::insertBookmark for detailed desciption.
2270     */
2271    public function insertBookmark($id, $now=true) {
2272        $this->document->insertBookmark($id, $now);
2273    }
2274
2275    /**
2276     * Automatically generate ODT elements from HTML code.
2277     *
2278     * @param string $html_code The HTML code to convert
2279     * @param array  $options   Options array (FIXME: documentation needed)
2280     * @see ODTUtility::generateODTfromHTMLCode for detailed desciption.
2281     */
2282    public function generateODTfromHTMLCode($html_code, $options=null) {
2283        // Generate ODT content from Geshi's HTML code
2284        $this->document->generateODTfromHTMLCode($html_code, $options);
2285    }
2286}
2287
2288//Setup VIM: ex: et ts=4 enc=utf-8 :
2289