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
|
|
|
|
"""Section-related custom element classes"""
|
|
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
from copy import deepcopy
|
|
|
|
from docx.enum.section import WD_HEADER_FOOTER, WD_ORIENTATION, WD_SECTION_START
|
|
from docx.oxml.simpletypes import ST_SignedTwipsMeasure, ST_TwipsMeasure, XsdString
|
|
from docx.oxml.xmlchemy import (
|
|
BaseOxmlElement,
|
|
OptionalAttribute,
|
|
RequiredAttribute,
|
|
ZeroOrMore,
|
|
ZeroOrOne,
|
|
)
|
|
|
|
|
|
class CT_HdrFtr(BaseOxmlElement):
|
|
"""`w:hdr` and `w:ftr`, the root element for header and footer part respectively"""
|
|
|
|
p = ZeroOrMore('w:p', successors=())
|
|
tbl = ZeroOrMore('w:tbl', successors=())
|
|
|
|
|
|
class CT_HdrFtrRef(BaseOxmlElement):
|
|
"""`w:headerReference` and `w:footerReference` elements"""
|
|
|
|
type_ = RequiredAttribute('w:type', WD_HEADER_FOOTER)
|
|
rId = RequiredAttribute('r:id', XsdString)
|
|
|
|
|
|
class CT_PageMar(BaseOxmlElement):
|
|
"""
|
|
``<w:pgMar>`` element, defining page margins.
|
|
"""
|
|
top = OptionalAttribute('w:top', ST_SignedTwipsMeasure)
|
|
right = OptionalAttribute('w:right', ST_TwipsMeasure)
|
|
bottom = OptionalAttribute('w:bottom', ST_SignedTwipsMeasure)
|
|
left = OptionalAttribute('w:left', ST_TwipsMeasure)
|
|
header = OptionalAttribute('w:header', ST_TwipsMeasure)
|
|
footer = OptionalAttribute('w:footer', ST_TwipsMeasure)
|
|
gutter = OptionalAttribute('w:gutter', ST_TwipsMeasure)
|
|
|
|
|
|
class CT_PageSz(BaseOxmlElement):
|
|
"""
|
|
``<w:pgSz>`` element, defining page dimensions and orientation.
|
|
"""
|
|
w = OptionalAttribute('w:w', ST_TwipsMeasure)
|
|
h = OptionalAttribute('w:h', ST_TwipsMeasure)
|
|
orient = OptionalAttribute(
|
|
'w:orient', WD_ORIENTATION, default=WD_ORIENTATION.PORTRAIT
|
|
)
|
|
|
|
|
|
class CT_SectPr(BaseOxmlElement):
|
|
"""`w:sectPr` element, the container element for section properties"""
|
|
|
|
_tag_seq = (
|
|
'w:footnotePr', 'w:endnotePr', 'w:type', 'w:pgSz', 'w:pgMar', 'w:paperSrc',
|
|
'w:pgBorders', 'w:lnNumType', 'w:pgNumType', 'w:cols', 'w:formProt', 'w:vAlign',
|
|
'w:noEndnote', 'w:titlePg', 'w:textDirection', 'w:bidi', 'w:rtlGutter',
|
|
'w:docGrid', 'w:printerSettings', 'w:sectPrChange',
|
|
)
|
|
headerReference = ZeroOrMore("w:headerReference", successors=_tag_seq)
|
|
footerReference = ZeroOrMore("w:footerReference", successors=_tag_seq)
|
|
type = ZeroOrOne("w:type", successors=_tag_seq[3:])
|
|
pgSz = ZeroOrOne("w:pgSz", successors=_tag_seq[4:])
|
|
pgMar = ZeroOrOne("w:pgMar", successors=_tag_seq[5:])
|
|
titlePg = ZeroOrOne("w:titlePg", successors=_tag_seq[14:])
|
|
del _tag_seq
|
|
|
|
def add_footerReference(self, type_, rId):
|
|
"""Return newly added CT_HdrFtrRef element of *type_* with *rId*.
|
|
|
|
The element tag is `w:footerReference`.
|
|
"""
|
|
footerReference = self._add_footerReference()
|
|
footerReference.type_ = type_
|
|
footerReference.rId = rId
|
|
return footerReference
|
|
|
|
def add_headerReference(self, type_, rId):
|
|
"""Return newly added CT_HdrFtrRef element of *type_* with *rId*.
|
|
|
|
The element tag is `w:headerReference`.
|
|
"""
|
|
headerReference = self._add_headerReference()
|
|
headerReference.type_ = type_
|
|
headerReference.rId = rId
|
|
return headerReference
|
|
|
|
@property
|
|
def bottom_margin(self):
|
|
"""
|
|
The value of the ``w:bottom`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.bottom
|
|
|
|
@bottom_margin.setter
|
|
def bottom_margin(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.bottom = value
|
|
|
|
def clone(self):
|
|
"""
|
|
Return an exact duplicate of this ``<w:sectPr>`` element tree
|
|
suitable for use in adding a section break. All rsid* attributes are
|
|
removed from the root ``<w:sectPr>`` element.
|
|
"""
|
|
clone_sectPr = deepcopy(self)
|
|
clone_sectPr.attrib.clear()
|
|
return clone_sectPr
|
|
|
|
@property
|
|
def footer(self):
|
|
"""
|
|
The value of the ``w:footer`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.footer
|
|
|
|
@footer.setter
|
|
def footer(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.footer = value
|
|
|
|
def get_footerReference(self, type_):
|
|
"""Return footerReference element of *type_* or None if not present."""
|
|
path = "./w:footerReference[@w:type='%s']" % WD_HEADER_FOOTER.to_xml(type_)
|
|
footerReferences = self.xpath(path)
|
|
if not footerReferences:
|
|
return None
|
|
return footerReferences[0]
|
|
|
|
def get_headerReference(self, type_):
|
|
"""Return headerReference element of *type_* or None if not present."""
|
|
matching_headerReferences = self.xpath(
|
|
"./w:headerReference[@w:type='%s']" % WD_HEADER_FOOTER.to_xml(type_)
|
|
)
|
|
if len(matching_headerReferences) == 0:
|
|
return None
|
|
return matching_headerReferences[0]
|
|
|
|
@property
|
|
def gutter(self):
|
|
"""
|
|
The value of the ``w:gutter`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.gutter
|
|
|
|
@gutter.setter
|
|
def gutter(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.gutter = value
|
|
|
|
@property
|
|
def header(self):
|
|
"""
|
|
The value of the ``w:header`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.header
|
|
|
|
@header.setter
|
|
def header(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.header = value
|
|
|
|
@property
|
|
def left_margin(self):
|
|
"""
|
|
The value of the ``w:left`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.left
|
|
|
|
@left_margin.setter
|
|
def left_margin(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.left = value
|
|
|
|
@property
|
|
def orientation(self):
|
|
"""
|
|
The member of the ``WD_ORIENTATION`` enumeration corresponding to the
|
|
value of the ``orient`` attribute of the ``<w:pgSz>`` child element,
|
|
or ``WD_ORIENTATION.PORTRAIT`` if not present.
|
|
"""
|
|
pgSz = self.pgSz
|
|
if pgSz is None:
|
|
return WD_ORIENTATION.PORTRAIT
|
|
return pgSz.orient
|
|
|
|
@orientation.setter
|
|
def orientation(self, value):
|
|
pgSz = self.get_or_add_pgSz()
|
|
pgSz.orient = value
|
|
|
|
@property
|
|
def page_height(self):
|
|
"""
|
|
Value in EMU of the ``h`` attribute of the ``<w:pgSz>`` child
|
|
element, or |None| if not present.
|
|
"""
|
|
pgSz = self.pgSz
|
|
if pgSz is None:
|
|
return None
|
|
return pgSz.h
|
|
|
|
@page_height.setter
|
|
def page_height(self, value):
|
|
pgSz = self.get_or_add_pgSz()
|
|
pgSz.h = value
|
|
|
|
@property
|
|
def page_width(self):
|
|
"""
|
|
Value in EMU of the ``w`` attribute of the ``<w:pgSz>`` child
|
|
element, or |None| if not present.
|
|
"""
|
|
pgSz = self.pgSz
|
|
if pgSz is None:
|
|
return None
|
|
return pgSz.w
|
|
|
|
@page_width.setter
|
|
def page_width(self, value):
|
|
pgSz = self.get_or_add_pgSz()
|
|
pgSz.w = value
|
|
|
|
@property
|
|
def preceding_sectPr(self):
|
|
"""sectPr immediately preceding this one or None if this is the first."""
|
|
# ---[1] predicate returns list of zero or one value---
|
|
preceding_sectPrs = self.xpath("./preceding::w:sectPr[1]")
|
|
return preceding_sectPrs[0] if len(preceding_sectPrs) > 0 else None
|
|
|
|
def remove_footerReference(self, type_):
|
|
"""Return rId of w:footerReference child of *type_* after removing it."""
|
|
footerReference = self.get_footerReference(type_)
|
|
rId = footerReference.rId
|
|
self.remove(footerReference)
|
|
return rId
|
|
|
|
def remove_headerReference(self, type_):
|
|
"""Return rId of w:headerReference child of *type_* after removing it."""
|
|
headerReference = self.get_headerReference(type_)
|
|
rId = headerReference.rId
|
|
self.remove(headerReference)
|
|
return rId
|
|
|
|
@property
|
|
def right_margin(self):
|
|
"""
|
|
The value of the ``w:right`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.right
|
|
|
|
@right_margin.setter
|
|
def right_margin(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.right = value
|
|
|
|
@property
|
|
def start_type(self):
|
|
"""
|
|
The member of the ``WD_SECTION_START`` enumeration corresponding to
|
|
the value of the ``val`` attribute of the ``<w:type>`` child element,
|
|
or ``WD_SECTION_START.NEW_PAGE`` if not present.
|
|
"""
|
|
type = self.type
|
|
if type is None or type.val is None:
|
|
return WD_SECTION_START.NEW_PAGE
|
|
return type.val
|
|
|
|
@start_type.setter
|
|
def start_type(self, value):
|
|
if value is None or value is WD_SECTION_START.NEW_PAGE:
|
|
self._remove_type()
|
|
return
|
|
type = self.get_or_add_type()
|
|
type.val = value
|
|
|
|
@property
|
|
def titlePg_val(self):
|
|
"""Value of `w:titlePg/@val` or |None| if not present"""
|
|
titlePg = self.titlePg
|
|
if titlePg is None:
|
|
return False
|
|
return titlePg.val
|
|
|
|
@titlePg_val.setter
|
|
def titlePg_val(self, value):
|
|
if value in [None, False]:
|
|
self._remove_titlePg()
|
|
else:
|
|
self.get_or_add_titlePg().val = value
|
|
|
|
@property
|
|
def top_margin(self):
|
|
"""
|
|
The value of the ``w:top`` attribute in the ``<w:pgMar>`` child
|
|
element, as a |Length| object, or |None| if either the element or the
|
|
attribute is not present.
|
|
"""
|
|
pgMar = self.pgMar
|
|
if pgMar is None:
|
|
return None
|
|
return pgMar.top
|
|
|
|
@top_margin.setter
|
|
def top_margin(self, value):
|
|
pgMar = self.get_or_add_pgMar()
|
|
pgMar.top = value
|
|
|
|
|
|
class CT_SectType(BaseOxmlElement):
|
|
"""
|
|
``<w:sectType>`` element, defining the section start type.
|
|
"""
|
|
val = OptionalAttribute('w:val', WD_SECTION_START)
|