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