1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# Copyright (c) 2010-2024 openpyxl
from copy import copy
from .numbers import (
BUILTIN_FORMATS,
BUILTIN_FORMATS_MAX_SIZE,
BUILTIN_FORMATS_REVERSE,
)
from .proxy import StyleProxy
from .cell_style import StyleArray
from .named_styles import NamedStyle
from .builtins import styles
class StyleDescriptor:
def __init__(self, collection, key):
self.collection = collection
self.key = key
def __set__(self, instance, value):
coll = getattr(instance.parent.parent, self.collection)
if not getattr(instance, "_style"):
instance._style = StyleArray()
setattr(instance._style, self.key, coll.add(value))
def __get__(self, instance, cls):
coll = getattr(instance.parent.parent, self.collection)
if not getattr(instance, "_style"):
instance._style = StyleArray()
idx = getattr(instance._style, self.key)
return StyleProxy(coll[idx])
class NumberFormatDescriptor:
key = "numFmtId"
collection = '_number_formats'
def __set__(self, instance, value):
coll = getattr(instance.parent.parent, self.collection)
if value in BUILTIN_FORMATS_REVERSE:
idx = BUILTIN_FORMATS_REVERSE[value]
else:
idx = coll.add(value) + BUILTIN_FORMATS_MAX_SIZE
if not getattr(instance, "_style"):
instance._style = StyleArray()
setattr(instance._style, self.key, idx)
def __get__(self, instance, cls):
if not getattr(instance, "_style"):
instance._style = StyleArray()
idx = getattr(instance._style, self.key)
if idx < BUILTIN_FORMATS_MAX_SIZE:
return BUILTIN_FORMATS.get(idx, "General")
coll = getattr(instance.parent.parent, self.collection)
return coll[idx - BUILTIN_FORMATS_MAX_SIZE]
class NamedStyleDescriptor:
key = "xfId"
collection = "_named_styles"
def __set__(self, instance, value):
if not getattr(instance, "_style"):
instance._style = StyleArray()
coll = getattr(instance.parent.parent, self.collection)
if isinstance(value, NamedStyle):
style = value
if style not in coll:
instance.parent.parent.add_named_style(style)
elif value not in coll.names:
if value in styles: # is it builtin?
style = styles[value]
if style not in coll:
instance.parent.parent.add_named_style(style)
else:
raise ValueError("{0} is not a known style".format(value))
else:
style = coll[value]
instance._style = copy(style.as_tuple())
def __get__(self, instance, cls):
if not getattr(instance, "_style"):
instance._style = StyleArray()
idx = getattr(instance._style, self.key)
coll = getattr(instance.parent.parent, self.collection)
return coll.names[idx]
class StyleArrayDescriptor:
def __init__(self, key):
self.key = key
def __set__(self, instance, value):
if instance._style is None:
instance._style = StyleArray()
setattr(instance._style, self.key, value)
def __get__(self, instance, cls):
if instance._style is None:
return False
return bool(getattr(instance._style, self.key))
class StyleableObject:
"""
Base class for styleble objects implementing proxy and lookup functions
"""
font = StyleDescriptor('_fonts', "fontId")
fill = StyleDescriptor('_fills', "fillId")
border = StyleDescriptor('_borders', "borderId")
number_format = NumberFormatDescriptor()
protection = StyleDescriptor('_protections', "protectionId")
alignment = StyleDescriptor('_alignments', "alignmentId")
style = NamedStyleDescriptor()
quotePrefix = StyleArrayDescriptor('quotePrefix')
pivotButton = StyleArrayDescriptor('pivotButton')
__slots__ = ('parent', '_style')
def __init__(self, sheet, style_array=None):
self.parent = sheet
if style_array is not None:
style_array = StyleArray(style_array)
self._style = style_array
@property
def style_id(self):
if self._style is None:
self._style = StyleArray()
return self.parent.parent._cell_styles.add(self._style)
@property
def has_style(self):
if self._style is None:
return False
return any(self._style)
|