source: sourcecode/application/libraries/PHPExcel/Style.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 23.6 KB
Line 
1<?php
2/**
3 * PHPExcel
4 *
5 * Copyright (c) 2006 - 2014 PHPExcel
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 * @category   PHPExcel
22 * @package    PHPExcel_Style
23 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25 * @version    1.8.0, 2014-03-02
26 */
27
28
29/**
30 * PHPExcel_Style
31 *
32 * @category   PHPExcel
33 * @package    PHPExcel_Style
34 * @copyright  Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35 */
36class PHPExcel_Style extends PHPExcel_Style_Supervisor implements PHPExcel_IComparable
37{
38    /**
39     * Font
40     *
41     * @var PHPExcel_Style_Font
42     */
43    protected $_font;
44
45    /**
46     * Fill
47     *
48     * @var PHPExcel_Style_Fill
49     */
50    protected $_fill;
51
52    /**
53     * Borders
54     *
55     * @var PHPExcel_Style_Borders
56     */
57    protected $_borders;
58
59    /**
60     * Alignment
61     *
62     * @var PHPExcel_Style_Alignment
63     */
64    protected $_alignment;
65
66    /**
67     * Number Format
68     *
69     * @var PHPExcel_Style_NumberFormat
70     */
71    protected $_numberFormat;
72
73    /**
74     * Conditional styles
75     *
76     * @var PHPExcel_Style_Conditional[]
77     */
78    protected $_conditionalStyles;
79
80    /**
81     * Protection
82     *
83     * @var PHPExcel_Style_Protection
84     */
85    protected $_protection;
86
87    /**
88     * Index of style in collection. Only used for real style.
89     *
90     * @var int
91     */
92    protected $_index;
93
94    /**
95     * Use Quote Prefix when displaying in cell editor. Only used for real style.
96     *
97     * @var boolean
98     */
99    protected $_quotePrefix = false;
100
101    /**
102     * Create a new PHPExcel_Style
103     *
104     * @param boolean $isSupervisor Flag indicating if this is a supervisor or not
105     *          Leave this value at default unless you understand exactly what
106     *    its ramifications are
107     * @param boolean $isConditional Flag indicating if this is a conditional style or not
108     *          Leave this value at default unless you understand exactly what
109     *    its ramifications are
110     */
111    public function __construct($isSupervisor = false, $isConditional = false)
112    {
113        // Supervisor?
114        $this->_isSupervisor = $isSupervisor;
115
116        // Initialise values
117        $this->_conditionalStyles       = array();
118        $this->_font              = new PHPExcel_Style_Font($isSupervisor, $isConditional);
119        $this->_fill              = new PHPExcel_Style_Fill($isSupervisor, $isConditional);
120        $this->_borders           = new PHPExcel_Style_Borders($isSupervisor, $isConditional);
121        $this->_alignment         = new PHPExcel_Style_Alignment($isSupervisor, $isConditional);
122        $this->_numberFormat      = new PHPExcel_Style_NumberFormat($isSupervisor, $isConditional);
123        $this->_protection        = new PHPExcel_Style_Protection($isSupervisor, $isConditional);
124
125        // bind parent if we are a supervisor
126        if ($isSupervisor) {
127            $this->_font->bindParent($this);
128            $this->_fill->bindParent($this);
129            $this->_borders->bindParent($this);
130            $this->_alignment->bindParent($this);
131            $this->_numberFormat->bindParent($this);
132            $this->_protection->bindParent($this);
133        }
134    }
135
136    /**
137     * Get the shared style component for the currently active cell in currently active sheet.
138     * Only used for style supervisor
139     *
140     * @return PHPExcel_Style
141     */
142    public function getSharedComponent()
143    {
144        $activeSheet = $this->getActiveSheet();
145        $selectedCell = $this->getActiveCell(); // e.g. 'A1'
146
147        if ($activeSheet->cellExists($selectedCell)) {
148            $xfIndex = $activeSheet->getCell($selectedCell)->getXfIndex();
149        } else {
150            $xfIndex = 0;
151        }
152
153        return $this->_parent->getCellXfByIndex($xfIndex);
154    }
155
156    /**
157     * Get parent. Only used for style supervisor
158     *
159     * @return PHPExcel
160     */
161    public function getParent()
162    {
163        return $this->_parent;
164    }
165
166        /**
167         * Build style array from subcomponents
168         *
169         * @param array $array
170         * @return array
171         */
172        public function getStyleArray($array)
173        {
174                return array('quotePrefix' => $array);
175        }
176
177    /**
178     * Apply styles from array
179     *
180     * <code>
181     * $objPHPExcel->getActiveSheet()->getStyle('B2')->applyFromArray(
182     *         array(
183     *             'font'    => array(
184     *                 'name'      => 'Arial',
185     *                 'bold'      => true,
186     *                 'italic'    => false,
187     *                 'underline' => PHPExcel_Style_Font::UNDERLINE_DOUBLE,
188     *                 'strike'    => false,
189     *                 'color'     => array(
190     *                     'rgb' => '808080'
191     *                 )
192     *             ),
193     *             'borders' => array(
194     *                 'bottom'     => array(
195     *                     'style' => PHPExcel_Style_Border::BORDER_DASHDOT,
196     *                     'color' => array(
197     *                         'rgb' => '808080'
198     *                     )
199     *                 ),
200     *                 'top'     => array(
201     *                     'style' => PHPExcel_Style_Border::BORDER_DASHDOT,
202     *                     'color' => array(
203     *                         'rgb' => '808080'
204     *                     )
205     *                 )
206     *             ),
207     *             'quotePrefix'    => true
208     *         )
209     * );
210     * </code>
211     *
212     * @param    array    $pStyles    Array containing style information
213     * @param     boolean        $pAdvanced    Advanced mode for setting borders.
214     * @throws    PHPExcel_Exception
215     * @return PHPExcel_Style
216     */
217    public function applyFromArray($pStyles = null, $pAdvanced = true)
218    {
219        if (is_array($pStyles)) {
220            if ($this->_isSupervisor) {
221
222                $pRange = $this->getSelectedCells();
223
224                // Uppercase coordinate
225                $pRange = strtoupper($pRange);
226
227                // Is it a cell range or a single cell?
228                if (strpos($pRange, ':') === false) {
229                    $rangeA = $pRange;
230                    $rangeB = $pRange;
231                } else {
232                    list($rangeA, $rangeB) = explode(':', $pRange);
233                }
234
235                // Calculate range outer borders
236                $rangeStart = PHPExcel_Cell::coordinateFromString($rangeA);
237                $rangeEnd     = PHPExcel_Cell::coordinateFromString($rangeB);
238
239                // Translate column into index
240                $rangeStart[0]    = PHPExcel_Cell::columnIndexFromString($rangeStart[0]) - 1;
241                $rangeEnd[0]    = PHPExcel_Cell::columnIndexFromString($rangeEnd[0]) - 1;
242
243                // Make sure we can loop upwards on rows and columns
244                if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
245                    $tmp = $rangeStart;
246                    $rangeStart = $rangeEnd;
247                    $rangeEnd = $tmp;
248                }
249
250                // ADVANCED MODE:
251
252                if ($pAdvanced && isset($pStyles['borders'])) {
253
254                    // 'allborders' is a shorthand property for 'outline' and 'inside' and
255                    //        it applies to components that have not been set explicitly
256                    if (isset($pStyles['borders']['allborders'])) {
257                        foreach (array('outline', 'inside') as $component) {
258                            if (!isset($pStyles['borders'][$component])) {
259                                $pStyles['borders'][$component] = $pStyles['borders']['allborders'];
260                            }
261                        }
262                        unset($pStyles['borders']['allborders']); // not needed any more
263                    }
264
265                    // 'outline' is a shorthand property for 'top', 'right', 'bottom', 'left'
266                    //        it applies to components that have not been set explicitly
267                    if (isset($pStyles['borders']['outline'])) {
268                        foreach (array('top', 'right', 'bottom', 'left') as $component) {
269                            if (!isset($pStyles['borders'][$component])) {
270                                $pStyles['borders'][$component] = $pStyles['borders']['outline'];
271                            }
272                        }
273                        unset($pStyles['borders']['outline']); // not needed any more
274                    }
275
276                    // 'inside' is a shorthand property for 'vertical' and 'horizontal'
277                    //        it applies to components that have not been set explicitly
278                    if (isset($pStyles['borders']['inside'])) {
279                        foreach (array('vertical', 'horizontal') as $component) {
280                            if (!isset($pStyles['borders'][$component])) {
281                                $pStyles['borders'][$component] = $pStyles['borders']['inside'];
282                            }
283                        }
284                        unset($pStyles['borders']['inside']); // not needed any more
285                    }
286
287                    // width and height characteristics of selection, 1, 2, or 3 (for 3 or more)
288                    $xMax = min($rangeEnd[0] - $rangeStart[0] + 1, 3);
289                    $yMax = min($rangeEnd[1] - $rangeStart[1] + 1, 3);
290
291                    // loop through up to 3 x 3 = 9 regions
292                    for ($x = 1; $x <= $xMax; ++$x) {
293                        // start column index for region
294                        $colStart = ($x == 3) ?
295                            PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0])
296                                : PHPExcel_Cell::stringFromColumnIndex($rangeStart[0] + $x - 1);
297
298                        // end column index for region
299                        $colEnd = ($x == 1) ?
300                            PHPExcel_Cell::stringFromColumnIndex($rangeStart[0])
301                                : PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0] - $xMax + $x);
302
303                        for ($y = 1; $y <= $yMax; ++$y) {
304
305                            // which edges are touching the region
306                            $edges = array();
307
308                            // are we at left edge
309                            if ($x == 1) {
310                                $edges[] = 'left';
311                            }
312
313                            // are we at right edge
314                            if ($x == $xMax) {
315                                $edges[] = 'right';
316                            }
317
318                            // are we at top edge?
319                            if ($y == 1) {
320                                $edges[] = 'top';
321                            }
322
323                            // are we at bottom edge?
324                            if ($y == $yMax) {
325                                $edges[] = 'bottom';
326                            }
327
328                            // start row index for region
329                            $rowStart = ($y == 3) ?
330                                $rangeEnd[1] : $rangeStart[1] + $y - 1;
331
332                            // end row index for region
333                            $rowEnd = ($y == 1) ?
334                                $rangeStart[1] : $rangeEnd[1] - $yMax + $y;
335
336                            // build range for region
337                            $range = $colStart . $rowStart . ':' . $colEnd . $rowEnd;
338
339                            // retrieve relevant style array for region
340                            $regionStyles = $pStyles;
341                            unset($regionStyles['borders']['inside']);
342
343                            // what are the inner edges of the region when looking at the selection
344                            $innerEdges = array_diff( array('top', 'right', 'bottom', 'left'), $edges );
345
346                            // inner edges that are not touching the region should take the 'inside' border properties if they have been set
347                            foreach ($innerEdges as $innerEdge) {
348                                switch ($innerEdge) {
349                                    case 'top':
350                                    case 'bottom':
351                                        // should pick up 'horizontal' border property if set
352                                        if (isset($pStyles['borders']['horizontal'])) {
353                                            $regionStyles['borders'][$innerEdge] = $pStyles['borders']['horizontal'];
354                                        } else {
355                                            unset($regionStyles['borders'][$innerEdge]);
356                                        }
357                                        break;
358                                    case 'left':
359                                    case 'right':
360                                        // should pick up 'vertical' border property if set
361                                        if (isset($pStyles['borders']['vertical'])) {
362                                            $regionStyles['borders'][$innerEdge] = $pStyles['borders']['vertical'];
363                                        } else {
364                                            unset($regionStyles['borders'][$innerEdge]);
365                                        }
366                                        break;
367                                }
368                            }
369
370                            // apply region style to region by calling applyFromArray() in simple mode
371                            $this->getActiveSheet()->getStyle($range)->applyFromArray($regionStyles, false);
372                        }
373                    }
374                    return $this;
375                }
376
377                // SIMPLE MODE:
378
379                // Selection type, inspect
380                if (preg_match('/^[A-Z]+1:[A-Z]+1048576$/', $pRange)) {
381                    $selectionType = 'COLUMN';
382                } else if (preg_match('/^A[0-9]+:XFD[0-9]+$/', $pRange)) {
383                    $selectionType = 'ROW';
384                } else {
385                    $selectionType = 'CELL';
386                }
387
388                // First loop through columns, rows, or cells to find out which styles are affected by this operation
389                switch ($selectionType) {
390                    case 'COLUMN':
391                        $oldXfIndexes = array();
392                        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
393                            $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
394                        }
395                        break;
396
397                    case 'ROW':
398                        $oldXfIndexes = array();
399                        for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
400                            if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() == null) {
401                                $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style
402                            } else {
403                                $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
404                            }
405                        }
406                        break;
407
408                    case 'CELL':
409                        $oldXfIndexes = array();
410                        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
411                            for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
412                                $oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true;
413                            }
414                        }
415                        break;
416                }
417
418                // clone each of the affected styles, apply the style array, and add the new styles to the workbook
419                $workbook = $this->getActiveSheet()->getParent();
420                foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
421                    $style = $workbook->getCellXfByIndex($oldXfIndex);
422                    $newStyle = clone $style;
423                    $newStyle->applyFromArray($pStyles);
424
425                    if ($existingStyle = $workbook->getCellXfByHashCode($newStyle->getHashCode())) {
426                        // there is already such cell Xf in our collection
427                        $newXfIndexes[$oldXfIndex] = $existingStyle->getIndex();
428                    } else {
429                        // we don't have such a cell Xf, need to add
430                        $workbook->addCellXf($newStyle);
431                        $newXfIndexes[$oldXfIndex] = $newStyle->getIndex();
432                    }
433                }
434
435                // Loop through columns, rows, or cells again and update the XF index
436                switch ($selectionType) {
437                    case 'COLUMN':
438                        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
439                            $columnDimension = $this->getActiveSheet()->getColumnDimensionByColumn($col);
440                            $oldXfIndex = $columnDimension->getXfIndex();
441                            $columnDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
442                        }
443                        break;
444
445                    case 'ROW':
446                        for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
447                            $rowDimension = $this->getActiveSheet()->getRowDimension($row);
448                            $oldXfIndex = $rowDimension->getXfIndex() === null ?
449                                0 : $rowDimension->getXfIndex(); // row without explicit style should be formatted based on default style
450                            $rowDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
451                        }
452                        break;
453
454                    case 'CELL':
455                        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
456                            for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
457                                $cell = $this->getActiveSheet()->getCellByColumnAndRow($col, $row);
458                                $oldXfIndex = $cell->getXfIndex();
459                                $cell->setXfIndex($newXfIndexes[$oldXfIndex]);
460                            }
461                        }
462                        break;
463                }
464
465            } else {
466                // not a supervisor, just apply the style array directly on style object
467                if (array_key_exists('fill', $pStyles)) {
468                    $this->getFill()->applyFromArray($pStyles['fill']);
469                }
470                if (array_key_exists('font', $pStyles)) {
471                    $this->getFont()->applyFromArray($pStyles['font']);
472                }
473                if (array_key_exists('borders', $pStyles)) {
474                    $this->getBorders()->applyFromArray($pStyles['borders']);
475                }
476                if (array_key_exists('alignment', $pStyles)) {
477                    $this->getAlignment()->applyFromArray($pStyles['alignment']);
478                }
479                if (array_key_exists('numberformat', $pStyles)) {
480                    $this->getNumberFormat()->applyFromArray($pStyles['numberformat']);
481                }
482                if (array_key_exists('protection', $pStyles)) {
483                    $this->getProtection()->applyFromArray($pStyles['protection']);
484                }
485                if (array_key_exists('quotePrefix', $pStyles)) {
486                    $this->_quotePrefix = $pStyles['quotePrefix'];
487                }
488            }
489        } else {
490            throw new PHPExcel_Exception("Invalid style array passed.");
491        }
492        return $this;
493    }
494
495    /**
496     * Get Fill
497     *
498     * @return PHPExcel_Style_Fill
499     */
500    public function getFill()
501    {
502        return $this->_fill;
503    }
504
505    /**
506     * Get Font
507     *
508     * @return PHPExcel_Style_Font
509     */
510    public function getFont()
511    {
512        return $this->_font;
513    }
514
515    /**
516     * Set font
517     *
518     * @param PHPExcel_Style_Font $font
519     * @return PHPExcel_Style
520     */
521    public function setFont(PHPExcel_Style_Font $font)
522    {
523        $this->_font = $font;
524        return $this;
525    }
526
527    /**
528     * Get Borders
529     *
530     * @return PHPExcel_Style_Borders
531     */
532    public function getBorders()
533    {
534        return $this->_borders;
535    }
536
537    /**
538     * Get Alignment
539     *
540     * @return PHPExcel_Style_Alignment
541     */
542    public function getAlignment()
543    {
544        return $this->_alignment;
545    }
546
547    /**
548     * Get Number Format
549     *
550     * @return PHPExcel_Style_NumberFormat
551     */
552    public function getNumberFormat()
553    {
554        return $this->_numberFormat;
555    }
556
557    /**
558     * Get Conditional Styles. Only used on supervisor.
559     *
560     * @return PHPExcel_Style_Conditional[]
561     */
562    public function getConditionalStyles()
563    {
564        return $this->getActiveSheet()->getConditionalStyles($this->getActiveCell());
565    }
566
567    /**
568     * Set Conditional Styles. Only used on supervisor.
569     *
570     * @param PHPExcel_Style_Conditional[] $pValue Array of condtional styles
571     * @return PHPExcel_Style
572     */
573    public function setConditionalStyles($pValue = null)
574    {
575        if (is_array($pValue)) {
576            $this->getActiveSheet()->setConditionalStyles($this->getSelectedCells(), $pValue);
577        }
578        return $this;
579    }
580
581    /**
582     * Get Protection
583     *
584     * @return PHPExcel_Style_Protection
585     */
586    public function getProtection()
587    {
588        return $this->_protection;
589    }
590
591    /**
592     * Get quote prefix
593     *
594     * @return boolean
595     */
596    public function getQuotePrefix()
597    {
598        if ($this->_isSupervisor) {
599            return $this->getSharedComponent()->getQuotePrefix();
600        }
601        return $this->_quotePrefix;
602    }
603
604    /**
605     * Set quote prefix
606     *
607     * @param boolean $pValue
608     */
609    public function setQuotePrefix($pValue)
610    {
611        if ($pValue == '') {
612            $pValue = false;
613        }
614        if ($this->_isSupervisor) {
615            $styleArray = array('quotePrefix' => $pValue);
616            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
617        } else {
618            $this->_quotePrefix = (boolean) $pValue;
619        }
620        return $this;
621    }
622
623    /**
624     * Get hash code
625     *
626     * @return string Hash code
627     */
628    public function getHashCode()
629    {
630        $hashConditionals = '';
631        foreach ($this->_conditionalStyles as $conditional) {
632            $hashConditionals .= $conditional->getHashCode();
633        }
634
635        return md5(
636              $this->_fill->getHashCode()
637            . $this->_font->getHashCode()
638            . $this->_borders->getHashCode()
639            . $this->_alignment->getHashCode()
640            . $this->_numberFormat->getHashCode()
641            . $hashConditionals
642            . $this->_protection->getHashCode()
643            . ($this->_quotePrefix  ? 't' : 'f')
644            . __CLASS__
645        );
646    }
647
648    /**
649     * Get own index in style collection
650     *
651     * @return int
652     */
653    public function getIndex()
654    {
655        return $this->_index;
656    }
657
658    /**
659     * Set own index in style collection
660     *
661     * @param int $pValue
662     */
663    public function setIndex($pValue)
664    {
665        $this->_index = $pValue;
666    }
667
668}
Note: See TracBrowser for help on using the repository browser.