xref: /webtrees/app/Report/ReportHtmlTextbox.php (revision 43e2aec9e526d1a242c3e80ff940736aec157724)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2018 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16namespace Fisharebest\Webtrees\Report;
17
18/**
19 * Class ReportHtmlTextbox
20 */
21class ReportHtmlTextbox extends ReportBaseTextbox
22{
23    /**
24     * Render the elements.
25     *
26     * @param ReportHtml $renderer
27     */
28    public function render($renderer)
29    {
30        // checkFootnote
31        $newelements      = [];
32        $lastelement      = [];
33        $footnote_element = [];
34        // Element counter
35        $cE = count($this->elements);
36        //-- collapse duplicate elements
37        for ($i = 0; $i < $cE; $i++) {
38            $element = $this->elements[$i];
39            if (is_object($element)) {
40                if ($element instanceof ReportBaseText) {
41                    if (!empty($footnote_element)) {
42                        ksort($footnote_element);
43                        foreach ($footnote_element as $links) {
44                            $newelements[] = $links;
45                        }
46                        $footnote_element = [];
47                    }
48                    if (empty($lastelement)) {
49                        $lastelement = $element;
50                    } else {
51                        // Checking if the Text has the same style
52                        if ($element->getStyleName() == $lastelement->getStyleName()) {
53                            $lastelement->addText(str_replace("\n", '<br>', $element->getValue()));
54                        } elseif (!empty($lastelement)) {
55                            $newelements[] = $lastelement;
56                            $lastelement   = $element;
57                        }
58                    }
59                } // Collect the Footnote links
60                elseif ($element instanceof ReportBaseFootnote) {
61                    // Check if the Footnote has been set with it’s link number
62                    $renderer->checkFootnote($element);
63                    // Save first the last element if any
64                    if (!empty($lastelement)) {
65                        $newelements[] = $lastelement;
66                        $lastelement   = [];
67                    }
68                    // Save the Footnote with it’s link number as key for sorting later
69                    $footnote_element[$element->num] = $element;
70                } //-- do not keep empty footnotes
71                elseif (!($element instanceof ReportBaseFootnote) || trim($element->getValue()) != '') {
72                    if (!empty($footnote_element)) {
73                        ksort($footnote_element);
74                        foreach ($footnote_element as $links) {
75                            $newelements[] = $links;
76                        }
77                        $footnote_element = [];
78                    }
79                    if (!empty($lastelement)) {
80                        $newelements[] = $lastelement;
81                        $lastelement   = [];
82                    }
83                    $newelements[] = $element;
84                }
85            } else {
86                if (!empty($lastelement)) {
87                    $newelements[] = $lastelement;
88                    $lastelement   = [];
89                }
90                if (!empty($footnote_element)) {
91                    ksort($footnote_element);
92                    foreach ($footnote_element as $links) {
93                        $newelements[] = $links;
94                    }
95                    $footnote_element = [];
96                }
97                $newelements[] = $element;
98            }
99        }
100        if (!empty($lastelement)) {
101            $newelements[] = $lastelement;
102        }
103        if (!empty($footnote_element)) {
104            ksort($footnote_element);
105            foreach ($footnote_element as $links) {
106                $newelements[] = $links;
107            }
108        }
109        $this->elements = $newelements;
110        unset($footnote_element, $lastelement, $links, $newelements);
111
112        $cP = 0; // Class Padding
113
114        // Used with line breaks and cell height calculation within this box only
115        $renderer->largestFontHeight = 0;
116
117        // Current position
118        if ($this->left == '.') {
119            $cX = $renderer->getX();
120        } else {
121            $cX = $this->left;
122            $renderer->setX($cX);
123        }
124        // Current position (top)
125        if ($this->top == '.') {
126            $this->top = $renderer->getY();
127        } else {
128            $renderer->setY($this->top);
129        }
130
131        // Check the width if set to page wide OR set by xml to larger then page wide
132        if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) {
133            $this->width = $renderer->getRemainingWidth();
134        }
135        // Setup the CellPadding
136        if ($this->padding) {
137            $cP = $renderer->cPadding;
138        }
139
140        // For padding, we have to use less wrap width
141        $cW = $this->width - ($cP * 2);
142
143        //-- calculate the text box height
144        // Number of lines, will be converted to height
145        $cHT = 0;
146        // Element height (exept text)
147        $eH = 0;
148        // Footnote height (in points)
149        $fH = 0;
150        $w  = 0;
151        //-- $lw is an array
152        // 0 => last line width
153        // 1 => 1 if text was wrapped, 0 if text did not wrap
154        // 2 => number of LF
155        $lw = [];
156        // Element counter
157        $cE = count($this->elements);
158        for ($i = 0; $i < $cE; $i++) {
159            if (is_object($this->elements[$i])) {
160                $ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW);
161                if ($ew == $cW) {
162                    $w = 0;
163                }
164                $lw = $this->elements[$i]->getWidth($renderer);
165                // Text is already gets the # LF
166                $cHT += $lw[2];
167                if ($lw[1] == 1) {
168                    $w = $lw[0];
169                } elseif ($lw[1] == 2) {
170                    $w = 0;
171                } else {
172                    $w += $lw[0];
173                }
174                if ($w > $cW) {
175                    $w = $lw[0];
176                }
177                // For anything else but text (images), get the height
178                $eH += $this->elements[$i]->getHeight($renderer);
179            } else {
180                $fH += abs($renderer->getFootnotesHeight($cW));
181            }
182        }
183        // Add up what’s the final height
184        $cH = $this->height;
185        // If any element exist
186        if ($cE > 0) {
187            // Check if this is text or some other element, like images
188            if ($eH == 0) {
189                // Number of LF but at least one line
190                $cHT = ($cHT + 1) * $renderer->cellHeightRatio;
191                // Calculate the cell hight with the largest font size used
192                $cHT = $cHT * $renderer->largestFontHeight;
193                if ($cH < $cHT) {
194                    $cH = $cHT;
195                }
196            } // This is any other element
197            else {
198                if ($cH < $eH) {
199                    $cH = $eH;
200                }
201                // Add Footnote height to the rest of the height
202                $cH += $fH;
203            }
204        }
205
206        unset($lw, $cHT, $fH, $w);
207
208        // Finaly, check the last cells height
209        if ($cH < $renderer->lastCellHeight) {
210            $cH = $renderer->lastCellHeight;
211        }
212        // Update max Y incase of a pagebreak
213        // We don't want to over write any images or other stuff
214        $renderer->addMaxY($this->top + $cH);
215
216        // Start to print HTML
217        echo '<div style="position:absolute;top:', $this->top, 'pt;';
218        // LTR (left) or RTL (right)
219        echo $renderer->alignRTL, ':', $cX, 'pt;';
220        // Background color
221        if ($this->fill) {
222            if (!empty($this->bgcolor)) {
223                echo ' background-color:', $this->bgcolor, ';';
224            }
225        }
226        // Print padding only when it’s set
227        if ($this->padding) {
228            // Use Cell around padding to support RTL also
229            echo 'padding:', $cP, 'pt;';
230        }
231        // Border setup
232        if ($this->border) {
233            echo ' border:solid black 1pt;';
234            echo 'width:', ($this->width - 1 - ($cP * 2)), 'pt;height:', $cH - 1, 'pt;';
235        } else {
236            echo 'width:', ($this->width - ($cP * 2)), 'pt;height:', $cH, 'pt;';
237        }
238        echo '">';
239
240        // Do a little "margin" trick before print
241        // to get the correct current position => "."
242        $cXT = $renderer->getX();
243        $cYT = $renderer->getY();
244        $renderer->setXy(0, 0);
245
246        // Print the text elements
247        foreach ($this->elements as $element) {
248            if (is_object($element)) {
249                $element->render($renderer, $cX, false);
250            } elseif (is_string($element) && $element == 'footnotetexts') {
251                $renderer->footnotes();
252            } elseif (is_string($element) && $element == 'addpage') {
253                $renderer->addPage();
254            }
255        }
256        echo "</div>\n";
257
258        // Reset "margins"
259        $renderer->setXy($cXT, $cYT);
260        // This will be mostly used to trick the multiple images last height
261        if ($this->reseth) {
262            $cH = 0;
263        }
264        // New line and some clean up
265        if (!$this->newline) {
266            $renderer->setXy($cX + $this->width, $this->top);
267            $renderer->lastCellHeight = $cH;
268        } else {
269            $renderer->setXy(0, $this->top + $cH + ($cP * 2));
270            $renderer->lastCellHeight = 0;
271        }
272    }
273}
274