1<?php
2/**
3 * ODT Paragraph handling.
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     LarsDW223
7 * @package    ODT\Paragraph
8 */
9
10/** Include ODTDocument */
11require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
12
13/**
14 * ODTParagraph:
15 * Class containing static code for handling paragraphs.
16 *
17 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
18 */
19class ODTParagraph
20{
21    /**
22     * Open a paragraph
23     *
24     * @param     ODTInternalParams $params     Commom params.
25     * @param     string|null       $styleName  The style to use.
26     * @param     string            $element    The element name, e.g. "div"
27     * @param     string            $attributes The attributes belonging o the element, e.g. 'class="example"'
28     */
29    public static function paragraphOpen(ODTInternalParams $params, $styleName=NULL, $element=NULL, $attributes=NULL){
30        if ($element == NULL) {
31            $element = 'p';
32        }
33        if ( empty($styleName) ) {
34            $styleName = $params->document->getStyleName('body');
35        }
36
37        $list = NULL;
38        $listItem = $params->document->state->getCurrentListItem();
39        if ($listItem != NULL) {
40            // We are in a list item. Is this the list start?
41            $list = $listItem->getList();
42            if ($list != NULL) {
43                // Get list count and Flag if this is the first paragraph in the list
44                $listCount = $params->document->state->countClass('list');
45                $isFirst = $list->getListFirstParagraph();
46                $list->setListFirstParagraph(false);
47
48                // Create a style for putting a top margin for this first paragraph of the list
49                // (if not done yet, the name must be unique!)
50                if ($listCount == 1 && $isFirst) {
51                    // If we have a standard list content paragraph style then we use the
52                    // corresponding always existing first and last default styles
53                    if ($styleName == $params->document->getStyleName('list content')) {
54                        $styleName = $params->document->getStyleName('list first');
55                    } else if ($styleName == $params->document->getStyleName('numbering content')) {
56                        $styleName = $params->document->getStyleName('numbering first');
57                    } else {
58                        // No standard list paragraph style.
59                        // Has a clone for the first paragraph's style already been created...
60                        $styleNameFirst = 'FirstListParagraph_'.$styleName;
61                        if (!$params->document->styleExists($styleNameFirst)) {
62
63                            // ...no, create style as copy of style 'list first' or 'numbering first'
64                            if ($list->getStyleName() == $params->document->getStyleName('list')) {
65                                $styleFirstTemplate = $params->document->getStyleByAlias('list first');
66                            } else {
67                                $styleFirstTemplate = $params->document->getStyleByAlias('numbering first');
68                            }
69                            if ($styleFirstTemplate != NULL) {
70                                $styleBody = $params->document->getStyle($styleName);
71                                $styleDisplayName = 'First '.$styleBody->getProperty('style-display-name');
72                                $styleObj = clone $styleFirstTemplate;
73                                if ($styleObj != NULL) {
74                                    $styleObj->setProperty('style-name', $styleNameFirst);
75                                    $styleObj->setProperty('style-parent', $styleName);
76                                    $styleObj->setProperty('style-display-name', $styleDisplayName);
77                                    $bottom = $styleFirstTemplate->getProperty('margin-bottom');
78                                    if ($bottom === NULL) {
79                                        $styleObj->setProperty('margin-bottom', $styleBody->getProperty('margin-bottom'));
80                                    }
81                                    $params->document->addStyle($styleObj);
82                                    $styleName = $styleNameFirst;
83                                }
84                            }
85                        } else {
86                            // ...yes, just use the name
87                            $styleName = $styleNameFirst;
88                        }
89                    }
90                }
91            }
92        }
93
94        // Opening a paragraph inside another paragraph is illegal
95        $inParagraph = $params->document->state->getInParagraph();
96        if (!$inParagraph) {
97            if ( $params->document->pageFormatChangeIsPending() ) {
98                $pageStyle = $params->document->doPageFormatChange($styleName);
99                if ( $pageStyle != NULL ) {
100                    $styleName = $pageStyle;
101                    // Delete pagebreak, the format change will also introduce a pagebreak.
102                    $params->document->setPagebreakPending(false);
103                }
104            }
105            if ( $params->document->pagebreakIsPending() ) {
106                $styleName = $params->document->createPagebreakStyle ($styleName);
107                $params->document->setPagebreakPending(false);
108            }
109
110            // If we are in a list remember paragraph position
111            if ($list != NULL) {
112                $list->setListLastParagraphPosition(strlen($params->content));
113            }
114
115            if ($params->elementObj == NULL) {
116                $properties = array();
117                ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
118            }
119
120            $paragraph = new ODTElementParagraph($styleName);
121            $params->document->state->enter($paragraph);
122            $params->content .= $paragraph->getOpeningTag();
123            $paragraph->setHTMLElement ($element);
124        }
125    }
126
127    /**
128     * Close a paragraph.
129     *
130     * @param     ODTInternalParams $params     Commom params.
131     */
132    public static function paragraphClose(ODTInternalParams $params){
133        $paragraph = $params->document->state->getCurrentParagraph();
134        if ($paragraph != NULL) {
135            ODTUtility::closeHTMLElement ($params, $paragraph->getHTMLElement());
136            $params->content .= $paragraph->getClosingTag();
137            $params->document->state->leave();
138        }
139    }
140
141    /**
142     * This function opens a new paragraph using the style as set in the imported CSS $import.
143     * So, the function requires the helper class 'helper_plugin_odt_cssimport'.
144     * The CSS style is selected by the element type 'p' and the specified classes in $classes.
145     * The property 'background-image' is emulated by inserting an image manually in the paragraph.
146     * If the url from the CSS should be converted to a local path, then the caller can specify a $baseURL.
147     * The full path will then be $baseURL/background-image.
148     *
149     * This function calls _odtParagraphOpenUseProperties. See the function description for supported properties.
150     *
151     * The span should be closed by calling '_odtParagraphClose'.
152     *
153     * @author    LarsDW223
154     * @param     ODTInternalParams $params     Commom params.
155     * @param     string            $element    The element name, e.g. "div"
156     * @param     string            $attributes The attributes belonging o the element, e.g. 'class="example"'
157     */
158    public static function paragraphOpenUseCSS(ODTInternalParams $params, $element=NULL, $attributes=NULL){
159        $inParagraph = $params->document->state->getInParagraph();
160        if ($inParagraph) {
161            return;
162        }
163
164        $properties = array();
165        ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
166        $params->elementObj = $params->htmlStack->getCurrentElement();
167
168        self::paragraphOpenUseProperties($params, $properties);
169    }
170
171    /**
172     * This function opens a new paragraph using the style as set in the assoziative array $properties.
173     * The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
174     * The property 'background-image' is emulated by inserting an image manually in the paragraph.
175     *
176     * The currently supported properties are:
177     * background-color, color, font-style, font-weight, font-size, border, font-family, font-variant, letter-spacing,
178     * vertical-align, line-height, background-image (emulated)
179     *
180     * The paragraph must be closed by calling 'p_close'.
181     *
182     * @author LarsDW223
183     *
184     * @param     ODTInternalParams $params     Commom params.
185     * @param     array             $properties Properties to use.
186     */
187    public static function paragraphOpenUseProperties(ODTInternalParams $params, $properties){
188        $inParagraph = $params->document->state->getInParagraph();
189        if ($inParagraph) {
190            return;
191        }
192        $disabled = array ();
193
194        $in_paragraph = $params->document->state->getInParagraph();
195        if ($in_paragraph) {
196            // opening a paragraph inside another paragraph is illegal
197            return;
198        }
199
200        $odt_bg = $properties ['background-color'];
201        $picture = $properties ['background-image'];
202
203        if ( !empty ($picture) ) {
204            // If a picture/background-image is set, than we insert it manually here.
205            // This is a workaround because ODT background-image works different than in CSS.
206
207            // Define graphic style for picture
208            $style_name = ODTStyle::getNewStylename('span_graphic');
209            $image_style = '<style:style style:name="'.$style_name.'" style:family="graphic" style:parent-style-name="'.$params->document->getStyleName('graphics').'"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:background-color="'.$odt_bg.'" style:flow-with-text="true"></style:graphic-properties></style:style>';
210
211            // Add style and image to our document
212            // (as unknown style because style-family graphic is not supported)
213            $style_obj = ODTUnknownStyle::importODTStyle($image_style);
214            $params->document->addAutomaticStyle($style_obj);
215            ODTImage::addImage ($params, $picture, NULL, NULL, NULL, NULL, $style_name);
216        }
217
218        // Create the style for the paragraph.
219        //$disabled ['background-image'] = 1;
220        //FIXME: pass $disabled
221        $style_obj = ODTParagraphStyle::createParagraphStyle ($properties);
222        $params->document->addAutomaticStyle($style_obj);
223        $style_name = $style_obj->getProperty('style-name');
224
225        // Open a paragraph
226        self::paragraphOpen($params, $style_name);
227    }
228}
229