1<?php 2/** 3 * ODTFrame: Frame handling. 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author LarsDW223 7 */ 8 9/** Include ODTDocument.php */ 10require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php'; 11 12/** 13 * ODTFrame: 14 * Class containing static code for handling frames. 15 * 16 * @package ODT\Frame 17 */ 18class ODTFrame 19{ 20 static $frameCount = 0; 21 static $fields = array('background-color' => 'fo:background-color', 22 'fill-color' => 'draw:fill-color', 23 'fill' => 'draw:fill', 24 'stroke-color' => 'svg:stroke-color', 25 'stroke' => 'draw:stroke', 26 'stroke-width' => 'svg:stroke-width', 27 'border' => 'fo:border', 28 'border-left' => 'fo:border-left', 29 'border-right' => 'fo:border-right', 30 'border-top' => 'fo:border-top', 31 'border-bottom' => 'fo:border-bottom', 32 'padding-left' => 'fo:padding-left', 33 'padding-right' => 'fo:padding-right', 34 'padding-top' => 'fo:padding-top', 35 'padding-bottom' => 'fo:padding-bottom', 36 'margin-left' => 'fo:margin-left', 37 'margin-right' => 'fo:margin-right', 38 'margin-top' => 'fo:margin-top', 39 'margin-bottom' => 'fo:margin-bottom', 40 'vertical-align' => 'draw:textarea-vertical-align', 41 'horizontal-align' => 'draw:textarea-horizontal-align', 42 'min-height' => 'fo:min-height', 43 'background-transparency' => 'style:background-transparency', 44 'textarea-horizontal-align' => 'draw:textarea-horizontal-align', 45 'run-through' => 'style:run-through', 46 'vertical-pos' => 'style:vertical-pos', 47 'vertical-rel' => 'style:vertical-rel', 48 'horizontal-pos' => 'style:horizontal-pos', 49 'horizontal-rel' => 'style:horizontal-rel', 50 'wrap' => 'style:wrap', 51 'number-wrapped-paragraphs' => 'style:number-wrapped-paragraphs', 52 'wrap-influence-on-position' => 'draw:wrap-influence-on-position' 53 ); 54 55 /** 56 * This function opens a textbox in a frame using CSS. 57 * 58 * The currently supported CSS properties are: 59 * background-color, color, padding, margin, display, border-radius, min-height. 60 * The background-image is simulated using a picture frame. 61 * FIXME: Find a way to successfuly use the background-image in the graphic style (see comments). 62 * 63 * The text box should be closed by calling 'closeTextBox()'. 64 * 65 * @param ODTInternalParams $params Commom params. 66 * @param string $element The element name, e.g. "div" 67 * @param string $attributes The attributes belonging o the element, e.g. 'class="example"' 68 */ 69 public static function openTextBoxUseCSS (ODTInternalParams $params, $element=NULL, $attributes=NULL) { 70 $frame = $params->document->state->getCurrentFrame(); 71 if (isset($frame)) { 72 // Do not open a nested frame as this will make the content ofthe nested frame disappear. 73 //return; 74 } 75 76 $properties = array(); 77 ODTUtility::openHTMLElement ($params, $properties, $element, $attributes); 78 $params->elementObj = $params->htmlStack->getCurrentElement(); 79 80 self::openTextBoxUseProperties ($params, $properties); 81 } 82 83 /** 84 * This function opens a textbox in a frame. 85 * 86 * The currently supported CSS properties are: 87 * background-color, color, padding, margin, display, border-radius, min-height. 88 * The background-image is simulated using a picture frame. 89 * FIXME: Find a way to successfuly use the background-image in the graphic style (see comments). 90 * 91 * The text box should be closed by calling 'closeTextBox()'. 92 * 93 * @param ODTInternalParams $params Commom params. 94 * @param array $properties Properties to use for creating the text box 95 * @param string $element The element name, e.g. "div" 96 * @param string $attributes The attributes belonging o the element, e.g. 'class="example"' 97 */ 98 public static function openTextBoxUseProperties (ODTInternalParams $params, $properties, $element=NULL, $attributes=NULL) { 99 // Encode frame 100 self::openFrameUseProperties ($params, $properties, $element, $attributes); 101 102 // Create text box 103 $box = new ODTElementTextBox(); 104 $box_attrs = ''; 105 // If required use round corners. 106 if ( !empty($properties ['border-radius']) ) 107 $box_attrs .= 'draw:corner-radius="'.$properties ['border-radius'].'"'; 108 $box->setAttributes($box_attrs); 109 $params->document->state->enter($box); 110 111 // Encode box 112 $params->content .= $box->getOpeningTag($params); 113 } 114 115 /** 116 * This function closes a textbox (previously opened with openTextBoxUseProperties()). 117 * 118 * @param ODTInternalParams $params Commom params. 119 */ 120 public static function closeTextBox (ODTInternalParams $params) { 121 // Close paragraph (if open) 122 $params->document->paragraphClose(); 123 // Close text box 124 $params->document->closeCurrentElement(); 125 // Close frame 126 self::closeFrame($params); 127 } 128 129 /** 130 * This function opens a multi column frame/text box according to the 131 * parameters in $properties. Call 'closeMultiColumnTextBox()' to 132 * close the text box. 133 * 134 * @param ODTInternalParams $params Commom params. 135 * @param array $properties Properties to use 136 * @see ODTUnknownStyle::createMultiColumnFrameStyle for information 137 * about supported $properties. 138 */ 139 public static function openMultiColumnTextBoxUseProperties (ODTInternalParams $params, $properties) { 140 if (!isset($element)) { 141 $element = 'div'; 142 } 143 144 // Create style name. 145 $style_obj = ODTUnknownStyle::createMultiColumnFrameStyle ($properties); 146 $params->document->addAutomaticStyle($style_obj); 147 $style_name = $style_obj->getProperty('style-name'); 148 149 $width_abs = $params->document->getAbsWidthMindMargins (100); 150 151 // Group the frame so that they are stacked one on each other. 152 $params->document->paragraphClose(); 153 $params->document->paragraphOpen(); 154 155 // Draw a frame with a text box in it. the text box will be left opened 156 // to grow with the content (requires fo:min-height in $style_name). 157 158 if (!isset($params->elementObj)) { 159 $properties = array(); 160 ODTUtility::openHTMLElement ($params, $properties, $element, $attributes); 161 } 162 163 // Create frame 164 $frame = new ODTElementFrame($style_name); 165 self::$frameCount++; 166 $frame_attrs = 'draw:name="Frame'.self::$frameCount.'" text:anchor-type="paragraph" svg:width="'.$width_abs.'cm" draw:z-index="0">'; 167 $frame->setAttributes($frame_attrs); 168 $params->document->state->enter($frame); 169 $frame->setHTMLElement ($element); 170 171 // Encode frame 172 $params->content .= $frame->getOpeningTag($params); 173 174 // Create text box 175 $box = new ODTElementTextBox(); 176 $box_attrs = 'fo:min-height="1pt"'; 177 $box->setAttributes($box_attrs); 178 $params->document->state->enter($box); 179 180 // Encode box 181 $params->content .= $box->getOpeningTag($params); 182 } 183 184 /** 185 * This function closes a multi column frame (previously opened with _odtOpenMultiColumnFrame). 186 * 187 * @param ODTInternalParams $params Commom params. 188 */ 189 public static function closeMultiColumnTextBox (ODTInternalParams $params) { 190 // Close paragraph (if open) 191 $params->document->paragraphClose(); 192 // Close text box 193 $params->document->closeCurrentElement(); 194 // Close frame 195 ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement()); 196 $params->document->closeCurrentElement(); 197 198 $params->document->paragraphClose(); 199 200 $params->document->div_z_index -= 5; 201 } 202 203 /** 204 * This function opens a textbox in a frame. 205 * 206 * The currently supported CSS properties are: 207 * background-color, color, padding, margin, display, border-radius, min-height. 208 * The background-image is simulated using a picture frame. 209 * FIXME: Find a way to successfuly use the background-image in the graphic style (see comments). 210 * 211 * The text box should be closed by calling 'closeTextBox()'. 212 * 213 * @param ODTInternalParams $params Commom params. 214 * @param array $properties Properties to use for creating the frame 215 * @param string $element The element name, e.g. "div" 216 * @param string $attributes The attributes belonging o the element, e.g. 'class="example"' 217 */ 218 public static function openFrameUseProperties (ODTInternalParams $params, $properties, $element=NULL, $attributes=NULL) { 219 $frame = $params->document->state->getCurrentFrame(); 220 if (isset($frame)) { 221 // Do not open a nested frame as this will make the content ofthe nested frame disappear. 222 //return; 223 } 224 if (!isset($element)) { 225 $element = 'div'; 226 } 227 $elementObj = $params->elementObj; 228 229 // If we are not in a paragraph then open one. 230 $inParagraph = $params->document->state->getInParagraph(); 231 if (!$inParagraph) { 232 $params->document->paragraphOpen(); 233 } 234 235 $position = $properties ['position']; 236 $picture = $properties ['background-image']; 237 $pic_positions = preg_split ('/\s/', $properties ['background-position']); 238 //$min_height = $properties ['min-height']; 239 $width = $properties ['width']; 240 241 $pic_link = ''; 242 $pic_width = ''; 243 $pic_height = ''; 244 if ( !empty ($picture) ) { 245 // If a picture/background-image is set in the CSS, than we insert it manually here. 246 // This is a workaround because ODT does not support the background-image attribute in a span. 247 $pic_link = $params->document->addFileAsPicture($picture); 248 list($pic_width, $pic_height) = ODTUtility::getImageSizeString($picture, NULL, NULL, true, $params->units); 249 } 250 251 if ( empty ($width) ) { 252 $width = '100%'; 253 } 254 if ( !empty($pic_positions [0]) ) { 255 $pic_positions [0] = $params->document->toPoints($pic_positions [0], 'x'); 256 } 257 //if ( empty($min_height) ) { 258 // $min_height = '1pt'; 259 //} 260 261 // Get anchor type 262 $anchor_type = 'paragraph'; 263 if (!empty($properties ['anchor-type'])) { 264 $anchor_type = $properties ['anchor-type']; 265 } 266 267 // Get X and Y position. 268 // X and Y position can be set using 'x' or 'left' and 'y' or 'top'. 269 $svgX = null; 270 $svgY = null; 271 if (!empty($properties ['x'])) { 272 $svgX = $properties ['x']; 273 } 274 if (!empty($properties ['left'])) { 275 $svgX = $properties ['left']; 276 } 277 if (!empty($properties ['y'])) { 278 $svgY = $properties ['y']; 279 } 280 if (!empty($properties ['top'])) { 281 $svgY = $properties ['top']; 282 } 283 284 // Adjust properties for CSS property 'position' if given 285 switch ($position) { 286 case 'absolute': 287 $anchor_type = 'page'; 288 break; 289 case 'relative': 290 $anchor_type = 'paragraph'; 291 break; 292 case 'static': 293 $anchor_type = 'paragraph'; 294 $svgX = '0cm'; 295 $svgY = '0cm'; 296 break; 297 } 298 299 // Add our styles. 300 $style_name = ODTStyle::getNewStylename('Frame'); 301 $style = '<style:style style:name="'.$style_name.'_text_frame" style:family="graphic" style:parent-style-name="Frame">'; 302 $style .= '<style:graphic-properties '; 303 304 foreach (self::$fields as $name => $odtName) { 305 if (!empty($properties [$name])) { 306 $style .= $odtName.'="'.$properties [$name].'" '; 307 } 308 } 309 $style .= '>'; 310 $style .= '</style:graphic-properties>'; 311 $style .= '</style:style>'; 312 313 // Add style to our document 314 // (as unknown style because style-family graphic is not supported) 315 $style_obj = ODTUnknownStyle::importODTStyle($style); 316 $params->document->addAutomaticStyle($style_obj); 317 318 // Draw a frame with a text box in it. the text box will be left opened 319 // to grow with the content (requires fo:min-height in $style_name). 320 if (!isset($elementObj)) { 321 $throwAway = array(); 322 ODTUtility::openHTMLElement ($params, $throwAway, $element, $attributes); 323 } 324 325 // Create frame 326 $frame = new ODTElementFrame($style_name.'_text_frame'); 327 self::$frameCount++; 328 /*$frame_attrs .= 'draw:name="Frame'.self::$frameCount.'" 329 text:anchor-type="'.$anchor_type.'" 330 svg:width="'.$width.'" svg:min-height="'.$min_height.'" 331 draw:z-index="'.($params->document->div_z_index + 0).'"';*/ 332 $frame_attrs .= 'draw:name="Frame'.self::$frameCount.'" 333 text:anchor-type="'.$anchor_type.'" 334 svg:width="'.$width.'" 335 draw:z-index="'.($params->document->div_z_index + 0).'"'; 336 if (isset($svgX)) { 337 $frame_attrs .= ' svg:x="'.$svgX.'"'; 338 } 339 if (isset($svgY)) { 340 $frame_attrs .= ' svg:y="'.$svgY.'"'; 341 } 342 if (!empty($properties ['min-height'])) { 343 $frame_attrs .= ' svg:min-height="'.$properties ['min-height'].'"'; 344 } 345 if (!empty($properties ['height'])) { 346 $frame_attrs .= ' svg:height="'.$properties ['height'].'"'; 347 } 348 349 $frame->setAttributes($frame_attrs); 350 $params->document->state->enter($frame); 351 $frame->setHTMLElement ($element); 352 353 // Encode frame 354 $params->content .= $frame->getOpeningTag($params); 355 356 $params->document->div_z_index += 1; 357 } 358 359 /** 360 * This function closes a textbox (previously opened with openTextBoxUseProperties()). 361 * 362 * @param ODTInternalParams $params Commom params. 363 */ 364 public static function closeFrame (ODTInternalParams $params) { 365 $frame = $params->document->state->getCurrentFrame(); 366 if (!isset($frame)) { 367 // ??? Error. Not table found. 368 return; 369 } 370 371 // Close paragraph (if open) 372 $params->document->paragraphClose(); 373 374 // Eventually adjust frame width. 375 $frame->adjustWidth ($params); 376 377 // Close frame 378 $element = $params->document->state->getHTMLElement(); 379 ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement()); 380 $params->document->closeCurrentElement(); 381 382 // Do not close the open paragraph here as it may lead to extra empty lines. 383 384 $params->document->div_z_index -= 1; 385 } 386} 387