You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
11 KiB
352 lines
11 KiB
# encoding: utf-8
|
|
|
|
"""
|
|
Custom element classes related to the styles part
|
|
"""
|
|
|
|
from ..enum.style import WD_STYLE_TYPE
|
|
from .simpletypes import ST_DecimalNumber, ST_OnOff, ST_String
|
|
from .xmlchemy import (
|
|
BaseOxmlElement, OptionalAttribute, RequiredAttribute, ZeroOrMore,
|
|
ZeroOrOne
|
|
)
|
|
|
|
|
|
def styleId_from_name(name):
|
|
"""
|
|
Return the style id corresponding to *name*, taking into account
|
|
special-case names such as 'Heading 1'.
|
|
"""
|
|
return {
|
|
'caption': 'Caption',
|
|
'heading 1': 'Heading1',
|
|
'heading 2': 'Heading2',
|
|
'heading 3': 'Heading3',
|
|
'heading 4': 'Heading4',
|
|
'heading 5': 'Heading5',
|
|
'heading 6': 'Heading6',
|
|
'heading 7': 'Heading7',
|
|
'heading 8': 'Heading8',
|
|
'heading 9': 'Heading9',
|
|
}.get(name, name.replace(' ', ''))
|
|
|
|
|
|
class CT_LatentStyles(BaseOxmlElement):
|
|
"""
|
|
`w:latentStyles` element, defining behavior defaults for latent styles
|
|
and containing `w:lsdException` child elements that each override those
|
|
defaults for a named latent style.
|
|
"""
|
|
lsdException = ZeroOrMore('w:lsdException', successors=())
|
|
|
|
count = OptionalAttribute('w:count', ST_DecimalNumber)
|
|
defLockedState = OptionalAttribute('w:defLockedState', ST_OnOff)
|
|
defQFormat = OptionalAttribute('w:defQFormat', ST_OnOff)
|
|
defSemiHidden = OptionalAttribute('w:defSemiHidden', ST_OnOff)
|
|
defUIPriority = OptionalAttribute('w:defUIPriority', ST_DecimalNumber)
|
|
defUnhideWhenUsed = OptionalAttribute('w:defUnhideWhenUsed', ST_OnOff)
|
|
|
|
def bool_prop(self, attr_name):
|
|
"""
|
|
Return the boolean value of the attribute having *attr_name*, or
|
|
|False| if not present.
|
|
"""
|
|
value = getattr(self, attr_name)
|
|
if value is None:
|
|
return False
|
|
return value
|
|
|
|
def get_by_name(self, name):
|
|
"""
|
|
Return the `w:lsdException` child having *name*, or |None| if not
|
|
found.
|
|
"""
|
|
found = self.xpath('w:lsdException[@w:name="%s"]' % name)
|
|
if not found:
|
|
return None
|
|
return found[0]
|
|
|
|
def set_bool_prop(self, attr_name, value):
|
|
"""
|
|
Set the on/off attribute having *attr_name* to *value*.
|
|
"""
|
|
setattr(self, attr_name, bool(value))
|
|
|
|
|
|
class CT_LsdException(BaseOxmlElement):
|
|
"""
|
|
``<w:lsdException>`` element, defining override visibility behaviors for
|
|
a named latent style.
|
|
"""
|
|
locked = OptionalAttribute('w:locked', ST_OnOff)
|
|
name = RequiredAttribute('w:name', ST_String)
|
|
qFormat = OptionalAttribute('w:qFormat', ST_OnOff)
|
|
semiHidden = OptionalAttribute('w:semiHidden', ST_OnOff)
|
|
uiPriority = OptionalAttribute('w:uiPriority', ST_DecimalNumber)
|
|
unhideWhenUsed = OptionalAttribute('w:unhideWhenUsed', ST_OnOff)
|
|
|
|
def delete(self):
|
|
"""
|
|
Remove this `w:lsdException` element from the XML document.
|
|
"""
|
|
self.getparent().remove(self)
|
|
|
|
def on_off_prop(self, attr_name):
|
|
"""
|
|
Return the boolean value of the attribute having *attr_name*, or
|
|
|None| if not present.
|
|
"""
|
|
return getattr(self, attr_name)
|
|
|
|
def set_on_off_prop(self, attr_name, value):
|
|
"""
|
|
Set the on/off attribute having *attr_name* to *value*.
|
|
"""
|
|
setattr(self, attr_name, value)
|
|
|
|
|
|
class CT_Style(BaseOxmlElement):
|
|
"""
|
|
A ``<w:style>`` element, representing a style definition
|
|
"""
|
|
_tag_seq = (
|
|
'w:name', 'w:aliases', 'w:basedOn', 'w:next', 'w:link',
|
|
'w:autoRedefine', 'w:hidden', 'w:uiPriority', 'w:semiHidden',
|
|
'w:unhideWhenUsed', 'w:qFormat', 'w:locked', 'w:personal',
|
|
'w:personalCompose', 'w:personalReply', 'w:rsid', 'w:pPr', 'w:rPr',
|
|
'w:tblPr', 'w:trPr', 'w:tcPr', 'w:tblStylePr'
|
|
)
|
|
name = ZeroOrOne('w:name', successors=_tag_seq[1:])
|
|
basedOn = ZeroOrOne('w:basedOn', successors=_tag_seq[3:])
|
|
next = ZeroOrOne('w:next', successors=_tag_seq[4:])
|
|
uiPriority = ZeroOrOne('w:uiPriority', successors=_tag_seq[8:])
|
|
semiHidden = ZeroOrOne('w:semiHidden', successors=_tag_seq[9:])
|
|
unhideWhenUsed = ZeroOrOne('w:unhideWhenUsed', successors=_tag_seq[10:])
|
|
qFormat = ZeroOrOne('w:qFormat', successors=_tag_seq[11:])
|
|
locked = ZeroOrOne('w:locked', successors=_tag_seq[12:])
|
|
pPr = ZeroOrOne('w:pPr', successors=_tag_seq[17:])
|
|
rPr = ZeroOrOne('w:rPr', successors=_tag_seq[18:])
|
|
del _tag_seq
|
|
|
|
type = OptionalAttribute('w:type', WD_STYLE_TYPE)
|
|
styleId = OptionalAttribute('w:styleId', ST_String)
|
|
default = OptionalAttribute('w:default', ST_OnOff)
|
|
customStyle = OptionalAttribute('w:customStyle', ST_OnOff)
|
|
|
|
@property
|
|
def basedOn_val(self):
|
|
"""
|
|
Value of `w:basedOn/@w:val` or |None| if not present.
|
|
"""
|
|
basedOn = self.basedOn
|
|
if basedOn is None:
|
|
return None
|
|
return basedOn.val
|
|
|
|
@basedOn_val.setter
|
|
def basedOn_val(self, value):
|
|
if value is None:
|
|
self._remove_basedOn()
|
|
else:
|
|
self.get_or_add_basedOn().val = value
|
|
|
|
@property
|
|
def base_style(self):
|
|
"""
|
|
Sibling CT_Style element this style is based on or |None| if no base
|
|
style or base style not found.
|
|
"""
|
|
basedOn = self.basedOn
|
|
if basedOn is None:
|
|
return None
|
|
styles = self.getparent()
|
|
base_style = styles.get_by_id(basedOn.val)
|
|
if base_style is None:
|
|
return None
|
|
return base_style
|
|
|
|
def delete(self):
|
|
"""
|
|
Remove this `w:style` element from its parent `w:styles` element.
|
|
"""
|
|
self.getparent().remove(self)
|
|
|
|
@property
|
|
def locked_val(self):
|
|
"""
|
|
Value of `w:locked/@w:val` or |False| if not present.
|
|
"""
|
|
locked = self.locked
|
|
if locked is None:
|
|
return False
|
|
return locked.val
|
|
|
|
@locked_val.setter
|
|
def locked_val(self, value):
|
|
self._remove_locked()
|
|
if bool(value) is True:
|
|
locked = self._add_locked()
|
|
locked.val = value
|
|
|
|
@property
|
|
def name_val(self):
|
|
"""
|
|
Value of ``<w:name>`` child or |None| if not present.
|
|
"""
|
|
name = self.name
|
|
if name is None:
|
|
return None
|
|
return name.val
|
|
|
|
@name_val.setter
|
|
def name_val(self, value):
|
|
self._remove_name()
|
|
if value is not None:
|
|
name = self._add_name()
|
|
name.val = value
|
|
|
|
@property
|
|
def next_style(self):
|
|
"""
|
|
Sibling CT_Style element identified by the value of `w:name/@w:val`
|
|
or |None| if no value is present or no style with that style id
|
|
is found.
|
|
"""
|
|
next = self.next
|
|
if next is None:
|
|
return None
|
|
styles = self.getparent()
|
|
return styles.get_by_id(next.val) # None if not found
|
|
|
|
@property
|
|
def qFormat_val(self):
|
|
"""
|
|
Value of `w:qFormat/@w:val` or |False| if not present.
|
|
"""
|
|
qFormat = self.qFormat
|
|
if qFormat is None:
|
|
return False
|
|
return qFormat.val
|
|
|
|
@qFormat_val.setter
|
|
def qFormat_val(self, value):
|
|
self._remove_qFormat()
|
|
if bool(value):
|
|
self._add_qFormat()
|
|
|
|
@property
|
|
def semiHidden_val(self):
|
|
"""
|
|
Value of ``<w:semiHidden>`` child or |False| if not present.
|
|
"""
|
|
semiHidden = self.semiHidden
|
|
if semiHidden is None:
|
|
return False
|
|
return semiHidden.val
|
|
|
|
@semiHidden_val.setter
|
|
def semiHidden_val(self, value):
|
|
self._remove_semiHidden()
|
|
if bool(value) is True:
|
|
semiHidden = self._add_semiHidden()
|
|
semiHidden.val = value
|
|
|
|
@property
|
|
def uiPriority_val(self):
|
|
"""
|
|
Value of ``<w:uiPriority>`` child or |None| if not present.
|
|
"""
|
|
uiPriority = self.uiPriority
|
|
if uiPriority is None:
|
|
return None
|
|
return uiPriority.val
|
|
|
|
@uiPriority_val.setter
|
|
def uiPriority_val(self, value):
|
|
self._remove_uiPriority()
|
|
if value is not None:
|
|
uiPriority = self._add_uiPriority()
|
|
uiPriority.val = value
|
|
|
|
@property
|
|
def unhideWhenUsed_val(self):
|
|
"""
|
|
Value of `w:unhideWhenUsed/@w:val` or |False| if not present.
|
|
"""
|
|
unhideWhenUsed = self.unhideWhenUsed
|
|
if unhideWhenUsed is None:
|
|
return False
|
|
return unhideWhenUsed.val
|
|
|
|
@unhideWhenUsed_val.setter
|
|
def unhideWhenUsed_val(self, value):
|
|
self._remove_unhideWhenUsed()
|
|
if bool(value) is True:
|
|
unhideWhenUsed = self._add_unhideWhenUsed()
|
|
unhideWhenUsed.val = value
|
|
|
|
|
|
class CT_Styles(BaseOxmlElement):
|
|
"""
|
|
``<w:styles>`` element, the root element of a styles part, i.e.
|
|
styles.xml
|
|
"""
|
|
_tag_seq = ('w:docDefaults', 'w:latentStyles', 'w:style')
|
|
latentStyles = ZeroOrOne('w:latentStyles', successors=_tag_seq[2:])
|
|
style = ZeroOrMore('w:style', successors=())
|
|
del _tag_seq
|
|
|
|
def add_style_of_type(self, name, style_type, builtin):
|
|
"""
|
|
Return a newly added `w:style` element having *name* and
|
|
*style_type*. `w:style/@customStyle` is set based on the value of
|
|
*builtin*.
|
|
"""
|
|
style = self.add_style()
|
|
style.type = style_type
|
|
style.customStyle = None if builtin else True
|
|
style.styleId = styleId_from_name(name)
|
|
style.name_val = name
|
|
return style
|
|
|
|
def default_for(self, style_type):
|
|
"""
|
|
Return `w:style[@w:type="*{style_type}*][-1]` or |None| if not found.
|
|
"""
|
|
default_styles_for_type = [
|
|
s for s in self._iter_styles()
|
|
if s.type == style_type and s.default
|
|
]
|
|
if not default_styles_for_type:
|
|
return None
|
|
# spec calls for last default in document order
|
|
return default_styles_for_type[-1]
|
|
|
|
def get_by_id(self, styleId):
|
|
"""
|
|
Return the ``<w:style>`` child element having ``styleId`` attribute
|
|
matching *styleId*, or |None| if not found.
|
|
"""
|
|
xpath = 'w:style[@w:styleId="%s"]' % styleId
|
|
try:
|
|
return self.xpath(xpath)[0]
|
|
except IndexError:
|
|
return None
|
|
|
|
def get_by_name(self, name):
|
|
"""
|
|
Return the ``<w:style>`` child element having ``<w:name>`` child
|
|
element with value *name*, or |None| if not found.
|
|
"""
|
|
xpath = 'w:style[w:name/@w:val="%s"]' % name
|
|
try:
|
|
return self.xpath(xpath)[0]
|
|
except IndexError:
|
|
return None
|
|
|
|
def _iter_styles(self):
|
|
"""
|
|
Generate each of the `w:style` child elements in document order.
|
|
"""
|
|
return (style for style in self.xpath('w:style'))
|