Skip to content

Commit 26d0f0e

Browse files
eupharisSteve Canny
authored andcommitted
hdr: add _BaseHeaderFooter.is_linked_to_previous
1 parent b14766c commit 26d0f0e

File tree

9 files changed

+155
-22
lines changed

9 files changed

+155
-22
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.. _WdHeaderFooterIndex:
2+
3+
``WD_HEADER_FOOTER_INDEX``
4+
==========================
5+
6+
alias: **WD_HEADER_FOOTER**
7+
8+
Specifies the type of a header or footer.
9+
10+
----
11+
12+
PRIMARY
13+
The header or footer appearing on all pages except when an even and/or
14+
first-page header/footer is defined.
15+
16+
FIRST_PAGE
17+
The header or footer appearing only on the first page of the specified
18+
section.
19+
20+
EVEN_PAGES
21+
The header or footer appearing on even numbered (verso) pages in the
22+
specified section.

docs/api/enum/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ can be found here:
1313
WdAlignParagraph
1414
WdBuiltinStyle
1515
WdColorIndex
16+
WdHeaderFooterIndex
1617
WdLineSpacing
1718
WdOrientation
1819
WdSectionStart

docx/enum/header.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Enumerations related to headers and footers
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, print_function, unicode_literals, division
9+
)
10+
11+
from .base import alias, XmlEnumeration, XmlMappedEnumMember
12+
13+
14+
@alias('WD_HEADER_FOOTER')
15+
class WD_HEADER_FOOTER_INDEX(XmlEnumeration):
16+
"""
17+
alias: **WD_HEADER_FOOTER**
18+
19+
Specifies the type of a header or footer.
20+
"""
21+
22+
__ms_name__ = 'WdHeaderFooterIndex'
23+
24+
__url__ = 'https://msdn.microsoft.com/en-us/library/office/ff839314.aspx'
25+
26+
__members__ = (
27+
XmlMappedEnumMember(
28+
'PRIMARY', 1, 'default', 'The header or footer appearing on all '
29+
'pages except when an even and/or first-page header/footer is de'
30+
'fined.'
31+
),
32+
XmlMappedEnumMember(
33+
'FIRST_PAGE', 2, 'first', 'The header or footer appearing only o'
34+
'n the first page of the specified section.'
35+
),
36+
XmlMappedEnumMember(
37+
'EVEN_PAGES', 3, 'even', 'The header or footer appearing on even'
38+
' numbered (verso) pages in the specified section.'
39+
),
40+
)

docx/header.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,31 @@
1111
from .shared import ElementProxy
1212

1313

14-
class Header(ElementProxy):
14+
class _BaseHeaderFooter(ElementProxy):
1515
"""
16-
The default page header of a section.
16+
Base class for header and footer objects.
1717
"""
1818

19-
__slots__ = ()
19+
__slots__ = ('_sectPr', '_type')
20+
21+
def __init__(self, element, parent, type):
22+
super(_BaseHeaderFooter, self).__init__(element, parent)
23+
self._sectPr = element
24+
self._type = type
25+
26+
@property
27+
def is_linked_to_previous(self):
28+
"""
29+
Boolean representing whether this Header is inherited from
30+
a previous section.
31+
"""
32+
ref = self._sectPr.get_headerReference_of_type(self._type)
33+
if ref is None:
34+
return True
35+
return False
36+
37+
38+
class Header(_BaseHeaderFooter):
39+
"""
40+
One of the page headers for a section.
41+
"""

docx/oxml/section.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88

99
from copy import deepcopy
1010

11+
from ..enum.header import WD_HEADER_FOOTER
1112
from ..enum.section import WD_ORIENTATION, WD_SECTION_START
1213
from .simpletypes import ST_SignedTwipsMeasure, ST_TwipsMeasure
13-
from .xmlchemy import BaseOxmlElement, OptionalAttribute, ZeroOrOne
14+
from .xmlchemy import (
15+
BaseOxmlElement, OptionalAttribute, ZeroOrMore, ZeroOrOne
16+
)
1417

1518

1619
class CT_PageMar(BaseOxmlElement):
@@ -41,22 +44,18 @@ class CT_SectPr(BaseOxmlElement):
4144
"""
4245
``<w:sectPr>`` element, the container element for section properties.
4346
"""
44-
__child_sequence__ = (
45-
'w:footnotePr', 'w:endnotePr', 'w:type', 'w:pgSz', 'w:pgMar',
46-
'w:paperSrc', 'w:pgBorders', 'w:lnNumType', 'w:pgNumType', 'w:cols',
47-
'w:formProt', 'w:vAlign', 'w:noEndnote', 'w:titlePg',
48-
'w:textDirection', 'w:bidi', 'w:rtlGutter', 'w:docGrid',
49-
'w:printerSettings', 'w:sectPrChange',
47+
_tag_seq = (
48+
'w:headerReference', 'w:footerReference', 'w:footnotePr',
49+
'w:endnotePr', 'w:type', 'w:pgSz', 'w:pgMar', 'w:paperSrc',
50+
'w:pgBorders', 'w:lnNumType', 'w:pgNumType', 'w:cols', 'w:formProt',
51+
'w:vAlign', 'w:noEndnote', 'w:titlePg', 'w:textDirection', 'w:bidi',
52+
'w:rtlGutter', 'w:docGrid', 'w:printerSettings', 'w:sectPrChange',
5053
)
51-
type = ZeroOrOne('w:type', successors=(
52-
__child_sequence__[__child_sequence__.index('w:type')+1:]
53-
))
54-
pgSz = ZeroOrOne('w:pgSz', successors=(
55-
__child_sequence__[__child_sequence__.index('w:pgSz')+1:]
56-
))
57-
pgMar = ZeroOrOne('w:pgMar', successors=(
58-
__child_sequence__[__child_sequence__.index('w:pgMar')+1:]
59-
))
54+
headerReference = ZeroOrMore('w:headerReference', successors=_tag_seq[1:])
55+
type = ZeroOrOne('w:type', successors=_tag_seq[5:])
56+
pgSz = ZeroOrOne('w:pgSz', successors=_tag_seq[6:])
57+
pgMar = ZeroOrOne('w:pgMar', successors=_tag_seq[7:])
58+
del _tag_seq
6059

6160
@property
6261
def bottom_margin(self):
@@ -102,6 +101,17 @@ def footer(self, value):
102101
pgMar = self.get_or_add_pgMar()
103102
pgMar.footer = value
104103

104+
def get_headerReference_of_type(self, type_member):
105+
"""
106+
Return the `w:headerReference` child having type attribute value
107+
associated with *type_member*, or |None| if not present.
108+
"""
109+
type_str = WD_HEADER_FOOTER.to_xml(type_member)
110+
matches = self.xpath('w:headerReference[@w:type="%s"]' % type_str)
111+
if matches:
112+
return matches[0]
113+
return None
114+
105115
@property
106116
def gutter(self):
107117
"""

docx/section.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from collections import Sequence
1010

11+
from .enum.header import WD_HEADER_FOOTER
1112
from .header import Header
1213
from .shared import lazyproperty
1314

@@ -91,7 +92,7 @@ def header(self):
9192
is present or not. The header itself is added, updated, or removed
9293
using the returned object.
9394
"""
94-
return Header(self._sectPr)
95+
return Header(self._sectPr, self, WD_HEADER_FOOTER.PRIMARY)
9596

9697
@property
9798
def header_distance(self):

features/hdr-header-props.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Feature: Header properties
44
I need read/write properties on the Header object
55

66

7-
@wip
87
Scenario Outline: Get Header.is_linked_to_previous
98
Given a header <having-or-no> definition
109
Then header.is_linked_to_previous is <value>

tests/test_header.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for the docx.header module
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, print_function, unicode_literals, division
9+
)
10+
11+
import pytest
12+
13+
from docx.enum.header import WD_HEADER_FOOTER
14+
from docx.header import Header
15+
16+
from .unitutil.cxml import element
17+
18+
19+
class Describe_BaseHeaderFooter(object):
20+
21+
def it_knows_whether_it_is_linked_to_previous(self, is_linked_fixture):
22+
header, expected_value = is_linked_fixture
23+
assert header.is_linked_to_previous is expected_value
24+
25+
# fixtures -------------------------------------------------------
26+
27+
@pytest.fixture(params=[
28+
('w:sectPr', True),
29+
('w:sectPr/w:headerReference{w:type=default}', False),
30+
('w:sectPr/w:headerReference{w:type=even}', True),
31+
])
32+
def is_linked_fixture(self, request):
33+
sectPr_cxml, expected_value = request.param
34+
header = Header(element(sectPr_cxml), None, WD_HEADER_FOOTER.PRIMARY)
35+
return header, expected_value

tests/test_section.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pytest
1010

11+
from docx.enum.header import WD_HEADER_FOOTER
1112
from docx.enum.section import WD_ORIENT, WD_SECTION
1213
from docx.header import Header
1314
from docx.section import Section, Sections
@@ -114,7 +115,9 @@ def it_can_change_its_page_margins(self, margins_set_fixture):
114115
def it_provides_access_to_its_header(self, header_fixture):
115116
section, Header_, sectPr, header_ = header_fixture
116117
header = section.header
117-
Header_.assert_called_once_with(sectPr)
118+
Header_.assert_called_once_with(
119+
sectPr, section, WD_HEADER_FOOTER.PRIMARY
120+
)
118121
assert header is header_
119122

120123
# fixtures -------------------------------------------------------

0 commit comments

Comments
 (0)