1<?php
2/**
3 * ODTPageLayoutStyle: class for ODT page layout styles.
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author LarsDW223
7 */
8
9require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
10require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
11
12/**
13 * The ODTPageLayoutStyle class
14 */
15class ODTPageLayoutStyle extends ODTStyle
16{
17    static $page_layout_fields = array(
18        // Fields belonging to "style:master-page"
19        'style-name'                       => array ('style:name',                       'style', false),
20        'style-page-usage'                 => array ('style:page-usage',                 'style', false),
21    );
22
23    static $layout_props_fields = array(
24        // Fields belonging to "style:page-layout-properties"
25        'width'                            => array ('fo:page-width',                       'props', true),
26        'height'                           => array ('fo:page-height',                      'props', true),
27        'num-format'                       => array ('style:num-format',                    'props', true),
28        'num-letter-sync'                  => array ('style:num-letter-sync',               'props', true),
29        'num-prefix'                       => array ('style:num-prefix',                    'props', true),
30        'num-suffix'                       => array ('style:num-suffix',                    'props', true),
31        'paper-tray-name'                  => array ('style:paper-tray-name',               'props', true),
32        'print-orientation'                => array ('style:print-orientation',             'props', true),
33        'margin-left'                      => array ('fo:margin-left',                      'props', true),
34        'margin-right'                     => array ('fo:margin-right',                     'props', true),
35        'margin-top'                       => array ('fo:margin-top',                       'props', true),
36        'margin-bottom'                    => array ('fo:margin-bottom',                    'props', true),
37        'margin'                           => array ('fo:margin',                           'props', true),
38        'border'                           => array ('fo:border',                           'props', true),
39        'border-top'                       => array ('fo:border-top',                       'props', true),
40        'border-right'                     => array ('fo:border-right',                     'props', true),
41        'border-bottom'                    => array ('fo:border-bottom',                    'props', true),
42        'border-left'                      => array ('fo:border-left',                      'props', true),
43        'border-line-width'                => array ('style:border-line-width',             'props', true),
44        'border-line-width-top'            => array ('style:border-line-width-top',         'props', true),
45        'border-line-width-bottom'         => array ('style:border-line-width-bottom',      'props', true),
46        'border-line-width-left'           => array ('style:border-line-width-left',        'props', true),
47        'border-line-width-right'          => array ('style:border-line-width-right',       'props', true),
48        'padding'                          => array ('fo:padding',                          'props', true),
49        'padding-top'                      => array ('fo:padding-top',                      'props', true),
50        'padding-bottom'                   => array ('fo:padding-bottom',                   'props', true),
51        'padding-left'                     => array ('fo:padding-left',                     'props', true),
52        'padding-right'                    => array ('fo:padding-right',                    'props', true),
53        'shadow'                           => array ('style:shadow',                        'props', true),
54        'background-color'                 => array ('fo:background-color',                 'props', true),
55        'register-truth-ref-style-name'    => array ('style:register-truth-ref-style-name', 'props', true),
56        'print'                            => array ('style:print',                         'props', true),
57        'print-page-order'                 => array ('style:print-page-order',              'props', true),
58        'first-page-number'                => array ('style:first-page-number',             'props', true),
59        'scale-to'                         => array ('style:scale-to',                      'props', true),
60        'scale-to-pages'                   => array ('style:scale-to-pages',                'props', true),
61        'table-centering'                  => array ('style:table-centering',               'props', true),
62        'footnote-max-height'              => array ('style:footnote-max-height',           'props', true),
63        'writing-mode'                     => array ('style:writing-mode',                  'props', true),
64        'layout-grid-mode'                 => array ('style:layout-grid-mode',              'props', true),
65        'layout-grid-standard-mode'        => array ('style:layout-grid-standard-mode',     'props', true),
66        'layout-grid-base-height'          => array ('style:layout-grid-base-height',       'props', true),
67        'layout-grid-ruby-height'          => array ('style:layout-grid-ruby-height',       'props', true),
68        'layout-grid-lines'                => array ('style:layout-grid-lines',             'props', true),
69        'layout-grid-base-width'           => array ('style:layout-grid-base-width',        'props', true),
70        'layout-grid-color'                => array ('style:layout-grid-color',             'props', true),
71        'layout-grid-ruby-below'           => array ('style:layout-grid-ruby-below',        'props', true),
72        'layout-grid-print'                => array ('style:layout-grid-print',             'props', true),
73        'layout-grid-display'              => array ('style:layout-grid-display',           'props', true),
74        'layout-grid-snap-to'              => array ('style:layout-grid-snap-to',           'props', true),
75    );
76
77    static $bgi_fields = array(
78        // Fields belonging to "style:background-image"
79        // The content of element "style:background-image" will be saved as is
80        'repeat'                   => array ('style:repeat',                   'bgi', true),
81        'position'                 => array ('style:position',                 'bgi', true),
82        'filter-name'              => array ('style:filter-name',              'bgi', true),
83        'opacity'                  => array ('draw:opacity',                   'bgi', true),
84        'xlink-type'               => array ('xlink:type',                     'bgi', true),
85        'xlink-href'               => array ('xlink:href',                     'bgi', true),
86        'xlink-show'               => array ('xlink:show',                     'bgi', true),
87        'xlink-actuate'            => array ('xlink:actuate',                  'bgi', true),
88    );
89
90    static $columns_fields = array(
91        // Fields belonging to "style:columns"
92        // The content of element "style:columns" will be saved as is
93        'column-count'                   => array ('fo:column-count',          'columns', true),
94        'column-gap'                     => array ('fo:column-gap',            'columns', true),
95        'column-gap'                     => array ('fo:column-gap',            'columns', true),
96    );
97
98    static $footnote_fields = array(
99        // Fields belonging to "style:footnote-sep"
100        'ftsep-width'                    => array ('style:width',               'ftsep', true),
101        'ftsep-rel-width'                => array ('style:rel-width',           'ftsep', true),
102        'ftsep-color'                    => array ('style:color',               'ftsep', true),
103        'ftsep-line-style'               => array ('style:line-style',          'ftsep', true),
104        'ftsep-adjustment'               => array ('style:adjustment',          'ftsep', true),
105        'ftsep-distance-before-sep'      => array ('style:distance-before-sep', 'ftsep', true),
106        'ftsep-distance-after-sep'       => array ('style:distance-after-sep',  'ftsep', true),
107    );
108
109    protected $page_layout_style = array();
110    protected $layout_props = array();
111    protected $bgi_props = array();
112    protected $columns_props = array();
113    protected $footnote_props = array();
114
115    protected $content_bgi = NULL;
116    protected $content_columns = NULL;
117    protected $content_header = NULL;
118    protected $content_footer = NULL;
119
120    /**
121     * Get the element name for the ODT XML encoding of the style.
122     */
123    public function getElementName() {
124        return 'style:page-layout';
125    }
126
127    /**
128     * Set style properties by importing values from a properties array.
129     * Properties might be disabled by setting them in $disabled.
130     * The style must have been previously created.
131     *
132     * @param  $properties Properties to be imported
133     * @param  $disabled Properties to be ignored
134     */
135    public function importProperties($properties, $disabled) {
136        $this->importPropertiesInternal(self::$page_layout_fields, $properties, $disabled, $this->page_layout_style);
137        $this->importPropertiesInternal(self::$layout_props_fields, $properties, $disabled, $this->layout_props);
138        $this->importPropertiesInternal(self::$bgi_fields, $properties, $disabled, $this->bgi_props);
139        $this->importPropertiesInternal(self::$columns_fields, $properties, $disabled, $this->columns_props);
140        $this->importPropertiesInternal(self::$footnote_props, $properties, $disabled, $this->footnote_fields);
141    }
142
143    /**
144     * Check if a style is a common style.
145     *
146     * @return bool Is common style
147     */
148    public function mustBeCommonStyle() {
149        return false;
150    }
151
152    /**
153     * Set a property.
154     *
155     * @param $property The name of the property to set
156     * @param $value    New value to set
157     */
158    public function setProperty($property, $value) {
159        if (array_key_exists ($property, self::$page_layout_fields)) {
160            $this->setPropertyInternal
161                ($property, self::$page_layout_fields [$property][0], $value, self::$page_layout_fields [$property][1], $this->page_layout_style);
162            return;
163        }
164        if (array_key_exists ($property, self::$layout_props_fields)) {
165            $this->setPropertyInternal
166                ($property, self::$layout_props_fields [$property][0], $value, self::$layout_props_fields [$property][1], $this->layout_props);
167            return;
168        }
169        if (array_key_exists ($property, self::$bgi_fields)) {
170            $this->setPropertyInternal
171                ($property, self::$bgi_fields [$property][0], $value, self::$bgi_fields [$property][1], $this->bgi_props);
172            return;
173        }
174        if (array_key_exists ($property, self::$columns_fields)) {
175            $this->setPropertyInternal
176                ($property, self::$columns_fields [$property][0], $value, self::$columns_fields [$property][1], $this->columns_props);
177            return;
178        }
179        if (array_key_exists ($property, self::$footnote_fields)) {
180            $this->setPropertyInternal
181                ($property, self::$footnote_fields [$property][0], $value, self::$footnote_fields [$property][1], $this->footnote_props);
182            return;
183        }
184    }
185
186    /**
187     * Get the value of a property.
188     *
189     * @param  $property The property name
190     * @return string The current value of the property
191     */
192    public function getProperty($property) {
193        if (array_key_exists ($property, self::$page_layout_fields)) {
194            return $this->page_layout_style [$property]['value'];
195        }
196        if (array_key_exists ($property, self::$layout_props_fields)) {
197            return $this->layout_props [$property]['value'];
198        }
199        if (array_key_exists ($property, self::$bgi_fields)) {
200            return $this->bgi_props [$property]['value'];
201        }
202        if (array_key_exists ($property, self::$columns_fields)) {
203            return $this->columns_props [$property]['value'];
204        }
205        if (array_key_exists ($property, self::$footnote_fields)) {
206            return $this->footnote_props [$property]['value'];
207        }
208        return NULL;
209    }
210
211    /**
212     * Create new style by importing ODT style definition.
213     *
214     * @param  $xmlCode Style definition in ODT XML format
215     * @return ODTStyle New specific style
216     */
217    static public function importODTStyle($xmlCode) {
218        $style = new ODTPageLayoutStyle();
219
220        // Get attributes for element 'style:master-page'
221        $open = XMLUtil::getElementOpenTag('style:page-layout', $xmlCode);
222        if (!empty($open)) {
223            $style->importODTStyleInternal(self::$page_layout_fields, $open, $style->page_layout_style);
224
225            $childs = XMLUtil::getElementContent ('style:page-layout', $xmlCode);
226            if (!empty($childs)) {
227                // Get attributes for element 'style:page-layout-properties'
228                $open = XMLUtil::getElementOpenTag('style:page-layout-properties', $childs);
229                $style->content_header = XMLUtil::getElement ('style:header-style', $childs);
230                $style->content_footer = XMLUtil::getElement ('style:footer-style', $childs);
231                if (!empty($open)) {
232                    $style->importODTStyleInternal(self::$layout_props_fields, $open, $style->layout_props);
233
234                    $childs = XMLUtil::getElementContent ('style:page-layout-properties', $xmlCode);
235                    if (!empty($childs)) {
236                        // Get 'style:background-image'
237                        $open = XMLUtil::getElementOpenTag('style:background-image', $childs);
238                        if (!empty($open)) {
239                            $style->importODTStyleInternal(self::$bgi_fields, $open, $style->bgi_props);
240                            $style->content_bgi = XMLUtil::getElementContent ('style:background-image', $childs);
241                        }
242
243                        // Get 'style:columns'
244                        $open = XMLUtil::getElementOpenTag('style:columns', $childs);
245                        if (!empty($open)) {
246                            $style->importODTStyleInternal(self::$columns_fields, $open, $style->columns_props);
247                            $style->content_columns = XMLUtil::getElementContent ('style:columns', $childs);
248                        }
249
250                        // Get 'style:footnote-sep'
251                        $open = XMLUtil::getElementOpenTag('style:footnote-sep', $childs);
252                        if (!empty($open)) {
253                            $style->importODTStyleInternal(self::$footnote_fields, $open, $style->footnote_props);
254                        }
255                    }
256                }
257            }
258        }
259
260        return $style;
261    }
262
263    /**
264     * Encode current style values in a string and return it.
265     *
266     * @return string ODT XML encoded style
267     */
268    public function toString() {
269        $layout_style = '';
270        $layout = '';
271        $bgi = '';
272        $columns = '';
273        $footnote = '';
274
275        // Get page layout style ODT properties
276        foreach ($this->page_layout_style as $property => $items) {
277            $layout_style .= $items ['odt_property'].'="'.$items ['value'].'" ';
278        }
279
280        // Get page layout properties ODT properties
281        foreach ($this->layout_props as $property => $items) {
282            $layout .= $items ['odt_property'].'="'.$items ['value'].'" ';
283        }
284
285        // Get background-image ODT properties
286        foreach ($this->bgi_props as $property => $items) {
287            $bgi .= $items ['odt_property'].'="'.$items ['value'].'" ';
288        }
289
290        // Get columns ODT properties
291        foreach ($this->columns_props as $property => $items) {
292            $columns .= $items ['odt_property'].'="'.$items ['value'].'" ';
293        }
294
295        // Get footnote-sep ODT properties
296        foreach ($this->footnote_props as $property => $items) {
297            $footnote .= $items ['odt_property'].'="'.$items ['value'].'" ';
298        }
299
300        // Build style.
301        $style  = '<style:page-layout '.$layout_style.">\n";
302        if ( !empty($layout) || !empty($bgi) || !empty($columns) || !empty($footnote) ||
303             !empty($this->content_bgi) || !empty($this->content_columns) ) {
304            $style .= '<style:page-layout-properties '.$layout.">\n";
305
306            if ( !empty($bgi) || !empty($this->content_bgi) ) {
307                $style .= '<style:background-image '.$bgi.">\n";
308                $style .= $this->content_bgi;
309                $style .= '</style:background-image>'."\n";
310            }
311            if ( !empty($columns) || !empty($content_columns) ) {
312                $style .= '<style:columns '.$columns.">\n";
313                $style .= $this->content_columns;
314                $style .= '</style:columns>'."\n";
315            }
316            if ( !empty($footnote) ) {
317                $style .= '<style:footnote-sep '.$footnote."/>\n";
318            }
319
320            $style .= '</style:page-layout-properties>'."\n";
321        }
322
323        $style .= $this->content_header;
324        $style .= $this->content_footer;
325
326        $style .= '</style:page-layout'.">\n";
327        return $style;
328    }
329
330    /**
331     * This function creates a page layout style with the parameters given in $properies.
332     *
333     * The currently supported properties are:
334     * style-name, width, height, margin-top, margin-bottom, margin-right and margin-left.
335     * All properties except the style-name are expected to be numeric values.
336     * The function will add 'cm' itself, so do not add any units.
337     *
338     * The function returns the name of the new style or NULL if all relevant properties are empty.
339     *
340     * @author LarsDW223
341     *
342     * @param $properties
343     * @param null $disabled_props
344     * @return ODTUnknownStyle or NULL
345     */
346    public static function createPageLayoutStyle(array $properties, array $disabled_props = NULL) {
347        // Create style name (if not given).
348        $style_name = $properties ['style-name'];
349        if ( empty($style_name) ) {
350            $style_name = self::getNewStylename ('Page');
351            $properties ['style-name'] = $style_name;
352        }
353        $style = '<style:page-layout style:name="'.$style_name.'">
354                <style:page-layout-properties fo:page-width="'.$properties ['width'].'cm" fo:page-height="'.$properties ['height'].'cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="'.$properties ['margin-top'].'cm" fo:margin-bottom="'.$properties ['margin-bottom'].'cm" fo:margin-left="'.$properties ['margin-left'].'cm" fo:margin-right="'.$properties ['margin-right'].'cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm">
355                    <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.1cm" style:distance-after-sep="0.1cm" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
356                </style:page-layout-properties>
357                <style:header-style/>
358                <style:footer-style/>
359            </style:page-layout>';
360        return self::importODTStyle($style);
361    }
362}
363
364