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

# 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'))