Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xls Conditional Format Improvements #4030

Merged
merged 4 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading
Loading