1<?php 2/** 3 * ODTTextListStyle: class for ODT text list 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 ODTTextListStyle class 15 */ 16class ODTTextListStyle extends ODTStyle 17{ 18 static $list_fields = array( 19 // Fields belonging to "text:list-style" 20 'style-name' => array ('style:name', 'style', false), 21 'style-display-name' => array ('style:display-name', 'style', false), 22 'consecutive-numbering' => array ('text:consecutive-numbering', 'style', true), 23 ); 24 25 static $style_number_fields = array( 26 // Fields belonging to "text:list-level-style-number" 27 'level' => array ('text:level', 'style-attr', true), 28 'text-style-name' => array ('text:style-name', 'style-attr', true), 29 'num-format' => array ('style:num-format', 'style-attr', true), 30 'num-letter-sync' => array ('style:num-letter-sync', 'style-attr', true), 31 'num-prefix' => array ('style:num-prefix', 'style-attr', true), 32 'num-suffix' => array ('style:num-suffix', 'style-attr', true), 33 'display-levels' => array ('text:display-levels', 'style-attr', true), 34 'start-value' => array ('text:start-value', 'style-attr', true), 35 ); 36 37 static $style_bullet_fields = array( 38 // Fields belonging to "text:list-level-style-bullet" 39 'level' => array ('text:level', 'style-attr', true), 40 'text-style-name' => array ('text:style-name', 'style-attr', true), 41 'text-bullet-char' => array ('text:bullet-char', 'style-attr', true), 42 'num-prefix' => array ('style:num-prefix', 'style-attr', true), 43 'num-suffix' => array ('style:num-suffix', 'style-attr', true), 44 'text-bullet-relative-size' => array ('text:bullet-relative-size', 'style-attr', true), 45 ); 46 47 static $style_image_fields = array( 48 // Fields belonging to "text:list-level-style-image" 49 'level' => array ('text:level', 'style-attr', true), 50 'type' => array ('xlink:type', 'style-attr', true), 51 'href' => array ('xlink:href', 'style-attr', true), 52 'show' => array ('xlink:show', 'style-attr', true), 53 'actuate' => array ('xlink:actuate', 'style-attr', true), 54 'binary-data' => array ('office:binary-data', 'style-attr', true), 55 'base64Binary' => array ('base64Binary', 'style-attr', true), 56 ); 57 58 static $list_level_props_fields = array( 59 // Fields belonging to "style-list-level-properties" 60 'text-align' => array ('fo:text-align', 'level-list', true), 61 'text-space-before' => array ('text:space-before', 'level-list', true), 62 'text-min-label-width' => array ('text:min-label-width', 'level-list', true), 63 'text-min-label-distance' => array ('text:min-label-distance', 'level-list', true), 64 'font-name' => array ('style:font-name', 'level-list', true), 65 'width' => array ('fo:width', 'level-list', true), 66 'height' => array ('fo:height', 'level-list', true), 67 'vertical-rel' => array ('style:vertical-rel', 'level-list', true), 68 'vertical-pos' => array ('style:vertical-pos', 'level-list', true), 69 'list-level-position-and-space-mode' => array ('text:list-level-position-and-space-mode', 'level-list', true), 70 ); 71 72 static $label_align_fields = array( 73 // Fields belonging to "style:list-level-label-alignment" 74 'label-followed-by' => array ('text:label-followed-by', 'level-label', true), 75 'list-tab-stop-position' => array ('text:list-tab-stop-position', 'level-label', true), 76 'text-indent' => array ('fo:text-indent', 'level-label', true), 77 'margin-left' => array ('fo:margin-left', 'level-label', true), 78 ); 79 protected $list_level_styles = array(); 80 81 /** 82 * Get the element name for the ODT XML encoding of the style. 83 */ 84 public function getElementName() { 85 return 'text:list-style'; 86 } 87 88 /** 89 * Set style properties by importing values from a properties array. 90 * Properties might be disabled by setting them in $disabled. 91 * The style must have been previously created. 92 * 93 * @param $properties Properties to be imported 94 * @param $disabled Properties to be ignored 95 */ 96 public function importProperties($properties, $disabled=array()) { 97 $this->importPropertiesInternal(ODTTextStyle::getTextProperties (), $properties, $disabled); 98 $this->importPropertiesInternal(self::$list_fields, $properties, $disabled); 99 } 100 101 /** 102 * Check if a style is a common style. 103 * 104 * @return bool Is common style 105 */ 106 public function mustBeCommonStyle() { 107 return false; 108 } 109 110 /** 111 * Set a property. 112 * For a TextListStyle we can only set the style main properties here. 113 * All properties specific for a level need to be set using setPropertyForLevel(). 114 * 115 * @param $property The name of the property to set 116 * @param $value New value to set 117 */ 118 public function setProperty($property, $value) { 119 if (array_key_exists ($property, self::$list_fields)) { 120 $this->setPropertyInternal 121 ($property, self::$list_fields [$property][0], $value, self::$list_fields [$property][1]); 122 return; 123 } 124 } 125 126 /** 127 * Create new style by importing ODT style definition. 128 * 129 * @param $xmlCode Style definition in ODT XML format 130 * @return ODTStyle New specific style 131 */ 132 static public function importODTStyle($xmlCode) { 133 $style = new ODTTextListStyle(); 134 $attrs = 0; 135 136 $open = XMLUtil::getElementOpenTag('text:list-style', $xmlCode); 137 if (!empty($open)) { 138 // This properties are stored in the properties of ODTStyle 139 $attrs += $style->importODTStyleInternal(self::$list_fields, $open); 140 $content = XMLUtil::getElementContent('text:list-style', $xmlCode); 141 } 142 143 $pos = 0; 144 $end = 0; 145 $max = strlen ($content); 146 $text_fields = ODTTextStyle::getTextProperties (); 147 while ($pos < $max) 148 { 149 // Get XML code for next level. 150 $level = XMLUtil::getNextElement($element, substr($content, $pos), $end); 151 $level_content = XMLUtil::getNextElementContent($element, $level, $ignore); 152 if (!empty($level)) { 153 $list_style_properties = array(); 154 $list_level_properties = array(); 155 $label_properties = array(); 156 $text_properties = array(); 157 $properties = array(); 158 switch ($element) { 159 case 'text:list-level-style-number': 160 $attrs += $style->importODTStyleInternal(self::$style_number_fields, $level, $list_style_properties); 161 $list_level_style = 'number'; 162 break; 163 case 'text:list-level-style-bullet': 164 $attrs += $style->importODTStyleInternal(self::$style_bullet_fields, $level, $list_style_properties); 165 $list_level_style = 'bullet'; 166 break; 167 case 'text:list-level-style-image': 168 $attrs += $style->importODTStyleInternal(self::$style_image_fields, $level, $list_style_properties); 169 $list_level_style = 'image'; 170 break; 171 } 172 173 $temp_content = XMLUtil::getElement('style:text-properties', $level_content); 174 $attrs += $style->importODTStyleInternal($text_fields, $temp_content, $text_properties); 175 $temp_content = XMLUtil::getElementOpenTag('style:list-level-properties', $level_content); 176 $attrs += $style->importODTStyleInternal(self::$list_level_props_fields, $temp_content, $list_level_properties); 177 $temp_content = XMLUtil::getElement('style:list-level-label-alignment', $level_content); 178 $attrs += $style->importODTStyleInternal(self::$label_align_fields, $temp_content, $label_properties); 179 180 // Assign properties array to our level array 181 $level_number = $style->getPropertyInternal('level', $list_style_properties); 182 $properties ['list-style'] = $list_style_properties; 183 $properties ['list-level'] = $list_level_properties; 184 $properties ['label'] = $label_properties; 185 $properties ['text'] = $text_properties; 186 $style->list_level_styles [$level_number] = $properties; 187 188 // Set special property 'list-level-style' to remember element to encode 189 // on call to toString()! 190 $style->setPropertyForLevel($level_number, 'list-level-style', $list_level_style); 191 } 192 193 $pos += $end; 194 } 195 196 // If style has no meaningfull content then throw it away 197 if ( $attrs == 0 ) { 198 return NULL; 199 } 200 201 return $style; 202 } 203 204 /** 205 * Encode current style values in a string and return it. 206 * 207 * @return string ODT XML encoded style 208 */ 209 public function toString() { 210 $style = ''; 211 $levels = ''; 212 213 // The style properties are stored in the properties of ODTStyle 214 foreach ($this->properties as $property => $items) { 215 $style .= $items ['odt_property'].'="'.$items ['value'].'" '; 216 } 217 218 // The level properties are stored in our level properties 219 $level_number = 0; 220 foreach ($this->list_level_styles as $key => $properties) { 221 $level_number++; 222 $element = $this->getPropertyFromLevel($level_number, 'list-level-style'); 223 switch ($element) { 224 case 'number': 225 $fields = self::$style_number_fields; 226 break; 227 case 'bullet': 228 $fields = self::$style_bullet_fields; 229 break; 230 case 'image': 231 $fields = self::$style_image_fields; 232 break; 233 } 234 $element = 'text:list-level-style-'.$element; 235 236 $style_attr = ''; 237 foreach ($this->list_level_styles [$level_number]['list-style'] as $property => $items) { 238 // Only add fields/properties which are allowed for the specific list-level-style 239 if ($property != 'list-level-style' && array_key_exists ($property, $fields)) { 240 $style_attr .= $items ['odt_property'].'="'.$items ['value'].'" '; 241 } 242 } 243 $level_list = ''; 244 foreach ($this->list_level_styles [$level_number]['list-level'] as $property => $items) { 245 $level_list .= $items ['odt_property'].'="'.$items ['value'].'" '; 246 } 247 $level_label = ''; 248 foreach ($this->list_level_styles [$level_number]['label'] as $property => $items) { 249 $level_label .= $items ['odt_property'].'="'.$items ['value'].'" '; 250 } 251 $text = ''; 252 foreach ($this->list_level_styles [$level_number]['text'] as $property => $items) { 253 $text .= $items ['odt_property'].'="'.$items ['value'].'" '; 254 } 255 256 $levels .= ' <'.$element.' '.$style_attr.">\n"; 257 if (!empty($level_list)) { 258 if (empty($level_label)) { 259 $levels .= ' <style:list-level-properties '.$level_list."/>\n"; 260 } else { 261 $levels .= ' <style:list-level-properties '.$level_list.">\n"; 262 $levels .= ' <style:list-level-label-alignment '.$level_label."/>\n"; 263 $levels .= " </style:list-level-properties>\n"; 264 } 265 } 266 if (!empty($text)) { 267 $levels .= ' <style:text-properties '.$text.'/>'."\n"; 268 } 269 $levels .= " </".$element.">\n"; 270 } 271 272 // Build style. 273 $element = $this->getElementName(); 274 $style = '<'.$element.' '.$style.">\n"; 275 if ( !empty($levels) ) { 276 $style .= $levels; 277 } 278 $style .= '</'.$element.">\n"; 279 return $style; 280 } 281 282 /** 283 * Get the value of a property for text outline level $level. 284 * 285 * @param $level The text outline level (usually 1 to 10) 286 * @param $property The property name 287 * @return string The current value of the property 288 */ 289 public function getPropertyFromLevel($level, $property) { 290 if ($property == 'list-level-style') { 291 // Property 'list-level-style' is a special property just to remember 292 // which element needs to be encoded on a call to toString(). 293 // It may not be included in the output of toString()!!! 294 return $this->getPropertyInternal('list-level-style', $this->list_level_styles [$level]['list-style']); 295 } 296 $text_fields = ODTTextStyle::getTextProperties (); 297 if (array_key_exists ($property, $text_fields)) { 298 return $this->getPropertyInternal($property, $this->list_level_styles [$level]['text']); 299 } 300 $element = $this->getPropertyInternal('list-level-style', $this->list_level_styles [$level]['list-style']); 301 switch ($element) { 302 case 'number': 303 $fields = self::$style_number_fields; 304 break; 305 case 'bullet': 306 $fields = self::$style_bullet_fields; 307 break; 308 case 'image': 309 $fields = self::$style_image_fields; 310 break; 311 } 312 if (array_key_exists ($property, $fields)) { 313 return $this->getPropertyInternal($property, $this->list_level_styles [$level]['list-style']); 314 } 315 if (array_key_exists ($property, self::$list_level_props_fields)) { 316 return $this->getPropertyInternal($property, $this->list_level_styles [$level]['list-level']); 317 } 318 if (array_key_exists ($property, self::$label_align_fields)) { 319 return $this->getPropertyInternal($property, $this->list_level_styles [$level]['label']); 320 } 321 } 322 323 /** 324 * Set a property for a specific level. 325 * 326 * @param $level The level for which to set the property (1 to 10) 327 * @param $property The name of the property to set 328 * @param $value New value to set 329 */ 330 public function setPropertyForLevel($level, $property, $value) { 331 if ($property == 'list-level-style') { 332 // Property 'list-level-style' is a special property just to remember 333 // which element needs to be encoded on a call to toString(). 334 // It may not be included in the output of toString()!!! 335 $this->setPropertyInternal 336 ($property, 'list-level-style', $value, 'list-level-style', $this->list_level_styles [$level]['list-style']); 337 } else { 338 // First check fields/properties common to each list-level-style 339 $text_fields = ODTTextStyle::getTextProperties (); 340 if (array_key_exists ($property, $text_fields)) { 341 $this->setPropertyInternal 342 ($property, $text_fields [$property][0], $value, $text_fields [$property][1], $this->list_level_styles [$level]['text']); 343 return; 344 } 345 if (array_key_exists ($property, self::$list_level_props_fields)) { 346 $this->setPropertyInternal 347 ($property, self::$list_level_props_fields [$property][0], $value, self::$list_level_props_fields [$property][1], $this->list_level_styles [$level]['list-level']); 348 return; 349 } 350 if (array_key_exists ($property, self::$label_align_fields)) { 351 $this->setPropertyInternal 352 ($property, self::$label_align_fields [$property][0], $value, self::$label_align_fields [$property][1], $this->list_level_styles [$level]['label']); 353 return; 354 } 355 356 // Now check fields specific to the list-level-style. 357 $element = $this->getPropertyFromLevel ($level, 'list-level-style'); 358 switch ($element) { 359 case 'number': 360 $fields = self::$style_number_fields; 361 break; 362 case 'bullet': 363 $fields = self::$style_bullet_fields; 364 break; 365 case 'image': 366 $fields = self::$style_image_fields; 367 break; 368 } 369 if (array_key_exists ($property, $fields)) { 370 $this->setPropertyInternal 371 ($property, $fields [$property][0], $value, $fields [$property][1], $this->list_level_styles [$level]['list-style']); 372 } 373 } 374 } 375} 376 377