xref: /webtrees/app/Report/ReportHtmlTextbox.php (revision b6db7c1f82484c632c75d5225ce767d398ddc27f)
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                } elseif ($element instanceof ReportBaseFootnote) {
60                    // Check if the Footnote has been set with it’s link number
61                    $renderer->checkFootnote($element);
62                    // Save first the last element if any
63                    if (!empty($lastelement)) {
64                        $newelements[] = $lastelement;
65                        $lastelement   = [];
66                    }
67                    // Save the Footnote with it’s link number as key for sorting later
68                    $footnote_element[$element->num] = $element;
69                } elseif (!($element instanceof ReportBaseFootnote) || trim($element->getValue()) != '') {
70                    // Do not keep empty footnotes
71                    if (!empty($footnote_element)) {
72                        ksort($footnote_element);
73                        foreach ($footnote_element as $links) {
74                            $newelements[] = $links;
75                        }
76                        $footnote_element = [];
77                    }
78                    if (!empty($lastelement)) {
79                        $newelements[] = $lastelement;
80                        $lastelement   = [];
81                    }
82                    $newelements[] = $element;
83                }
84            } else {
85                if (!empty($lastelement)) {
86                    $newelements[] = $lastelement;
87                    $lastelement   = [];
88                }
89                if (!empty($footnote_element)) {
90                    ksort($footnote_element);
91                    foreach ($footnote_element as $links) {
92                        $newelements[] = $links;
93                    }
94                    $footnote_element = [];
95                }
96                $newelements[] = $element;
97            }
98        }
99        if (!empty($lastelement)) {
100            $newelements[] = $lastelement;
101        }
102        if (!empty($footnote_element)) {
103            ksort($footnote_element);
104            foreach ($footnote_element as $links) {
105                $newelements[] = $links;
106            }
107        }
108        $this->elements = $newelements;
109        unset($footnote_element, $lastelement, $links, $newelements);
110
111        $cP = 0; // Class Padding
112
113        // Used with line breaks and cell height calculation within this box only
114        $renderer->largestFontHeight = 0;
115
116        // Current position
117        if ($this->left == '.') {
118            $cX = $renderer->getX();
119        } else {
120            $cX = $this->left;
121            $renderer->setX($cX);
122        }
123        // Current position (top)
124        if ($this->top == '.') {
125            $this->top = $renderer->getY();
126        } else {
127            $renderer->setY($this->top);
128        }
129
130        // Check the width if set to page wide OR set by xml to larger then page wide
131        if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) {
132            $this->width = $renderer->getRemainingWidth();
133        }
134        // Setup the CellPadding
135        if ($this->padding) {
136            $cP = $renderer->cPadding;
137        }
138
139        // For padding, we have to use less wrap width
140        $cW = $this->width - ($cP * 2);
141
142        //-- calculate the text box height
143        // Number of lines, will be converted to height
144        $cHT = 0;
145        // Element height (exept text)
146        $eH = 0;
147        // Footnote height (in points)
148        $fH = 0;
149        $w  = 0;
150        //-- $lw is an array
151        // 0 => last line width
152        // 1 => 1 if text was wrapped, 0 if text did not wrap
153        // 2 => number of LF
154        $lw = [];
155        // Element counter
156        $cE = count($this->elements);
157        for ($i = 0; $i < $cE; $i++) {
158            if (is_object($this->elements[$i])) {
159                $ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW);
160                if ($ew == $cW) {
161                    $w = 0;
162                }
163                $lw = $this->elements[$i]->getWidth($renderer);
164                // Text is already gets the # LF
165                $cHT += $lw[2];
166                if ($lw[1] == 1) {
167                    $w = $lw[0];
168                } elseif ($lw[1] == 2) {
169                    $w = 0;
170                } else {
171                    $w += $lw[0];
172                }
173                if ($w > $cW) {
174                    $w = $lw[0];
175                }
176                // For anything else but text (images), get the height
177                $eH += $this->elements[$i]->getHeight($renderer);
178            } else {
179                $fH += abs($renderer->getFootnotesHeight($cW));
180            }
181        }
182        // Add up what’s the final height
183        $cH = $this->height;
184        // If any element exist
185        if ($cE > 0) {
186            // Check if this is text or some other element, like images
187            if ($eH == 0) {
188                // Number of LF but at least one line
189                $cHT = ($cHT + 1) * $renderer->cellHeightRatio;
190                // Calculate the cell hight with the largest font size used
191                $cHT = $cHT * $renderer->largestFontHeight;
192                if ($cH < $cHT) {
193                    $cH = $cHT;
194                }
195            } else {
196                // This is any other element
197                if ($cH < $eH) {
198                    $cH = $eH;
199                }
200                // Add Footnote height to the rest of the height
201                $cH += $fH;
202            }
203        }
204
205        unset($lw, $cHT, $fH, $w);
206
207        // Finaly, check the last cells height
208        if ($cH < $renderer->lastCellHeight) {
209            $cH = $renderer->lastCellHeight;
210        }
211        // Update max Y incase of a pagebreak
212        // We don't want to over write any images or other stuff
213        $renderer->addMaxY($this->top + $cH);
214
215        // Start to print HTML
216        echo '<div style="position:absolute;top:', $this->top, 'pt;';
217        // LTR (left) or RTL (right)
218        echo $renderer->alignRTL, ':', $cX, 'pt;';
219        // Background color
220        if ($this->fill) {
221            if (!empty($this->bgcolor)) {
222                echo ' background-color:', $this->bgcolor, ';';
223            }
224        }
225        // Print padding only when it’s set
226        if ($this->padding) {
227            // Use Cell around padding to support RTL also
228            echo 'padding:', $cP, 'pt;';
229        }
230        // Border setup
231        if ($this->border) {
232            echo ' border:solid black 1pt;';
233            echo 'width:', ($this->width - 1 - ($cP * 2)), 'pt;height:', $cH - 1, 'pt;';
234        } else {
235            echo 'width:', ($this->width - ($cP * 2)), 'pt;height:', $cH, 'pt;';
236        }
237        echo '">';
238
239        // Do a little "margin" trick before print
240        // to get the correct current position => "."
241        $cXT = $renderer->getX();
242        $cYT = $renderer->getY();
243        $renderer->setXy(0, 0);
244
245        // Print the text elements
246        foreach ($this->elements as $element) {
247            if (is_object($element)) {
248                $element->render($renderer, $cX, false);
249            } elseif (is_string($element) && $element == 'footnotetexts') {
250                $renderer->footnotes();
251            } elseif (is_string($element) && $element == 'addpage') {
252                $renderer->addPage();
253            }
254        }
255        echo "</div>\n";
256
257        // Reset "margins"
258        $renderer->setXy($cXT, $cYT);
259        // This will be mostly used to trick the multiple images last height
260        if ($this->reseth) {
261            $cH = 0;
262        }
263        // New line and some clean up
264        if (!$this->newline) {
265            $renderer->setXy($cX + $this->width, $this->top);
266            $renderer->lastCellHeight = $cH;
267        } else {
268            $renderer->setXy(0, $this->top + $cH + ($cP * 2));
269            $renderer->lastCellHeight = 0;
270        }
271    }
272}
273