PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/PHPExcel_1.7.8-with_documentation-msoffice_format/PHPExcel_1.7.8-with_documentation-msoffice_format/Classes/PHPExcel/Style.php

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