1<?php
2/**
3 * ODTTextOutlineStyle: class for ODT text outline 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';
11require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTTextStyle.php';
12
13/**
14 * The ODTTextOutlineStyle class
15 */
16class ODTTextOutlineStyle extends ODTStyle
17{
18    static $outline_fields = array(
19        // Fields belonging to "text:outline-style"
20        'style-name'                         => array ('style:name',                              'style', false),
21
22        // Fields belonging to "text:outline-level-style"
23        'level'                              => array ('text:level',                              'level', true),
24        'text-style-name'                    => array ('text:style-name',                         'level', true),
25        'num-format'                         => array ('style:num-format',                        'level', true),
26        'num-letter-sync'                    => array ('style:num-letter-sync',                   'level', true),
27        'num-prefix'                         => array ('style:num-prefix',                        'level', true),
28        'num-suffix'                         => array ('style:num-suffix',                        'level', true),
29        'display-levels'                     => array ('text:display-levels',                     'level', true),
30        'start-value'                        => array ('text:start-value',                        'level', true),
31
32        // Fields belonging to "style-list-level-properties"
33        'text-align'                         => array ('fo:text-align',                           'level-list', true),
34        'text-space-before'                  => array ('text:space-before',                       'level-list', true),
35        'text-min-label-width'               => array ('text:min-label-width',                    'level-list', true),
36        'text-min-label-distance'            => array ('text:min-label-distance',                 'level-list', true),
37        'font-name'                          => array ('style:font-name',                         'level-list', true),
38        'width'                              => array ('fo:width',                                'level-list', true),
39        'height'                             => array ('fo:height',                               'level-list', true),
40        'vertical-rel'                       => array ('style:vertical-rel',                      'level-list', true),
41        'vertical-pos'                       => array ('style:vertical-pos',                      'level-list', true),
42        'list-level-position-and-space-mode' => array ('text:list-level-position-and-space-mode', 'level-list', true),
43
44        // Fields belonging to "style:list-level-label-alignment"
45        'label-followed-by'                  => array ('text:label-followed-by',                  'level-label', true),
46        'list-tab-stop-position'             => array ('text:list-tab-stop-position',             'level-label', true),
47        'text-indent'                        => array ('fo:text-indent',                          'level-label', true),
48        'margin-left'                        => array ('fo:margin-left',                          'level-label', true),
49    );
50    protected $outline_level_styles = array();
51
52    /**
53     * Get the element name for the ODT XML encoding of the style.
54     */
55    public function getElementName() {
56        return 'text:outline-style';
57    }
58
59    /**
60     * Set style properties by importing values from a properties array.
61     * Properties might be disabled by setting them in $disabled.
62     * The style must have been previously created.
63     *
64     * @param  $properties Properties to be imported
65     * @param  $disabled Properties to be ignored
66     */
67    public function importProperties($properties, $disabled=array()) {
68        $this->importPropertiesInternal(ODTTextStyle::getTextProperties (), $properties, $disabled);
69        $this->importPropertiesInternal(self::$outline_fields, $properties, $disabled);
70    }
71
72    /**
73     * Check if a style is a common style.
74     *
75     * @return bool Is common style
76     */
77    public function mustBeCommonStyle() {
78        return false;
79    }
80
81    /**
82     * Set a property.
83     *
84     * @param $property The name of the property to set
85     * @param $value    New value to set
86     */
87    public function setProperty($property, $value) {
88        $text_fields = ODTTextStyle::getTextProperties ();
89        if (array_key_exists ($property, $style_fields)) {
90            $this->setPropertyInternal
91                ($property, $text_fields [$property][0], $value, $text_fields [$property][1]);
92            return;
93        }
94        if (array_key_exists ($property, self::$outline_fields)) {
95            $this->setPropertyInternal
96                ($property, self::$outline_fields [$property][0], $value, self::$outline_fields [$property][1]);
97            return;
98        }
99    }
100
101    /**
102     * Create new style by importing ODT style definition.
103     *
104     * @param  $xmlCode Style definition in ODT XML format
105     * @return ODTStyle New specific style
106     */
107    static public function importODTStyle($xmlCode) {
108        $style = new ODTTextOutlineStyle();
109        $attrs = 0;
110
111        $open = XMLUtil::getElementOpenTag('text:outline-style', $xmlCode);
112        if (!empty($open)) {
113            // This properties are stored in the properties of ODTStyle
114            $attrs += $style->importODTStyleInternal(self::$outline_fields, $open);
115        }
116
117        $pos = 0;
118        $end = 0;
119        $max = strlen ($xmlCode);
120        $level = XMLUtil::getElement('text:outline-level-style', substr($xmlCode, $pos), $end);
121        $pos += $end;
122        $text_fields = ODTTextStyle::getTextProperties ();
123
124        $check = 0;
125        while (isset($level))
126        {
127            // We can have multiple level definitons with all the same properties.
128            // So we store this in our own array. The "text:level" is the array key.
129            if (!empty($level)) {
130                $properties = array();
131                $attrs += $style->importODTStyleInternal($text_fields, $level, $properties);
132                $attrs += $style->importODTStyleInternal(self::$outline_fields, $level, $properties);
133
134                // Assign properties array to our level array
135                $level_number = $style->getPropertyInternal('level', $properties);
136                $style->outline_level_styles [$level_number] = $properties;
137            }
138
139            // Get XML code for next level.
140            $level = XMLUtil::getElement('text:outline-level-style', substr($xmlCode, $pos), $end);
141            $pos += $end;
142            if ($pos >= $max) {
143                break;
144            }
145        }
146
147        // If style has no meaningfull content then throw it away
148        if ( $attrs == 0 ) {
149            return NULL;
150        }
151
152        return $style;
153    }
154
155    /**
156     * Encode current style values in a string and return it.
157     *
158     * @return string ODT XML encoded style
159     */
160    public function toString() {
161        $style = '';
162        $levels = '';
163
164        // The style properties are stored in the properties of ODTStyle
165        foreach ($this->properties as $property => $items) {
166            $style .= $items ['odt_property'].'="'.$items ['value'].'" ';
167        }
168
169        // The level properties are stored in our level properties
170        foreach ($this->outline_level_styles as $key => $properties) {
171            $level = '';
172            $level_list = '';
173            $level_label = '';
174            $text = '';
175            foreach ($properties as $property => $items) {
176                switch ($items ['section']) {
177                    case 'level':
178                        $level .= $items ['odt_property'].'="'.$items ['value'].'" ';
179                        break;
180                    case 'level-list':
181                        $level_list .= $items ['odt_property'].'="'.$items ['value'].'" ';
182                        break;
183                    case 'level-label':
184                        $level_label .= $items ['odt_property'].'="'.$items ['value'].'" ';
185                        break;
186                    case 'text':
187                        $text .= $items ['odt_property'].'="'.$items ['value'].'" ';
188                        break;
189                }
190            }
191            $levels .= '    <text:outline-level-style '.$level.">\n";
192            if (!empty($level_list)) {
193                if (empty($level_label)) {
194                    $levels .= '        <style:list-level-properties '.$level_list."/>\n";
195                } else {
196                    $levels .= '        <style:list-level-properties '.$level_list.">\n";
197                    $levels .= '            <style:list-level-label-alignment '.$level_label."/>\n";
198                    $levels .= "        </style:list-level-properties>\n";
199                }
200            }
201            if (!empty($text)) {
202                $levels .= '        <style:text-properties '.$text.'/>';
203            }
204            $levels .= "    </text:outline-level-style>\n";
205        }
206
207        // Build style.
208        $element = $this->getElementName();
209        $style  = '<'.$element.' '.$style.">\n";
210        if ( !empty($levels) ) {
211            $style .= $levels;
212        }
213        $style .= '</'.$element.">\n";
214        return $style;
215    }
216
217    /**
218     * Get the value of a property for text outline level $level.
219     *
220     * @param  $level      The text outline level (usually 1 to 10)
221     * @param  $property   The property name
222     * @return string      The current value of the property
223     */
224    public function getPropertyFromLevel($level, $property) {
225        return $this->getPropertyInternal($property, $this->outline_level_styles [$level]);
226    }
227
228    /**
229     * Set a property.
230     *
231     * @param $property The name of the property to set
232     * @param $value    New value to set
233     */
234    public function setPropertyForLevel($level, $property, $value) {
235        if (array_key_exists ($property, self::$outline_fields)) {
236            $this->setPropertyInternal
237                ($property, self::$outline_fields [$property][0], $value, self::$outline_fields [$property][1], $this->outline_level_styles [$level]);
238            return;
239        }
240    }
241}
242
243