1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Worksheet;
4
5use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
7
8/**
9 * <code>
10 * Paper size taken from Office Open XML Part 4 - Markup Language Reference, page 1988:.
11 *
12 * 1 = Letter paper (8.5 in. by 11 in.)
13 * 2 = Letter small paper (8.5 in. by 11 in.)
14 * 3 = Tabloid paper (11 in. by 17 in.)
15 * 4 = Ledger paper (17 in. by 11 in.)
16 * 5 = Legal paper (8.5 in. by 14 in.)
17 * 6 = Statement paper (5.5 in. by 8.5 in.)
18 * 7 = Executive paper (7.25 in. by 10.5 in.)
19 * 8 = A3 paper (297 mm by 420 mm)
20 * 9 = A4 paper (210 mm by 297 mm)
21 * 10 = A4 small paper (210 mm by 297 mm)
22 * 11 = A5 paper (148 mm by 210 mm)
23 * 12 = B4 paper (250 mm by 353 mm)
24 * 13 = B5 paper (176 mm by 250 mm)
25 * 14 = Folio paper (8.5 in. by 13 in.)
26 * 15 = Quarto paper (215 mm by 275 mm)
27 * 16 = Standard paper (10 in. by 14 in.)
28 * 17 = Standard paper (11 in. by 17 in.)
29 * 18 = Note paper (8.5 in. by 11 in.)
30 * 19 = #9 envelope (3.875 in. by 8.875 in.)
31 * 20 = #10 envelope (4.125 in. by 9.5 in.)
32 * 21 = #11 envelope (4.5 in. by 10.375 in.)
33 * 22 = #12 envelope (4.75 in. by 11 in.)
34 * 23 = #14 envelope (5 in. by 11.5 in.)
35 * 24 = C paper (17 in. by 22 in.)
36 * 25 = D paper (22 in. by 34 in.)
37 * 26 = E paper (34 in. by 44 in.)
38 * 27 = DL envelope (110 mm by 220 mm)
39 * 28 = C5 envelope (162 mm by 229 mm)
40 * 29 = C3 envelope (324 mm by 458 mm)
41 * 30 = C4 envelope (229 mm by 324 mm)
42 * 31 = C6 envelope (114 mm by 162 mm)
43 * 32 = C65 envelope (114 mm by 229 mm)
44 * 33 = B4 envelope (250 mm by 353 mm)
45 * 34 = B5 envelope (176 mm by 250 mm)
46 * 35 = B6 envelope (176 mm by 125 mm)
47 * 36 = Italy envelope (110 mm by 230 mm)
48 * 37 = Monarch envelope (3.875 in. by 7.5 in.).
49 * 38 = 6 3/4 envelope (3.625 in. by 6.5 in.)
50 * 39 = US standard fanfold (14.875 in. by 11 in.)
51 * 40 = German standard fanfold (8.5 in. by 12 in.)
52 * 41 = German legal fanfold (8.5 in. by 13 in.)
53 * 42 = ISO B4 (250 mm by 353 mm)
54 * 43 = Japanese double postcard (200 mm by 148 mm)
55 * 44 = Standard paper (9 in. by 11 in.)
56 * 45 = Standard paper (10 in. by 11 in.)
57 * 46 = Standard paper (15 in. by 11 in.)
58 * 47 = Invite envelope (220 mm by 220 mm)
59 * 50 = Letter extra paper (9.275 in. by 12 in.)
60 * 51 = Legal extra paper (9.275 in. by 15 in.)
61 * 52 = Tabloid extra paper (11.69 in. by 18 in.)
62 * 53 = A4 extra paper (236 mm by 322 mm)
63 * 54 = Letter transverse paper (8.275 in. by 11 in.)
64 * 55 = A4 transverse paper (210 mm by 297 mm)
65 * 56 = Letter extra transverse paper (9.275 in. by 12 in.)
66 * 57 = SuperA/SuperA/A4 paper (227 mm by 356 mm)
67 * 58 = SuperB/SuperB/A3 paper (305 mm by 487 mm)
68 * 59 = Letter plus paper (8.5 in. by 12.69 in.)
69 * 60 = A4 plus paper (210 mm by 330 mm)
70 * 61 = A5 transverse paper (148 mm by 210 mm)
71 * 62 = JIS B5 transverse paper (182 mm by 257 mm)
72 * 63 = A3 extra paper (322 mm by 445 mm)
73 * 64 = A5 extra paper (174 mm by 235 mm)
74 * 65 = ISO B5 extra paper (201 mm by 276 mm)
75 * 66 = A2 paper (420 mm by 594 mm)
76 * 67 = A3 transverse paper (297 mm by 420 mm)
77 * 68 = A3 extra transverse paper (322 mm by 445 mm)
78 * </code>
79 *
80 * @category   PhpSpreadsheet
81 *
82 * @copyright  Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
83 */
84class PageSetup
85{
86    // Paper size
87    const PAPERSIZE_LETTER = 1;
88    const PAPERSIZE_LETTER_SMALL = 2;
89    const PAPERSIZE_TABLOID = 3;
90    const PAPERSIZE_LEDGER = 4;
91    const PAPERSIZE_LEGAL = 5;
92    const PAPERSIZE_STATEMENT = 6;
93    const PAPERSIZE_EXECUTIVE = 7;
94    const PAPERSIZE_A3 = 8;
95    const PAPERSIZE_A4 = 9;
96    const PAPERSIZE_A4_SMALL = 10;
97    const PAPERSIZE_A5 = 11;
98    const PAPERSIZE_B4 = 12;
99    const PAPERSIZE_B5 = 13;
100    const PAPERSIZE_FOLIO = 14;
101    const PAPERSIZE_QUARTO = 15;
102    const PAPERSIZE_STANDARD_1 = 16;
103    const PAPERSIZE_STANDARD_2 = 17;
104    const PAPERSIZE_NOTE = 18;
105    const PAPERSIZE_NO9_ENVELOPE = 19;
106    const PAPERSIZE_NO10_ENVELOPE = 20;
107    const PAPERSIZE_NO11_ENVELOPE = 21;
108    const PAPERSIZE_NO12_ENVELOPE = 22;
109    const PAPERSIZE_NO14_ENVELOPE = 23;
110    const PAPERSIZE_C = 24;
111    const PAPERSIZE_D = 25;
112    const PAPERSIZE_E = 26;
113    const PAPERSIZE_DL_ENVELOPE = 27;
114    const PAPERSIZE_C5_ENVELOPE = 28;
115    const PAPERSIZE_C3_ENVELOPE = 29;
116    const PAPERSIZE_C4_ENVELOPE = 30;
117    const PAPERSIZE_C6_ENVELOPE = 31;
118    const PAPERSIZE_C65_ENVELOPE = 32;
119    const PAPERSIZE_B4_ENVELOPE = 33;
120    const PAPERSIZE_B5_ENVELOPE = 34;
121    const PAPERSIZE_B6_ENVELOPE = 35;
122    const PAPERSIZE_ITALY_ENVELOPE = 36;
123    const PAPERSIZE_MONARCH_ENVELOPE = 37;
124    const PAPERSIZE_6_3_4_ENVELOPE = 38;
125    const PAPERSIZE_US_STANDARD_FANFOLD = 39;
126    const PAPERSIZE_GERMAN_STANDARD_FANFOLD = 40;
127    const PAPERSIZE_GERMAN_LEGAL_FANFOLD = 41;
128    const PAPERSIZE_ISO_B4 = 42;
129    const PAPERSIZE_JAPANESE_DOUBLE_POSTCARD = 43;
130    const PAPERSIZE_STANDARD_PAPER_1 = 44;
131    const PAPERSIZE_STANDARD_PAPER_2 = 45;
132    const PAPERSIZE_STANDARD_PAPER_3 = 46;
133    const PAPERSIZE_INVITE_ENVELOPE = 47;
134    const PAPERSIZE_LETTER_EXTRA_PAPER = 48;
135    const PAPERSIZE_LEGAL_EXTRA_PAPER = 49;
136    const PAPERSIZE_TABLOID_EXTRA_PAPER = 50;
137    const PAPERSIZE_A4_EXTRA_PAPER = 51;
138    const PAPERSIZE_LETTER_TRANSVERSE_PAPER = 52;
139    const PAPERSIZE_A4_TRANSVERSE_PAPER = 53;
140    const PAPERSIZE_LETTER_EXTRA_TRANSVERSE_PAPER = 54;
141    const PAPERSIZE_SUPERA_SUPERA_A4_PAPER = 55;
142    const PAPERSIZE_SUPERB_SUPERB_A3_PAPER = 56;
143    const PAPERSIZE_LETTER_PLUS_PAPER = 57;
144    const PAPERSIZE_A4_PLUS_PAPER = 58;
145    const PAPERSIZE_A5_TRANSVERSE_PAPER = 59;
146    const PAPERSIZE_JIS_B5_TRANSVERSE_PAPER = 60;
147    const PAPERSIZE_A3_EXTRA_PAPER = 61;
148    const PAPERSIZE_A5_EXTRA_PAPER = 62;
149    const PAPERSIZE_ISO_B5_EXTRA_PAPER = 63;
150    const PAPERSIZE_A2_PAPER = 64;
151    const PAPERSIZE_A3_TRANSVERSE_PAPER = 65;
152    const PAPERSIZE_A3_EXTRA_TRANSVERSE_PAPER = 66;
153
154    // Page orientation
155    const ORIENTATION_DEFAULT = 'default';
156    const ORIENTATION_LANDSCAPE = 'landscape';
157    const ORIENTATION_PORTRAIT = 'portrait';
158
159    // Print Range Set Method
160    const SETPRINTRANGE_OVERWRITE = 'O';
161    const SETPRINTRANGE_INSERT = 'I';
162
163    /**
164     * Paper size.
165     *
166     * @var int
167     */
168    private $paperSize = self::PAPERSIZE_LETTER;
169
170    /**
171     * Orientation.
172     *
173     * @var string
174     */
175    private $orientation = self::ORIENTATION_DEFAULT;
176
177    /**
178     * Scale (Print Scale).
179     *
180     * Print scaling. Valid values range from 10 to 400
181     * This setting is overridden when fitToWidth and/or fitToHeight are in use
182     *
183     * @var null|int
184     */
185    private $scale = 100;
186
187    /**
188     * Fit To Page
189     * Whether scale or fitToWith / fitToHeight applies.
190     *
191     * @var bool
192     */
193    private $fitToPage = false;
194
195    /**
196     * Fit To Height
197     * Number of vertical pages to fit on.
198     *
199     * @var null|int
200     */
201    private $fitToHeight = 1;
202
203    /**
204     * Fit To Width
205     * Number of horizontal pages to fit on.
206     *
207     * @var null|int
208     */
209    private $fitToWidth = 1;
210
211    /**
212     * Columns to repeat at left.
213     *
214     * @var array Containing start column and end column, empty array if option unset
215     */
216    private $columnsToRepeatAtLeft = ['', ''];
217
218    /**
219     * Rows to repeat at top.
220     *
221     * @var array Containing start row number and end row number, empty array if option unset
222     */
223    private $rowsToRepeatAtTop = [0, 0];
224
225    /**
226     * Center page horizontally.
227     *
228     * @var bool
229     */
230    private $horizontalCentered = false;
231
232    /**
233     * Center page vertically.
234     *
235     * @var bool
236     */
237    private $verticalCentered = false;
238
239    /**
240     * Print area.
241     *
242     * @var string
243     */
244    private $printArea;
245
246    /**
247     * First page number.
248     *
249     * @var int
250     */
251    private $firstPageNumber;
252
253    /**
254     * Create a new PageSetup.
255     */
256    public function __construct()
257    {
258    }
259
260    /**
261     * Get Paper Size.
262     *
263     * @return int
264     */
265    public function getPaperSize()
266    {
267        return $this->paperSize;
268    }
269
270    /**
271     * Set Paper Size.
272     *
273     * @param int $pValue see self::PAPERSIZE_*
274     *
275     * @return $this
276     */
277    public function setPaperSize($pValue)
278    {
279        $this->paperSize = $pValue;
280
281        return $this;
282    }
283
284    /**
285     * Get Orientation.
286     *
287     * @return string
288     */
289    public function getOrientation()
290    {
291        return $this->orientation;
292    }
293
294    /**
295     * Set Orientation.
296     *
297     * @param string $pValue see self::ORIENTATION_*
298     *
299     * @return $this
300     */
301    public function setOrientation($pValue)
302    {
303        $this->orientation = $pValue;
304
305        return $this;
306    }
307
308    /**
309     * Get Scale.
310     *
311     * @return null|int
312     */
313    public function getScale()
314    {
315        return $this->scale;
316    }
317
318    /**
319     * Set Scale.
320     * Print scaling. Valid values range from 10 to 400
321     * This setting is overridden when fitToWidth and/or fitToHeight are in use.
322     *
323     * @param null|int $pValue
324     * @param bool $pUpdate Update fitToPage so scaling applies rather than fitToHeight / fitToWidth
325     *
326     * @throws PhpSpreadsheetException
327     *
328     * @return $this
329     */
330    public function setScale($pValue, $pUpdate = true)
331    {
332        // Microsoft Office Excel 2007 only allows setting a scale between 10 and 400 via the user interface,
333        // but it is apparently still able to handle any scale >= 0, where 0 results in 100
334        if (($pValue >= 0) || $pValue === null) {
335            $this->scale = $pValue;
336            if ($pUpdate) {
337                $this->fitToPage = false;
338            }
339        } else {
340            throw new PhpSpreadsheetException('Scale must not be negative');
341        }
342
343        return $this;
344    }
345
346    /**
347     * Get Fit To Page.
348     *
349     * @return bool
350     */
351    public function getFitToPage()
352    {
353        return $this->fitToPage;
354    }
355
356    /**
357     * Set Fit To Page.
358     *
359     * @param bool $pValue
360     *
361     * @return $this
362     */
363    public function setFitToPage($pValue)
364    {
365        $this->fitToPage = $pValue;
366
367        return $this;
368    }
369
370    /**
371     * Get Fit To Height.
372     *
373     * @return null|int
374     */
375    public function getFitToHeight()
376    {
377        return $this->fitToHeight;
378    }
379
380    /**
381     * Set Fit To Height.
382     *
383     * @param null|int $pValue
384     * @param bool $pUpdate Update fitToPage so it applies rather than scaling
385     *
386     * @return $this
387     */
388    public function setFitToHeight($pValue, $pUpdate = true)
389    {
390        $this->fitToHeight = $pValue;
391        if ($pUpdate) {
392            $this->fitToPage = true;
393        }
394
395        return $this;
396    }
397
398    /**
399     * Get Fit To Width.
400     *
401     * @return null|int
402     */
403    public function getFitToWidth()
404    {
405        return $this->fitToWidth;
406    }
407
408    /**
409     * Set Fit To Width.
410     *
411     * @param null|int $pValue
412     * @param bool $pUpdate Update fitToPage so it applies rather than scaling
413     *
414     * @return $this
415     */
416    public function setFitToWidth($pValue, $pUpdate = true)
417    {
418        $this->fitToWidth = $pValue;
419        if ($pUpdate) {
420            $this->fitToPage = true;
421        }
422
423        return $this;
424    }
425
426    /**
427     * Is Columns to repeat at left set?
428     *
429     * @return bool
430     */
431    public function isColumnsToRepeatAtLeftSet()
432    {
433        if (is_array($this->columnsToRepeatAtLeft)) {
434            if ($this->columnsToRepeatAtLeft[0] != '' && $this->columnsToRepeatAtLeft[1] != '') {
435                return true;
436            }
437        }
438
439        return false;
440    }
441
442    /**
443     * Get Columns to repeat at left.
444     *
445     * @return array Containing start column and end column, empty array if option unset
446     */
447    public function getColumnsToRepeatAtLeft()
448    {
449        return $this->columnsToRepeatAtLeft;
450    }
451
452    /**
453     * Set Columns to repeat at left.
454     *
455     * @param array $pValue Containing start column and end column, empty array if option unset
456     *
457     * @return $this
458     */
459    public function setColumnsToRepeatAtLeft(array $pValue)
460    {
461        $this->columnsToRepeatAtLeft = $pValue;
462
463        return $this;
464    }
465
466    /**
467     * Set Columns to repeat at left by start and end.
468     *
469     * @param string $pStart eg: 'A'
470     * @param string $pEnd eg: 'B'
471     *
472     * @return $this
473     */
474    public function setColumnsToRepeatAtLeftByStartAndEnd($pStart, $pEnd)
475    {
476        $this->columnsToRepeatAtLeft = [$pStart, $pEnd];
477
478        return $this;
479    }
480
481    /**
482     * Is Rows to repeat at top set?
483     *
484     * @return bool
485     */
486    public function isRowsToRepeatAtTopSet()
487    {
488        if (is_array($this->rowsToRepeatAtTop)) {
489            if ($this->rowsToRepeatAtTop[0] != 0 && $this->rowsToRepeatAtTop[1] != 0) {
490                return true;
491            }
492        }
493
494        return false;
495    }
496
497    /**
498     * Get Rows to repeat at top.
499     *
500     * @return array Containing start column and end column, empty array if option unset
501     */
502    public function getRowsToRepeatAtTop()
503    {
504        return $this->rowsToRepeatAtTop;
505    }
506
507    /**
508     * Set Rows to repeat at top.
509     *
510     * @param array $pValue Containing start column and end column, empty array if option unset
511     *
512     * @return $this
513     */
514    public function setRowsToRepeatAtTop(array $pValue)
515    {
516        $this->rowsToRepeatAtTop = $pValue;
517
518        return $this;
519    }
520
521    /**
522     * Set Rows to repeat at top by start and end.
523     *
524     * @param int $pStart eg: 1
525     * @param int $pEnd eg: 1
526     *
527     * @return $this
528     */
529    public function setRowsToRepeatAtTopByStartAndEnd($pStart, $pEnd)
530    {
531        $this->rowsToRepeatAtTop = [$pStart, $pEnd];
532
533        return $this;
534    }
535
536    /**
537     * Get center page horizontally.
538     *
539     * @return bool
540     */
541    public function getHorizontalCentered()
542    {
543        return $this->horizontalCentered;
544    }
545
546    /**
547     * Set center page horizontally.
548     *
549     * @param bool $value
550     *
551     * @return $this
552     */
553    public function setHorizontalCentered($value)
554    {
555        $this->horizontalCentered = $value;
556
557        return $this;
558    }
559
560    /**
561     * Get center page vertically.
562     *
563     * @return bool
564     */
565    public function getVerticalCentered()
566    {
567        return $this->verticalCentered;
568    }
569
570    /**
571     * Set center page vertically.
572     *
573     * @param bool $value
574     *
575     * @return $this
576     */
577    public function setVerticalCentered($value)
578    {
579        $this->verticalCentered = $value;
580
581        return $this;
582    }
583
584    /**
585     * Get print area.
586     *
587     * @param int $index Identifier for a specific print area range if several ranges have been set
588     *                            Default behaviour, or a index value of 0, will return all ranges as a comma-separated string
589     *                            Otherwise, the specific range identified by the value of $index will be returned
590     *                            Print areas are numbered from 1
591     *
592     * @throws PhpSpreadsheetException
593     *
594     * @return string
595     */
596    public function getPrintArea($index = 0)
597    {
598        if ($index == 0) {
599            return $this->printArea;
600        }
601        $printAreas = explode(',', $this->printArea);
602        if (isset($printAreas[$index - 1])) {
603            return $printAreas[$index - 1];
604        }
605
606        throw new PhpSpreadsheetException('Requested Print Area does not exist');
607    }
608
609    /**
610     * Is print area set?
611     *
612     * @param int $index Identifier for a specific print area range if several ranges have been set
613     *                            Default behaviour, or an index value of 0, will identify whether any print range is set
614     *                            Otherwise, existence of the range identified by the value of $index will be returned
615     *                            Print areas are numbered from 1
616     *
617     * @return bool
618     */
619    public function isPrintAreaSet($index = 0)
620    {
621        if ($index == 0) {
622            return $this->printArea !== null;
623        }
624        $printAreas = explode(',', $this->printArea);
625
626        return isset($printAreas[$index - 1]);
627    }
628
629    /**
630     * Clear a print area.
631     *
632     * @param int $index Identifier for a specific print area range if several ranges have been set
633     *                            Default behaviour, or an index value of 0, will clear all print ranges that are set
634     *                            Otherwise, the range identified by the value of $index will be removed from the series
635     *                            Print areas are numbered from 1
636     *
637     * @return $this
638     */
639    public function clearPrintArea($index = 0)
640    {
641        if ($index == 0) {
642            $this->printArea = null;
643        } else {
644            $printAreas = explode(',', $this->printArea);
645            if (isset($printAreas[$index - 1])) {
646                unset($printAreas[$index - 1]);
647                $this->printArea = implode(',', $printAreas);
648            }
649        }
650
651        return $this;
652    }
653
654    /**
655     * Set print area. e.g. 'A1:D10' or 'A1:D10,G5:M20'.
656     *
657     * @param string $value
658     * @param int $index Identifier for a specific print area range allowing several ranges to be set
659     *                            When the method is "O"verwrite, then a positive integer index will overwrite that indexed
660     *                                entry in the print areas list; a negative index value will identify which entry to
661     *                                overwrite working bacward through the print area to the list, with the last entry as -1.
662     *                                Specifying an index value of 0, will overwrite <b>all</b> existing print ranges.
663     *                            When the method is "I"nsert, then a positive index will insert after that indexed entry in
664     *                                the print areas list, while a negative index will insert before the indexed entry.
665     *                                Specifying an index value of 0, will always append the new print range at the end of the
666     *                                list.
667     *                            Print areas are numbered from 1
668     * @param string $method Determines the method used when setting multiple print areas
669     *                            Default behaviour, or the "O" method, overwrites existing print area
670     *                            The "I" method, inserts the new print area before any specified index, or at the end of the list
671     *
672     * @throws PhpSpreadsheetException
673     *
674     * @return $this
675     */
676    public function setPrintArea($value, $index = 0, $method = self::SETPRINTRANGE_OVERWRITE)
677    {
678        if (strpos($value, '!') !== false) {
679            throw new PhpSpreadsheetException('Cell coordinate must not specify a worksheet.');
680        } elseif (strpos($value, ':') === false) {
681            throw new PhpSpreadsheetException('Cell coordinate must be a range of cells.');
682        } elseif (strpos($value, '$') !== false) {
683            throw new PhpSpreadsheetException('Cell coordinate must not be absolute.');
684        }
685        $value = strtoupper($value);
686
687        if ($method == self::SETPRINTRANGE_OVERWRITE) {
688            if ($index == 0) {
689                $this->printArea = $value;
690            } else {
691                $printAreas = explode(',', $this->printArea);
692                if ($index < 0) {
693                    $index = count($printAreas) - abs($index) + 1;
694                }
695                if (($index <= 0) || ($index > count($printAreas))) {
696                    throw new PhpSpreadsheetException('Invalid index for setting print range.');
697                }
698                $printAreas[$index - 1] = $value;
699                $this->printArea = implode(',', $printAreas);
700            }
701        } elseif ($method == self::SETPRINTRANGE_INSERT) {
702            if ($index == 0) {
703                $this->printArea .= ($this->printArea == '') ? $value : ',' . $value;
704            } else {
705                $printAreas = explode(',', $this->printArea);
706                if ($index < 0) {
707                    $index = abs($index) - 1;
708                }
709                if ($index > count($printAreas)) {
710                    throw new PhpSpreadsheetException('Invalid index for setting print range.');
711                }
712                $printAreas = array_merge(array_slice($printAreas, 0, $index), [$value], array_slice($printAreas, $index));
713                $this->printArea = implode(',', $printAreas);
714            }
715        } else {
716            throw new PhpSpreadsheetException('Invalid method for setting print range.');
717        }
718
719        return $this;
720    }
721
722    /**
723     * Add a new print area (e.g. 'A1:D10' or 'A1:D10,G5:M20') to the list of print areas.
724     *
725     * @param string $value
726     * @param int $index Identifier for a specific print area range allowing several ranges to be set
727     *                            A positive index will insert after that indexed entry in the print areas list, while a
728     *                                negative index will insert before the indexed entry.
729     *                                Specifying an index value of 0, will always append the new print range at the end of the
730     *                                list.
731     *                            Print areas are numbered from 1
732     *
733     * @throws PhpSpreadsheetException
734     *
735     * @return $this
736     */
737    public function addPrintArea($value, $index = -1)
738    {
739        return $this->setPrintArea($value, $index, self::SETPRINTRANGE_INSERT);
740    }
741
742    /**
743     * Set print area.
744     *
745     * @param int $column1 Column 1
746     * @param int $row1 Row 1
747     * @param int $column2 Column 2
748     * @param int $row2 Row 2
749     * @param int $index Identifier for a specific print area range allowing several ranges to be set
750     *                                When the method is "O"verwrite, then a positive integer index will overwrite that indexed
751     *                                    entry in the print areas list; a negative index value will identify which entry to
752     *                                    overwrite working backward through the print area to the list, with the last entry as -1.
753     *                                    Specifying an index value of 0, will overwrite <b>all</b> existing print ranges.
754     *                                When the method is "I"nsert, then a positive index will insert after that indexed entry in
755     *                                    the print areas list, while a negative index will insert before the indexed entry.
756     *                                    Specifying an index value of 0, will always append the new print range at the end of the
757     *                                    list.
758     *                                Print areas are numbered from 1
759     * @param string $method Determines the method used when setting multiple print areas
760     *                                Default behaviour, or the "O" method, overwrites existing print area
761     *                                The "I" method, inserts the new print area before any specified index, or at the end of the list
762     *
763     * @throws PhpSpreadsheetException
764     *
765     * @return $this
766     */
767    public function setPrintAreaByColumnAndRow($column1, $row1, $column2, $row2, $index = 0, $method = self::SETPRINTRANGE_OVERWRITE)
768    {
769        return $this->setPrintArea(
770            Coordinate::stringFromColumnIndex($column1) . $row1 . ':' . Coordinate::stringFromColumnIndex($column2) . $row2,
771            $index,
772            $method
773        );
774    }
775
776    /**
777     * Add a new print area to the list of print areas.
778     *
779     * @param int $column1 Start Column for the print area
780     * @param int $row1 Start Row for the print area
781     * @param int $column2 End Column for the print area
782     * @param int $row2 End Row for the print area
783     * @param int $index Identifier for a specific print area range allowing several ranges to be set
784     *                                A positive index will insert after that indexed entry in the print areas list, while a
785     *                                    negative index will insert before the indexed entry.
786     *                                    Specifying an index value of 0, will always append the new print range at the end of the
787     *                                    list.
788     *                                Print areas are numbered from 1
789     *
790     * @throws PhpSpreadsheetException
791     *
792     * @return $this
793     */
794    public function addPrintAreaByColumnAndRow($column1, $row1, $column2, $row2, $index = -1)
795    {
796        return $this->setPrintArea(
797            Coordinate::stringFromColumnIndex($column1) . $row1 . ':' . Coordinate::stringFromColumnIndex($column2) . $row2,
798            $index,
799            self::SETPRINTRANGE_INSERT
800        );
801    }
802
803    /**
804     * Get first page number.
805     *
806     * @return int
807     */
808    public function getFirstPageNumber()
809    {
810        return $this->firstPageNumber;
811    }
812
813    /**
814     * Set first page number.
815     *
816     * @param int $value
817     *
818     * @return $this
819     */
820    public function setFirstPageNumber($value)
821    {
822        $this->firstPageNumber = $value;
823
824        return $this;
825    }
826
827    /**
828     * Reset first page number.
829     *
830     * @return $this
831     */
832    public function resetFirstPageNumber()
833    {
834        return $this->setFirstPageNumber(null);
835    }
836
837    /**
838     * Implement PHP __clone to create a deep clone, not just a shallow copy.
839     */
840    public function __clone()
841    {
842        $vars = get_object_vars($this);
843        foreach ($vars as $key => $value) {
844            if (is_object($value)) {
845                $this->$key = clone $value;
846            } else {
847                $this->$key = $value;
848            }
849        }
850    }
851}
852