1<?php
2/**
3 * ODTStyleStyle: class for ODT style styles.
4 * (Elements style:style and style:default-style)
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author LarsDW223
8 */
9
10require_once DOKU_PLUGIN.'odt/ODT/styles/ODTStyle.php';
11//require_once 'ODTTextStyle.php';
12//require_once 'ODTParagraphStyle.php';
13//require_once 'ODTTableStyle.php';
14//require_once 'ODTTableRowStyle.php';
15//require_once 'ODTTableColumnStyle.php';
16//require_once 'ODTTableCellStyle.php';
17//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTParagraphStyle.php';
18//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableStyle.php';
19//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableRowStyle.php';
20//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableCellStyle.php';
21
22/**
23 * The ODTStyleStyle class
24 */
25abstract class ODTStyleStyle extends ODTStyle
26{
27    // Style properties/attributes common to each
28    // style:style and style:default-style element
29    static $style_fields = array(
30        'style-name'                       => array ('style:name',                         'style', false),
31        'style-display-name'               => array ('style:display-name',                 'style', false),
32        'style-parent'                     => array ('style:parent-style-name',            'style', false),
33        'style-class'                      => array ('style:class',                        'style', true),
34        'style-family'                     => array ('style:family',                       'style', true),
35        'style-next'                       => array ('style:next-style-name',              'style', true),
36        'style-list-level'                 => array ('style:list-level',                   'style', true),
37        'style-list-style-name'            => array ('style:list-style-name',              'style', true),
38        'style-master-page-name'           => array ('style:master-page-name',             'style', true),
39        'style-auto-update'                => array ('style:auto-update',                  'style', true),
40        'style-data-style-name'            => array ('style:data-style-name',              'style', true),
41        'style-percentage-data-style-name' => array ('style:percentage-data-style-name',   'style', true),
42        'style-default-outline-level'      => array ('style:default-outline-level',        'style', true),
43        );
44    static $get_family_callbacks = NULL;
45    static $import_odt_callbacks = NULL;
46    protected $is_default = false;
47
48    /**
49     * Constructor.
50     */
51    public function __construct() {
52        if (!isset(self::$get_family_callbacks))
53            self::$get_family_callbacks = array();
54        if (!isset(self::$import_odt_callbacks))
55            self::$import_odt_callbacks = array();
56    }
57
58    static public function register ($classname) {
59        self::$get_family_callbacks [] = array($classname, 'getFamily');
60        self::$import_odt_callbacks [] = array($classname, 'importODTStyle');
61    }
62
63    /**
64     * Get the element name for the ODT XML encoding of the style.
65     *
66     * @param  $properties Properties to be imported
67     * @param  $disabled Properties to be ignored
68     */
69    public function getElementName() {
70        if ($this->isDefault() == true) {
71            return 'style:default-style';
72        }
73        return 'style:style';
74    }
75
76    /**
77     * Mark style as default style or not.
78     *
79     * @param  $is_default
80     */
81    public function setDefault($is_default) {
82        $this->is_default = $is_default;
83    }
84
85    /**
86     * Is this style a default style?
87     *
88     * @return boolean Is this a default style?
89     */
90    public function isDefault() {
91        return $this->is_default;
92    }
93
94    /**
95     * Encode current style values in a string and return it.
96     *
97     * @return string ODT XML encoded style
98     */
99    public function toString() {
100        //FIXME: Handling for background-image-section
101        $style = '';
102        $text = '';
103        $paragraph = '';
104        $table = '';
105        $table_column = '';
106        $table_row = '';
107        $table_cell = '';
108        $tab_stop = '';
109        $image = '';
110        foreach ($this->properties as $property => $items) {
111            switch ($items ['section']) {
112                case 'style':
113                    $style .= $items ['odt_property'].'="'.$items ['value'].'" ';
114                    break;
115                case 'text':
116                    $text .= $items ['odt_property'].'="'.$items ['value'].'" ';
117                    break;
118                case 'paragraph':
119                    $paragraph .= $items ['odt_property'].'="'.$items ['value'].'" ';
120                    break;
121                case 'table':
122                    $table .= $items ['odt_property'].'="'.$items ['value'].'" ';
123                    break;
124                case 'table-column':
125                    $table_column .= $items ['odt_property'].'="'.$items ['value'].'" ';
126                    break;
127                case 'table-row':
128                    $table_row .= $items ['odt_property'].'="'.$items ['value'].'" ';
129                    break;
130                case 'table-cell':
131                    $table_cell .= $items ['odt_property'].'="'.$items ['value'].'" ';
132                    break;
133                case 'tab-stop':
134                    $tab_stop .= $items ['odt_property'].'="'.$items ['value'].'" ';
135                    break;
136                case 'table-cell-background-image':
137                    $image .= $items ['odt_property'].'="'.$items ['value'].'" ';
138                    break;
139            }
140        }
141
142        // Build style.
143        $element = $this->getElementName();
144        $style  = '<'.$element.' '.$style.'>'."\n";
145        if ( !empty($paragraph) ) {
146            if ( empty($tab_stop) ) {
147                $style .= '    <style:paragraph-properties '.$paragraph.'/>'."\n";
148            } else {
149                $style .= '    <style:paragraph-properties '.$paragraph.'>'."\n";
150                $style .= '        <style:tab-stops><style:tab-stop '.$tab_stop.'/></style:tab-stops>'."\n";
151                $style .= '    </style:paragraph-properties>'."\n";
152            }
153        }
154        if ( !empty($text) ) {
155            $style .= '    <style:text-properties '.$text.'/>'."\n";
156        }
157        if ( !empty($table) ) {
158            $style .= '    <style:table-properties '.$table.'/>'."\n";
159        }
160        if ( !empty($table_column) ) {
161            $style .= '    <style:table-column-properties '.$table_column.'/>'."\n";
162        }
163        if ( !empty($table_row) ) {
164            $style .= '    <style:table-row-properties '.$table_row.'/>'."\n";
165        }
166        if ( !empty($table_cell) ) {
167            if (empty($image)) {
168                $style .= '    <style:table-cell-properties '.$table_cell.'/>'."\n";
169            } else {
170                $style .= '    <style:table-cell-properties '.$table_cell.'>'."\n";
171                $style .='         <style:background-image '.$image.'/>'."\n";
172                $style .= '    </style:table-cell-properties>';
173            }
174        }
175        $style .= '</'.$element.'>'."\n";
176        return $style;
177    }
178
179    /**
180     * Create new style by importing ODT style definition.
181     *
182     * @param  $xmlCode Style definition in ODT XML format
183     * @return ODTStyle New specific style
184     */
185    static public function importODTStyle($xmlCode) {
186        $matches = array();
187        if (preg_match ('/style:family="[^"]+"/', $xmlCode, $matches) !== 1) {
188            return NULL;
189        }
190        $family = substr ($matches [0], strlen('style:family='));
191        $family = trim ($family, '"<>');
192
193        for ($index = 0 ; $index < count(self::$get_family_callbacks) ; $index++ ) {
194            $curr_family = call_user_func(self::$get_family_callbacks [$index]);
195            if ($curr_family == $family) {
196                return call_user_func(self::$import_odt_callbacks [$index], $xmlCode);
197            }
198        }
199
200        // Unknown/not implemented style family.
201        // Return NULL, in this case ODTStyle will create a generic unknown style.
202        return NULL;
203    }
204
205    /**
206     * Set style properties by importing values from a properties array.
207     * Properties might be disabled by setting them in $disabled.
208     * The style must have been previously created. Only those properties
209     * will be accepted that are mentioned in the fields array.
210     *
211     * @param  $style      ODTStyle object for storing the properties
212     * @param  $fields     Properties accepted by the object/class
213     * @param  $properties Properties to be imported
214     * @param  $disabled   Properties to be ignored
215     */
216    protected function importPropertiesInternal(array $fields, $properties, $disabled, &$dest=NULL) {
217        parent::importPropertiesInternal($fields, $properties, $disabled, $dest);
218    }
219
220    /**
221     * The function deletes all properties that do not belong to the styles section,
222     * e.g. text properties or paragraph properties.
223     */
224    public function clearLayoutProperties() {
225        foreach ($this->properties as $property => $items) {
226            switch ($items ['section']) {
227                case 'style':
228                    // Keep it.
229                    break;
230                default:
231                    // Delete everything that does not belong to the styles section.
232                    $this->properties [$property] = NULL;
233                    unset ($this->properties [$property]);
234                    break;
235            }
236        }
237    }
238
239    static public function getStyleProperties () {
240        return self::$style_fields;
241    }
242}
243