aspose-cells-foss 25.12.1__py3-none-any.whl → 26.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aspose_cells/__init__.py +88 -0
- aspose_cells/auto_filter.py +527 -0
- aspose_cells/cell.py +483 -0
- aspose_cells/cell_value_handler.py +319 -0
- aspose_cells/cells.py +779 -0
- aspose_cells/cfb_handler.py +445 -0
- aspose_cells/cfb_writer.py +659 -0
- aspose_cells/cfb_writer_minimal.py +337 -0
- aspose_cells/comment_xml.py +475 -0
- aspose_cells/conditional_format.py +1185 -0
- aspose_cells/csv_handler.py +690 -0
- aspose_cells/data_validation.py +911 -0
- aspose_cells/document_properties.py +356 -0
- aspose_cells/encryption_crypto.py +247 -0
- aspose_cells/encryption_params.py +138 -0
- aspose_cells/hyperlink.py +372 -0
- aspose_cells/json_handler.py +185 -0
- aspose_cells/markdown_handler.py +583 -0
- aspose_cells/shared_strings.py +101 -0
- aspose_cells/style.py +841 -0
- aspose_cells/workbook.py +499 -0
- aspose_cells/workbook_hash_password.py +68 -0
- aspose_cells/workbook_properties.py +712 -0
- aspose_cells/worksheet.py +570 -0
- aspose_cells/worksheet_properties.py +1239 -0
- aspose_cells/xlsx_encryptor.py +403 -0
- aspose_cells/xml_autofilter_loader.py +195 -0
- aspose_cells/xml_autofilter_saver.py +173 -0
- aspose_cells/xml_conditional_format_loader.py +215 -0
- aspose_cells/xml_conditional_format_saver.py +351 -0
- aspose_cells/xml_datavalidation_loader.py +239 -0
- aspose_cells/xml_datavalidation_saver.py +245 -0
- aspose_cells/xml_hyperlink_handler.py +323 -0
- aspose_cells/xml_loader.py +986 -0
- aspose_cells/xml_properties_loader.py +512 -0
- aspose_cells/xml_properties_saver.py +607 -0
- aspose_cells/xml_saver.py +1306 -0
- aspose_cells_foss-26.2.2.dist-info/METADATA +190 -0
- aspose_cells_foss-26.2.2.dist-info/RECORD +41 -0
- {aspose_cells_foss-25.12.1.dist-info → aspose_cells_foss-26.2.2.dist-info}/WHEEL +1 -1
- aspose_cells_foss-26.2.2.dist-info/top_level.txt +1 -0
- aspose/__init__.py +0 -14
- aspose/cells/__init__.py +0 -31
- aspose/cells/cell.py +0 -350
- aspose/cells/constants.py +0 -44
- aspose/cells/converters/__init__.py +0 -13
- aspose/cells/converters/csv_converter.py +0 -55
- aspose/cells/converters/json_converter.py +0 -46
- aspose/cells/converters/markdown_converter.py +0 -453
- aspose/cells/drawing/__init__.py +0 -17
- aspose/cells/drawing/anchor.py +0 -172
- aspose/cells/drawing/collection.py +0 -233
- aspose/cells/drawing/image.py +0 -338
- aspose/cells/formats.py +0 -80
- aspose/cells/formula/__init__.py +0 -10
- aspose/cells/formula/evaluator.py +0 -360
- aspose/cells/formula/functions.py +0 -433
- aspose/cells/formula/tokenizer.py +0 -340
- aspose/cells/io/__init__.py +0 -27
- aspose/cells/io/csv/__init__.py +0 -8
- aspose/cells/io/csv/reader.py +0 -88
- aspose/cells/io/csv/writer.py +0 -98
- aspose/cells/io/factory.py +0 -138
- aspose/cells/io/interfaces.py +0 -48
- aspose/cells/io/json/__init__.py +0 -8
- aspose/cells/io/json/reader.py +0 -126
- aspose/cells/io/json/writer.py +0 -119
- aspose/cells/io/md/__init__.py +0 -8
- aspose/cells/io/md/reader.py +0 -161
- aspose/cells/io/md/writer.py +0 -334
- aspose/cells/io/models.py +0 -64
- aspose/cells/io/xlsx/__init__.py +0 -9
- aspose/cells/io/xlsx/constants.py +0 -312
- aspose/cells/io/xlsx/image_writer.py +0 -311
- aspose/cells/io/xlsx/reader.py +0 -284
- aspose/cells/io/xlsx/writer.py +0 -931
- aspose/cells/plugins/__init__.py +0 -6
- aspose/cells/plugins/docling_backend/__init__.py +0 -7
- aspose/cells/plugins/docling_backend/backend.py +0 -535
- aspose/cells/plugins/markitdown_plugin/__init__.py +0 -15
- aspose/cells/plugins/markitdown_plugin/plugin.py +0 -128
- aspose/cells/range.py +0 -210
- aspose/cells/style.py +0 -287
- aspose/cells/utils/__init__.py +0 -54
- aspose/cells/utils/coordinates.py +0 -68
- aspose/cells/utils/exceptions.py +0 -43
- aspose/cells/utils/validation.py +0 -102
- aspose/cells/workbook.py +0 -352
- aspose/cells/worksheet.py +0 -670
- aspose_cells_foss-25.12.1.dist-info/METADATA +0 -189
- aspose_cells_foss-25.12.1.dist-info/RECORD +0 -53
- aspose_cells_foss-25.12.1.dist-info/entry_points.txt +0 -2
- aspose_cells_foss-25.12.1.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Aspose.Cells for Python - XML AutoFilter Saver Module
|
|
3
|
+
|
|
4
|
+
This module provides the AutoFilterXMLWriter class which handles saving
|
|
5
|
+
autofilter data to XML format according to ECMA-376 specification.
|
|
6
|
+
|
|
7
|
+
ECMA-376 Section 18.3.1.2 defines the autoFilter element structure.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AutoFilterXMLWriter:
|
|
12
|
+
"""
|
|
13
|
+
Handles writing autofilter data to XML format for .xlsx files.
|
|
14
|
+
|
|
15
|
+
The AutoFilterXMLWriter class is responsible for creating the XML
|
|
16
|
+
representation of autofilter settings including filter columns,
|
|
17
|
+
filter values, custom filters, color filters, dynamic filters,
|
|
18
|
+
top10 filters, and sort state.
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
>>> writer = AutoFilterXMLWriter()
|
|
22
|
+
>>> xml = writer.format_auto_filter_xml(worksheet.auto_filter)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, escape_xml_func):
|
|
26
|
+
"""
|
|
27
|
+
Initializes a new instance of the AutoFilterXMLWriter class.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
escape_xml_func: A function to escape XML special characters.
|
|
31
|
+
"""
|
|
32
|
+
self._escape_xml = escape_xml_func
|
|
33
|
+
|
|
34
|
+
def format_auto_filter_xml(self, auto_filter):
|
|
35
|
+
"""
|
|
36
|
+
Formats auto filter settings as XML according to ECMA-376 specification.
|
|
37
|
+
|
|
38
|
+
ECMA-376 Section 18.3.1.2 defines the autoFilter element structure:
|
|
39
|
+
- autoFilter: Main element with ref attribute (filter range)
|
|
40
|
+
- filterColumn: Represents filter settings for a column (colId attribute)
|
|
41
|
+
- filters: Contains filter values
|
|
42
|
+
- filter: Individual filter value (val attribute)
|
|
43
|
+
- customFilters: Contains custom filter criteria
|
|
44
|
+
- customFilter: Custom filter criterion (operator and val attributes)
|
|
45
|
+
- colorFilter: Color filter settings
|
|
46
|
+
- dynamicFilter: Dynamic filter settings (type and val attributes)
|
|
47
|
+
- top10: Top 10 filter settings (top, percent, and val attributes)
|
|
48
|
+
- sortState: Sort state settings (columnOffset and order attributes)
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
auto_filter (AutoFilter): The AutoFilter object to format.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
str: XML representation of the auto filter settings.
|
|
55
|
+
"""
|
|
56
|
+
xml = f' <autoFilter ref="{auto_filter.range}">\n'
|
|
57
|
+
|
|
58
|
+
# Write filter columns
|
|
59
|
+
for col_id, filter_col in sorted(auto_filter.filter_columns.items()):
|
|
60
|
+
xml += f' <filterColumn colId="{col_id}"'
|
|
61
|
+
|
|
62
|
+
# Add hiddenButton attribute if filter button is hidden
|
|
63
|
+
if not filter_col.filter_button:
|
|
64
|
+
xml += ' hiddenButton="1"'
|
|
65
|
+
|
|
66
|
+
# Check if this column has any filters
|
|
67
|
+
has_filters = (len(filter_col.filters) > 0 or
|
|
68
|
+
len(filter_col.custom_filters) > 0 or
|
|
69
|
+
filter_col.color_filter is not None or
|
|
70
|
+
filter_col.dynamic_filter is not None or
|
|
71
|
+
filter_col.top10_filter is not None)
|
|
72
|
+
|
|
73
|
+
if not has_filters:
|
|
74
|
+
xml += '/>\n'
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
xml += '>\n'
|
|
78
|
+
|
|
79
|
+
# Write filters (value filters)
|
|
80
|
+
if len(filter_col.filters) > 0:
|
|
81
|
+
xml += f' <filters>\n'
|
|
82
|
+
for filter_value in filter_col.filters:
|
|
83
|
+
escaped_value = self._escape_xml(str(filter_value))
|
|
84
|
+
xml += f' <filter val="{escaped_value}"/>\n'
|
|
85
|
+
xml += f' </filters>\n'
|
|
86
|
+
|
|
87
|
+
# Write custom filters
|
|
88
|
+
if len(filter_col.custom_filters) > 0:
|
|
89
|
+
xml += f' <customFilters>\n'
|
|
90
|
+
for operator, value in filter_col.custom_filters:
|
|
91
|
+
escaped_value = self._escape_xml(str(value))
|
|
92
|
+
xml += f' <customFilter operator="{operator}" val="{escaped_value}"/>\n'
|
|
93
|
+
xml += f' </customFilters>\n'
|
|
94
|
+
|
|
95
|
+
# Write color filter
|
|
96
|
+
if filter_col.color_filter is not None:
|
|
97
|
+
color_data = filter_col.color_filter
|
|
98
|
+
cell_color_attr = ' cellColor="1"' if color_data['cell_color'] else ' cellColor="0"'
|
|
99
|
+
xml += f' <colorFilter rgb="{color_data["color"]}"{cell_color_attr}/>\n'
|
|
100
|
+
|
|
101
|
+
# Write dynamic filter
|
|
102
|
+
if filter_col.dynamic_filter is not None:
|
|
103
|
+
dynamic_data = filter_col.dynamic_filter
|
|
104
|
+
xml += f' <dynamicFilter type="{dynamic_data["type"]}"'
|
|
105
|
+
if dynamic_data['value'] is not None:
|
|
106
|
+
escaped_value = self._escape_xml(str(dynamic_data['value']))
|
|
107
|
+
xml += f' val="{escaped_value}"'
|
|
108
|
+
xml += '/>\n'
|
|
109
|
+
|
|
110
|
+
# Write top10 filter
|
|
111
|
+
if filter_col.top10_filter is not None:
|
|
112
|
+
top10_data = filter_col.top10_filter
|
|
113
|
+
top_attr = ' top="1"' if top10_data['top'] else ' top="0"'
|
|
114
|
+
percent_attr = ' percent="1"' if top10_data['percent'] else ' percent="0"'
|
|
115
|
+
xml += f' <top10{top_attr}{percent_attr} val="{top10_data["val"]}"/>\n'
|
|
116
|
+
|
|
117
|
+
xml += f' </filterColumn>\n'
|
|
118
|
+
|
|
119
|
+
# Write sort state (ECMA-376 Section 18.3.1.92)
|
|
120
|
+
if auto_filter.sort_state is not None and auto_filter.range is not None:
|
|
121
|
+
sort_data = auto_filter.sort_state
|
|
122
|
+
# Calculate sortState ref and sortCondition ref from autoFilter range
|
|
123
|
+
sort_state_ref, sort_condition_ref = self._calculate_sort_refs(
|
|
124
|
+
auto_filter.range, sort_data.get('column_index', 0)
|
|
125
|
+
)
|
|
126
|
+
xml += f' <sortState ref="{sort_state_ref}">\n'
|
|
127
|
+
# Build sortCondition with ref attribute
|
|
128
|
+
descending_attr = ' descending="1"' if sort_data.get('descending', False) else ''
|
|
129
|
+
xml += f' <sortCondition ref="{sort_condition_ref}"{descending_attr}/>\n'
|
|
130
|
+
xml += f' </sortState>\n'
|
|
131
|
+
|
|
132
|
+
xml += f' </autoFilter>\n'
|
|
133
|
+
|
|
134
|
+
return xml
|
|
135
|
+
|
|
136
|
+
def _calculate_sort_refs(self, filter_range, column_index):
|
|
137
|
+
"""
|
|
138
|
+
Calculates sortState ref and sortCondition ref from autoFilter range.
|
|
139
|
+
|
|
140
|
+
According to ECMA-376:
|
|
141
|
+
- sortState ref: The data range being sorted (excludes header row)
|
|
142
|
+
- sortCondition ref: The specific column range being sorted
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
filter_range (str): The autoFilter range (e.g., "A1:D10")
|
|
146
|
+
column_index (int): Zero-based column index within the filter range
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
tuple: (sort_state_ref, sort_condition_ref)
|
|
150
|
+
"""
|
|
151
|
+
from .cells import Cells
|
|
152
|
+
|
|
153
|
+
# Parse the filter range
|
|
154
|
+
if ':' in filter_range:
|
|
155
|
+
start_ref, end_ref = filter_range.split(':')
|
|
156
|
+
else:
|
|
157
|
+
start_ref = end_ref = filter_range
|
|
158
|
+
|
|
159
|
+
start_row, start_col = Cells.coordinate_from_string(start_ref)
|
|
160
|
+
end_row, end_col = Cells.coordinate_from_string(end_ref)
|
|
161
|
+
|
|
162
|
+
# sortState ref excludes header row (start from row after header)
|
|
163
|
+
data_start_row = start_row + 1
|
|
164
|
+
start_col_letter = Cells.column_letter_from_index(start_col)
|
|
165
|
+
end_col_letter = Cells.column_letter_from_index(end_col)
|
|
166
|
+
sort_state_ref = f"{start_col_letter}{data_start_row}:{end_col_letter}{end_row}"
|
|
167
|
+
|
|
168
|
+
# sortCondition ref is for the specific column being sorted
|
|
169
|
+
sort_col = start_col + column_index
|
|
170
|
+
sort_col_letter = Cells.column_letter_from_index(sort_col)
|
|
171
|
+
sort_condition_ref = f"{sort_col_letter}{data_start_row}:{sort_col_letter}{end_row}"
|
|
172
|
+
|
|
173
|
+
return sort_state_ref, sort_condition_ref
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Aspose.Cells for Python - XML Conditional Formatting Loader Module
|
|
3
|
+
|
|
4
|
+
This module provides the ConditionalFormatXMLLoader class which handles loading
|
|
5
|
+
conditional formatting data from XML format according to ECMA-376 specification.
|
|
6
|
+
|
|
7
|
+
ECMA-376 Section 18.3.1.18 defines the conditionalFormatting element structure.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConditionalFormatXMLLoader:
|
|
12
|
+
"""
|
|
13
|
+
Handles loading conditional formatting data from XML format for .xlsx files.
|
|
14
|
+
|
|
15
|
+
The ConditionalFormatXMLLoader class is responsible for parsing the XML
|
|
16
|
+
representation of conditional formatting rules including cell value rules,
|
|
17
|
+
text rules, date rules, formula rules, color scales, data bars, icon sets,
|
|
18
|
+
and more.
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
>>> loader = ConditionalFormatXMLLoader(namespaces, workbook)
|
|
22
|
+
>>> loader.load_conditional_formatting(worksheet, worksheet_root)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, namespaces, workbook):
|
|
26
|
+
"""
|
|
27
|
+
Initializes a new instance of the ConditionalFormatXMLLoader class.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
namespaces: XML namespaces dictionary for parsing.
|
|
31
|
+
workbook: The workbook instance for accessing dxf styles.
|
|
32
|
+
"""
|
|
33
|
+
self.ns = namespaces
|
|
34
|
+
self.workbook = workbook
|
|
35
|
+
|
|
36
|
+
def load_conditional_formatting(self, worksheet, worksheet_root):
|
|
37
|
+
"""
|
|
38
|
+
Loads conditional formatting from worksheet XML according to ECMA-376 specification.
|
|
39
|
+
|
|
40
|
+
ECMA-376 Section 18.3.1.18 defines the conditionalFormatting element and its children:
|
|
41
|
+
- conditionalFormatting: Main element with sqref attribute
|
|
42
|
+
- cfRule: Individual conditional formatting rule
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
worksheet (Worksheet): The worksheet object to load data into.
|
|
46
|
+
worksheet_root: The XML root element of the worksheet.
|
|
47
|
+
"""
|
|
48
|
+
from .conditional_format import ConditionalFormat
|
|
49
|
+
|
|
50
|
+
# Find all conditionalFormatting elements
|
|
51
|
+
cf_elements = worksheet_root.findall('.//main:conditionalFormatting', namespaces=self.ns)
|
|
52
|
+
|
|
53
|
+
for cf_elem in cf_elements:
|
|
54
|
+
sqref = cf_elem.get('sqref')
|
|
55
|
+
if not sqref:
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
# Load each cfRule within this conditionalFormatting element
|
|
59
|
+
for rule_elem in cf_elem.findall('main:cfRule', namespaces=self.ns):
|
|
60
|
+
cf = ConditionalFormat()
|
|
61
|
+
cf._range = sqref
|
|
62
|
+
|
|
63
|
+
# Parse rule attributes
|
|
64
|
+
rule_type = rule_elem.get('type')
|
|
65
|
+
cf._type = rule_type
|
|
66
|
+
|
|
67
|
+
# Parse priority
|
|
68
|
+
priority = rule_elem.get('priority')
|
|
69
|
+
if priority:
|
|
70
|
+
cf._priority = int(priority)
|
|
71
|
+
|
|
72
|
+
# Parse stopIfTrue
|
|
73
|
+
stop_if_true = rule_elem.get('stopIfTrue')
|
|
74
|
+
cf._stop_if_true = stop_if_true == '1'
|
|
75
|
+
|
|
76
|
+
# Parse dxfId for loading formatting later
|
|
77
|
+
dxf_id = rule_elem.get('dxfId')
|
|
78
|
+
if dxf_id:
|
|
79
|
+
cf._dxf_id = int(dxf_id)
|
|
80
|
+
|
|
81
|
+
# Parse operator for cellIs type
|
|
82
|
+
operator = rule_elem.get('operator')
|
|
83
|
+
if operator:
|
|
84
|
+
cf._operator = operator
|
|
85
|
+
|
|
86
|
+
# Parse text attribute for text-based rules
|
|
87
|
+
text = rule_elem.get('text')
|
|
88
|
+
if text:
|
|
89
|
+
cf._formula1 = text
|
|
90
|
+
|
|
91
|
+
# Parse timePeriod attribute
|
|
92
|
+
time_period = rule_elem.get('timePeriod')
|
|
93
|
+
if time_period:
|
|
94
|
+
cf._operator = time_period
|
|
95
|
+
|
|
96
|
+
# Parse top10 attributes
|
|
97
|
+
if rule_type == 'top10':
|
|
98
|
+
bottom = rule_elem.get('bottom')
|
|
99
|
+
cf._top = bottom != '1'
|
|
100
|
+
percent = rule_elem.get('percent')
|
|
101
|
+
cf._percent = percent == '1'
|
|
102
|
+
rank = rule_elem.get('rank')
|
|
103
|
+
if rank:
|
|
104
|
+
cf._rank = int(rank)
|
|
105
|
+
|
|
106
|
+
# Parse aboveAverage attributes
|
|
107
|
+
if rule_type == 'aboveAverage':
|
|
108
|
+
above_average = rule_elem.get('aboveAverage', '1')
|
|
109
|
+
cf._above = above_average != '0'
|
|
110
|
+
std_dev = rule_elem.get('stdDev')
|
|
111
|
+
if std_dev:
|
|
112
|
+
cf._std_dev = int(std_dev)
|
|
113
|
+
|
|
114
|
+
# Parse formula elements based on rule type
|
|
115
|
+
formula_elems = rule_elem.findall('main:formula', namespaces=self.ns)
|
|
116
|
+
if rule_type == 'expression':
|
|
117
|
+
# Expression rules store formula in _formula property
|
|
118
|
+
if len(formula_elems) > 0 and formula_elems[0].text:
|
|
119
|
+
cf._formula = formula_elems[0].text
|
|
120
|
+
elif rule_type == 'cellIs':
|
|
121
|
+
# Cell value rules use _formula1 and _formula2
|
|
122
|
+
if len(formula_elems) > 0 and formula_elems[0].text:
|
|
123
|
+
cf._formula1 = formula_elems[0].text
|
|
124
|
+
if len(formula_elems) > 1 and formula_elems[1].text:
|
|
125
|
+
cf._formula2 = formula_elems[1].text
|
|
126
|
+
elif rule_type in ('containsText', 'notContainsText', 'beginsWith', 'endsWith'):
|
|
127
|
+
# Text rules: the text attribute is already parsed above
|
|
128
|
+
# The formula element contains the Excel formula, not the text value
|
|
129
|
+
# We use the text attribute value which was set earlier
|
|
130
|
+
pass
|
|
131
|
+
else:
|
|
132
|
+
# Default: store in _formula1
|
|
133
|
+
if len(formula_elems) > 0 and formula_elems[0].text:
|
|
134
|
+
cf._formula1 = formula_elems[0].text
|
|
135
|
+
if len(formula_elems) > 1 and formula_elems[1].text:
|
|
136
|
+
cf._formula2 = formula_elems[1].text
|
|
137
|
+
|
|
138
|
+
# Parse colorScale element
|
|
139
|
+
color_scale_elem = rule_elem.find('main:colorScale', namespaces=self.ns)
|
|
140
|
+
if color_scale_elem is not None:
|
|
141
|
+
self._load_color_scale(cf, color_scale_elem)
|
|
142
|
+
|
|
143
|
+
# Parse dataBar element
|
|
144
|
+
data_bar_elem = rule_elem.find('main:dataBar', namespaces=self.ns)
|
|
145
|
+
if data_bar_elem is not None:
|
|
146
|
+
self._load_data_bar(cf, data_bar_elem)
|
|
147
|
+
|
|
148
|
+
# Parse iconSet element
|
|
149
|
+
icon_set_elem = rule_elem.find('main:iconSet', namespaces=self.ns)
|
|
150
|
+
if icon_set_elem is not None:
|
|
151
|
+
self._load_icon_set(cf, icon_set_elem)
|
|
152
|
+
|
|
153
|
+
# Add to worksheet's conditional formats
|
|
154
|
+
worksheet.conditional_formats._formats.append(cf)
|
|
155
|
+
|
|
156
|
+
# Load dxf formatting and apply to conditional formats
|
|
157
|
+
self._apply_dxf_to_conditional_formats(worksheet)
|
|
158
|
+
|
|
159
|
+
def _load_color_scale(self, cf, color_scale_elem):
|
|
160
|
+
"""Loads colorScale element data into conditional format."""
|
|
161
|
+
# Get cfvo elements to determine if 2-color or 3-color
|
|
162
|
+
cfvo_elems = color_scale_elem.findall('main:cfvo', namespaces=self.ns)
|
|
163
|
+
cf._color_scale_type = '3-color' if len(cfvo_elems) >= 3 else '2-color'
|
|
164
|
+
|
|
165
|
+
# Get color elements
|
|
166
|
+
color_elems = color_scale_elem.findall('main:color', namespaces=self.ns)
|
|
167
|
+
if len(color_elems) >= 1:
|
|
168
|
+
cf._min_color = color_elems[0].get('rgb')
|
|
169
|
+
if len(color_elems) >= 3:
|
|
170
|
+
cf._mid_color = color_elems[1].get('rgb')
|
|
171
|
+
cf._max_color = color_elems[2].get('rgb')
|
|
172
|
+
elif len(color_elems) >= 2:
|
|
173
|
+
cf._max_color = color_elems[1].get('rgb')
|
|
174
|
+
|
|
175
|
+
def _load_data_bar(self, cf, data_bar_elem):
|
|
176
|
+
"""Loads dataBar element data into conditional format."""
|
|
177
|
+
# Get color element
|
|
178
|
+
color_elem = data_bar_elem.find('main:color', namespaces=self.ns)
|
|
179
|
+
if color_elem is not None:
|
|
180
|
+
cf._bar_color = color_elem.get('rgb')
|
|
181
|
+
|
|
182
|
+
def _load_icon_set(self, cf, icon_set_elem):
|
|
183
|
+
"""Loads iconSet element data into conditional format."""
|
|
184
|
+
cf._icon_set_type = icon_set_elem.get('iconSet', '3TrafficLights1')
|
|
185
|
+
cf._reverse_icons = icon_set_elem.get('reverse') == '1'
|
|
186
|
+
cf._show_icon_only = icon_set_elem.get('showValue') == '0'
|
|
187
|
+
|
|
188
|
+
def _apply_dxf_to_conditional_formats(self, worksheet):
|
|
189
|
+
"""Applies differential formatting (dxf) to conditional formats."""
|
|
190
|
+
# dxf styles are stored in workbook._dxf_styles after loading styles.xml
|
|
191
|
+
if not hasattr(self.workbook, '_dxf_styles') or not self.workbook._dxf_styles:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
for cf in worksheet.conditional_formats:
|
|
195
|
+
if hasattr(cf, '_dxf_id') and cf._dxf_id is not None:
|
|
196
|
+
if cf._dxf_id < len(self.workbook._dxf_styles):
|
|
197
|
+
dxf_data = self.workbook._dxf_styles[cf._dxf_id]
|
|
198
|
+
self._apply_dxf_data_to_cf(cf, dxf_data)
|
|
199
|
+
|
|
200
|
+
def _apply_dxf_data_to_cf(self, cf, dxf_data):
|
|
201
|
+
"""Applies dxf data to a conditional format."""
|
|
202
|
+
if 'font' in dxf_data:
|
|
203
|
+
font = dxf_data['font']
|
|
204
|
+
cf._font.bold = font.get('bold', False)
|
|
205
|
+
cf._font.italic = font.get('italic', False)
|
|
206
|
+
cf._font.underline = font.get('underline', False)
|
|
207
|
+
cf._font.strikethrough = font.get('strikethrough', False)
|
|
208
|
+
if 'color' in font:
|
|
209
|
+
cf._font.color = font['color']
|
|
210
|
+
|
|
211
|
+
if 'fill' in dxf_data:
|
|
212
|
+
fill = dxf_data['fill']
|
|
213
|
+
cf._fill.pattern_type = fill.get('pattern_type', 'solid')
|
|
214
|
+
cf._fill.foreground_color = fill.get('fg_color', 'FFFFFFFF')
|
|
215
|
+
cf._fill.background_color = fill.get('bg_color', 'FFFFFFFF')
|