File Source for Style.php

PHPExcel_Style

# Source for file Style.php

Documentation is available at Style.php

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

Documentation generated on Sun, 27 Feb 2011 16:34:19 -0800 by phpDocumentor 1.4.3