Skip to content

Commit

Permalink
Merge pull request #4030 from oleibman/condxls
Browse files Browse the repository at this point in the history
Xls Conditional Format Improvements
  • Loading branch information
oleibman committed May 19, 2024
2 parents f2a934a + 623efc0 commit 2ed696f
Show file tree
Hide file tree
Showing 23 changed files with 147 additions and 64 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed

- Incorrect Reader CSV with BOM. [Issue #4028](https://github.com/PHPOffice/PhpSpreadsheet/issues/4028) [PR #4029](https://github.com/PHPOffice/PhpSpreadsheet/pull/4029)
- POWER Null/Bool Args. [PR #4031](https://github.com/PHPOffice/PhpSpreadsheet/pull/4031)
- POWER Null/Bool Args. [PR #4031](https://github.com/PHPOffice/PhpSpreadsheet/pull/4031)
- Do Not Output Alignment and Protection for Conditional Format. [Issue #4025](https://github.com/PHPOffice/PhpSpreadsheet/issues/4025) [PR #4027](https://github.com/PHPOffice/PhpSpreadsheet/pull/4027)
- Xls Conditional Format Improvements. [PR #4030](https://github.com/PHPOffice/PhpSpreadsheet/pull/4030)

## 2024-05-11 - 2.1.0

Expand Down
8 changes: 4 additions & 4 deletions docs/topics/conditional-formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ $conditional->setOperatorType(\PhpOffice\PhpSpreadsheet\Style\Conditional::OPERA
$conditional->addCondition(80);
$conditional->getStyle()->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKGREEN);
$conditional->getStyle()->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$conditional->getStyle()->getFill()->getEndColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);
$conditional->getStyle()->getFill()->getStartColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);

$conditionalStyles = $spreadsheet->getActiveSheet()->getStyle('A1:A10')->getConditionalStyles();
$conditionalStyles[] = $conditional;
Expand All @@ -63,7 +63,7 @@ $wizard = $wizardFactory->newRule(\PhpOffice\PhpSpreadsheet\Style\ConditionalFor
$wizard->greaterThan(80);
$wizard->getStyle()->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKGREEN);
$wizard->getStyle()->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$wizard->getStyle()->getFill()->getEndColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);
$wizard->getStyle()->getFill()->getStartColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);

$conditional = $wizard->getConditional();
```
Expand All @@ -84,7 +84,7 @@ $conditional2->setOperatorType(\PhpOffice\PhpSpreadsheet\Style\Conditional::OPER
$conditional2->addCondition(10);
$conditional2->getStyle()->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKRED);
$conditional2->getStyle()->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$conditional2->getStyle()->getFill()->getEndColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED);
$conditional2->getStyle()->getFill()->getStartColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED);

$conditionalStyles = $spreadsheet->getActiveSheet()->getStyle('A1:A10')->getConditionalStyles();
$conditionalStyles[] = $conditional2;
Expand All @@ -98,7 +98,7 @@ $wizard = $wizardFactory->newRule(\PhpOffice\PhpSpreadsheet\Style\ConditionalFor
$wizard->lessThan(10);
$wizard->getStyle()->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKGREEN);
$wizard->getStyle()->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$wizard->getStyle()->getFill()->getEndColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);
$wizard->getStyle()->getFill()->getStartColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_GREEN);

$conditional = $wizard->getConditional();
```
Expand Down
6 changes: 0 additions & 6 deletions samples/ConditionalFormatting/01_Basic_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,16 @@
$yellowStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFill()
->getEndColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFill()
->getEndColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
$redStyle = new Style(false, true);
$redStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB(Color::COLOR_RED);
$redStyle->getFill()
->getEndColor()->setARGB(Color::COLOR_RED);
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));

// Set conditional formatting rules and styles
Expand Down
6 changes: 3 additions & 3 deletions samples/ConditionalFormatting/02_Text_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@
$yellowStyle = new Style(false, true);
$yellowStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_YELLOW);
->getStartColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_GREEN);
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
$redStyle = new Style(false, true);
$redStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_RED);
->getStartColor()->setARGB(Color::COLOR_RED);
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));

// Set conditional formatting rules and styles
Expand Down
4 changes: 2 additions & 2 deletions samples/ConditionalFormatting/03_Blank_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_GREEN);
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
$redStyle = new Style(false, true);
$redStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_RED);
->getStartColor()->setARGB(Color::COLOR_RED);
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));

// Set conditional formatting rules and styles
Expand Down
4 changes: 2 additions & 2 deletions samples/ConditionalFormatting/04_Error_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_GREEN);
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));
$redStyle = new Style(false, true);
$redStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_RED);
->getStartColor()->setARGB(Color::COLOR_RED);
$redStyle->getFont()->setColor(new Color(Color::COLOR_GREEN));

// Set conditional formatting rules and styles
Expand Down
2 changes: 1 addition & 1 deletion samples/ConditionalFormatting/05_Date_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
$yellowStyle = new Style(false, true);
$yellowStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_YELLOW);
->getStartColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));

// Set conditional formatting rules and styles
Expand Down
4 changes: 2 additions & 2 deletions samples/ConditionalFormatting/06_Duplicate_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@
$yellowStyle = new Style(false, true);
$yellowStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_YELLOW);
->getStartColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_GREEN);
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));

// Set conditional formatting rules and styles
Expand Down
4 changes: 2 additions & 2 deletions samples/ConditionalFormatting/07_Expression_Comparisons.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@
$yellowStyle = new Style(false, true);
$yellowStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_YELLOW);
->getStartColor()->setARGB(Color::COLOR_YELLOW);
$yellowStyle->getFont()->setColor(new Color(Color::COLOR_BLUE));
$greenStyle = new Style(false, true);
$greenStyle->getFill()
->setFillType(Fill::FILL_SOLID)
->getEndColor()->setARGB(Color::COLOR_GREEN);
->getStartColor()->setARGB(Color::COLOR_GREEN);
$greenStyle->getFont()->setColor(new Color(Color::COLOR_DARKRED));

$greenStyleMoney = clone $greenStyle;
Expand Down
8 changes: 6 additions & 2 deletions src/PhpSpreadsheet/Reader/Xls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7493,11 +7493,15 @@ private function getCFFillStyle(string $options, Style $style): void

// bit: 0-6; mask: 0x007F; type
$color1 = (0x007F & $fillColors) >> 0;
$style->getFill()->getStartColor()->setRGB(Xls\Color::map($color1, $this->palette, $this->version)['rgb']);

// bit: 7-13; mask: 0x3F80; type
$color2 = (0x3F80 & $fillColors) >> 7;
$style->getFill()->getEndColor()->setRGB(Xls\Color::map($color2, $this->palette, $this->version)['rgb']);
if ($fillPattern === Fill::FILL_SOLID) {
$style->getFill()->getStartColor()->setRGB(Xls\Color::map($color2, $this->palette, $this->version)['rgb']);
} else {
$style->getFill()->getStartColor()->setRGB(Xls\Color::map($color1, $this->palette, $this->version)['rgb']);
$style->getFill()->getEndColor()->setRGB(Xls\Color::map($color2, $this->palette, $this->version)['rgb']);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/PhpSpreadsheet/Writer/Xls.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public function save($filename, int $flags = 0): void
// Initialise worksheet writers
$countSheets = $this->spreadsheet->getSheetCount();
for ($i = 0; $i < $countSheets; ++$i) {
$this->writerWorksheets[$i] = new Worksheet($this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser, $this->preCalculateFormulas, $this->spreadsheet->getSheet($i));
$this->writerWorksheets[$i] = new Worksheet($this->strTotal, $this->strUnique, $this->strTable, $this->colors, $this->parser, $this->preCalculateFormulas, $this->spreadsheet->getSheet($i), $this->writerWorkbook);
}

// build Escher objects. Escher objects for workbooks needs to be build before Escher object for workbook.
Expand Down
10 changes: 9 additions & 1 deletion src/PhpSpreadsheet/Writer/Xls/Style/ColorMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

use PhpOffice\PhpSpreadsheet\Style\Color;

/*
* Static array incorrectly used by Xls Writer for Conditional Styles.
*
* @deprecated since version 2.2
*
* @codecoverageignore
*/

class ColorMap
{
/**
Expand Down Expand Up @@ -70,7 +78,7 @@ class ColorMap

public static function lookup(Color $color, int $defaultIndex = 0x00): int
{
$colorRgb = $color->getRGB();
$colorRgb = strtoupper($color->getRGB());
if (is_string($colorRgb) && array_key_exists("#{$colorRgb}", self::$colorMap)) {
return self::$colorMap["#{$colorRgb}"];
}
Expand Down
4 changes: 2 additions & 2 deletions src/PhpSpreadsheet/Writer/Xls/Workbook.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public function addFont(\PhpOffice\PhpSpreadsheet\Style\Font $font): int
*
* @return int Color index
*/
private function addColor(string $rgb): int
public function addColor(string $rgb, int $default = 0): int
{
if (!isset($this->colors[$rgb])) {
$color
Expand All @@ -298,7 +298,7 @@ private function addColor(string $rgb): int
$this->colors[$rgb] = $colorIndex;
} else {
// no room for more custom colors, just map to black
$colorIndex = 0;
$colorIndex = $default;
}
}
} else {
Expand Down
24 changes: 13 additions & 11 deletions src/PhpSpreadsheet/Writer/Xls/Worksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class Worksheet extends BIFFwriter

private int $printHeaders;

private ?Workbook $writerWorkbook;

/**
* Constructor.
*
Expand All @@ -165,7 +167,7 @@ class Worksheet extends BIFFwriter
* @param bool $preCalculateFormulas Flag indicating whether formulas should be calculated or just written
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet The worksheet to write
*/
public function __construct(int &$str_total, int &$str_unique, array &$str_table, array &$colors, Parser $parser, bool $preCalculateFormulas, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet)
public function __construct(int &$str_total, int &$str_unique, array &$str_table, array &$colors, Parser $parser, bool $preCalculateFormulas, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet, ?Workbook $writerWorkbook = null)
{
// It needs to call its parent's constructor explicitly
parent::__construct();
Expand Down Expand Up @@ -208,6 +210,7 @@ public function __construct(int &$str_total, int &$str_unique, array &$str_table
if ($this->lastColumnIndex > 255) {
$this->lastColumnIndex = 255;
}
$this->writerWorkbook = $writerWorkbook;
}

/**
Expand Down Expand Up @@ -491,8 +494,6 @@ private function writeConditionalFormatting(): void

$arrConditionalStyles = $this->phpSheet->getConditionalStylesCollection();
if (!empty($arrConditionalStyles)) {
$arrConditional = [];

// Write ConditionalFormattingTable records
foreach ($arrConditionalStyles as $cellCoordinate => $conditionalStyles) {
$cfHeaderWritten = false;
Expand All @@ -506,10 +507,7 @@ private function writeConditionalFormatting(): void
if ($cfHeaderWritten === false) {
$cfHeaderWritten = $this->writeCFHeader($cellCoordinate, $conditionalStyles);
}
if ($cfHeaderWritten === true && !isset($arrConditional[$conditional->getHashCode()])) {
// This hash code has been handled
$arrConditional[$conditional->getHashCode()] = true;

if ($cfHeaderWritten === true) {
// Write CFRULE record
$this->writeCFRule($conditionalFormulaHelper, $conditional, $cellCoordinate);
}
Expand Down Expand Up @@ -2971,8 +2969,7 @@ private function writeCFRule(
// Not used (3)
$dataBlockFont .= pack('vC', 0x0000, 0x00);
// Font color index
$colorIdx = Style\ColorMap::lookup($conditional->getStyle()->getFont()->getColor(), 0x00);

$colorIdx = $this->workbookColorIndex($conditional->getStyle()->getFont()->getColor()->getRgb(), 0);
$dataBlockFont .= pack('V', $colorIdx);
// Not used (4)
$dataBlockFont .= pack('V', 0x00000000);
Expand Down Expand Up @@ -3043,9 +3040,9 @@ private function writeCFRule(
// Fill Pattern Style
$blockFillPatternStyle = Style\CellFill::style($conditional->getStyle()->getFill());
// Background Color
$colorIdxBg = Style\ColorMap::lookup($conditional->getStyle()->getFill()->getStartColor(), 0x41);
$colorIdxBg = $this->workbookColorIndex($conditional->getStyle()->getFill()->getStartColor()->getRgb(), 0x41);
// Foreground Color
$colorIdxFg = Style\ColorMap::lookup($conditional->getStyle()->getFill()->getEndColor(), 0x40);
$colorIdxFg = $this->workbookColorIndex($conditional->getStyle()->getFill()->getEndColor()->getRgb(), 0x40);

$dataBlockFill = pack('v', $blockFillPatternStyle);
$dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
Expand Down Expand Up @@ -3142,4 +3139,9 @@ private function writeCFHeader(string $cellCoordinate, array $conditionalStyles)
return $dataBlockProtection;
}*/

private function workbookColorIndex(?string $rgb, int $default): int
{
return (empty($rgb) || $this->writerWorkbook === null) ? $default : $this->writerWorkbook->addColor($rgb, $default);
}
}
8 changes: 4 additions & 4 deletions tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,24 @@ public function testXlfn(): void
$condition0->setConditionType(Conditional::CONDITION_EXPRESSION);
$condition0->addCondition('ABS(B3)<2');
$condition0->getStyle()->getFill()->setFillType(Fill::FILL_SOLID);
$condition0->getStyle()->getFill()->getEndColor()->setARGB(Color::COLOR_RED);
$condition0->getStyle()->getFill()->getStartColor()->setARGB(Color::COLOR_RED);
$condition1 = new Conditional();
$condition1->setConditionType(Conditional::CONDITION_EXPRESSION);
$condition1->addCondition('ABS(B3)>2');
$condition1->getStyle()->getFill()->setFillType(Fill::FILL_SOLID);
$condition1->getStyle()->getFill()->getEndColor()->setARGB(Color::COLOR_GREEN);
$condition1->getStyle()->getFill()->getStartColor()->setARGB(Color::COLOR_GREEN);
$cond = [$condition0, $condition1];
$sheet->getStyle('B3:B5')->setConditionalStyles($cond);
$condition0 = new Conditional();
$condition0->setConditionType(Conditional::CONDITION_EXPRESSION);
$condition0->addCondition('ISOWEEKNUM(A3)<10');
$condition0->getStyle()->getFill()->setFillType(Fill::FILL_SOLID);
$condition0->getStyle()->getFill()->getEndColor()->setARGB(Color::COLOR_RED);
$condition0->getStyle()->getFill()->getStartColor()->setARGB(Color::COLOR_RED);
$condition1 = new Conditional();
$condition1->setConditionType(Conditional::CONDITION_EXPRESSION);
$condition1->addCondition('ISOWEEKNUM(A3)>40');
$condition1->getStyle()->getFill()->setFillType(Fill::FILL_SOLID);
$condition1->getStyle()->getFill()->getEndColor()->setARGB(Color::COLOR_GREEN);
$condition1->getStyle()->getFill()->getStartColor()->setARGB(Color::COLOR_GREEN);
$cond = [$condition0, $condition1];
$sheet->getStyle('A3:A5')->setConditionalStyles($cond);
$sheet->setSelectedCell('B1');
Expand Down

0 comments on commit 2ed696f

Please sign in to comment.