1# Copyright (c) 2010-2024 openpyxl
2
3from collections import OrderedDict
4
5from openpyxl.descriptors import (
6 Bool,
7 Sequence,
8 Alias,
9 Convertible,
10)
11from openpyxl.descriptors.serialisable import Serialisable
12
13from .rule import Rule
14
15from openpyxl.worksheet.cell_range import MultiCellRange
16
17class ConditionalFormatting(Serialisable):
18
19 tagname = "conditionalFormatting"
20
21 sqref = Convertible(expected_type=MultiCellRange)
22 cells = Alias("sqref")
23 pivot = Bool(allow_none=True)
24 cfRule = Sequence(expected_type=Rule)
25 rules = Alias("cfRule")
26
27
28 def __init__(self, sqref=(), pivot=None, cfRule=(), extLst=None):
29 self.sqref = sqref
30 self.pivot = pivot
31 self.cfRule = cfRule
32
33
34 def __eq__(self, other):
35 if not isinstance(other, self.__class__):
36 return False
37 return self.sqref == other.sqref
38
39
40 def __hash__(self):
41 return hash(self.sqref)
42
43
44 def __repr__(self):
45 return "<{cls} {cells}>".format(cls=self.__class__.__name__, cells=self.sqref)
46
47
48 def __contains__(self, coord):
49 """
50 Check whether a certain cell is affected by the formatting
51 """
52 return coord in self.sqref
53
54
55class ConditionalFormattingList:
56 """Conditional formatting rules."""
57
58
59 def __init__(self):
60 self._cf_rules = OrderedDict()
61 self.max_priority = 0
62
63
64 def add(self, range_string, cfRule):
65 """Add a rule such as ColorScaleRule, FormulaRule or CellIsRule
66
67 The priority will be added automatically.
68 """
69 cf = range_string
70 if isinstance(range_string, str):
71 cf = ConditionalFormatting(range_string)
72 if not isinstance(cfRule, Rule):
73 raise ValueError("Only instances of openpyxl.formatting.rule.Rule may be added")
74 rule = cfRule
75 self.max_priority += 1
76 if not rule.priority:
77 rule.priority = self.max_priority
78
79 self._cf_rules.setdefault(cf, []).append(rule)
80
81
82 def __bool__(self):
83 return bool(self._cf_rules)
84
85
86 def __len__(self):
87 return len(self._cf_rules)
88
89
90 def __iter__(self):
91 for cf, rules in self._cf_rules.items():
92 cf.rules = rules
93 yield cf
94
95
96 def __getitem__(self, key):
97 """
98 Get the rules for a cell range
99 """
100 if isinstance(key, str):
101 key = ConditionalFormatting(sqref=key)
102 return self._cf_rules[key]
103
104
105 def __delitem__(self, key):
106 key = ConditionalFormatting(sqref=key)
107 del self._cf_rules[key]
108
109
110 def __setitem__(self, key, rule):
111 """
112 Add a rule for a cell range
113 """
114 self.add(key, rule)