1# encoding: utf-8
2
3"""
4Step implementations for document-related features
5"""
6
7from __future__ import absolute_import, print_function, unicode_literals
8
9from behave import given, then, when
10
11from docx import Document
12from docx.enum.section import WD_ORIENT, WD_SECTION
13from docx.shape import InlineShapes
14from docx.shared import Inches
15from docx.section import Sections
16from docx.styles.styles import Styles
17from docx.table import Table
18from docx.text.paragraph import Paragraph
19
20from helpers import test_docx, test_file
21
22
23# given ===================================================
24
25@given('a blank document')
26def given_a_blank_document(context):
27    context.document = Document(test_docx('doc-word-default-blank'))
28
29
30@given('a document having built-in styles')
31def given_a_document_having_builtin_styles(context):
32    context.document = Document()
33
34
35@given('a document having inline shapes')
36def given_a_document_having_inline_shapes(context):
37    context.document = Document(test_docx('shp-inline-shape-access'))
38
39
40@given('a document having sections')
41def given_a_document_having_sections(context):
42    context.document = Document(test_docx('doc-access-sections'))
43
44
45@given('a document having styles')
46def given_a_document_having_styles(context):
47    context.document = Document(test_docx('sty-having-styles-part'))
48
49
50@given('a document having three tables')
51def given_a_document_having_three_tables(context):
52    context.document = Document(test_docx('tbl-having-tables'))
53
54
55@given('a single-section document having portrait layout')
56def given_a_single_section_document_having_portrait_layout(context):
57    context.document = Document(test_docx('doc-add-section'))
58    section = context.document.sections[-1]
59    context.original_dimensions = (section.page_width, section.page_height)
60
61
62@given("a single-section Document object with headers and footers as document")
63def given_a_single_section_Document_object_with_headers_and_footers(context):
64    context.document = Document(test_docx("doc-add-section"))
65
66
67# when ====================================================
68
69@when('I add a 2 x 2 table specifying only row and column count')
70def when_add_2x2_table_specifying_only_row_and_col_count(context):
71    document = context.document
72    document.add_table(rows=2, cols=2)
73
74
75@when('I add a 2 x 2 table specifying style \'{style_name}\'')
76def when_add_2x2_table_specifying_style_name(context, style_name):
77    document = context.document
78    document.add_table(rows=2, cols=2, style=style_name)
79
80
81@when('I add a heading specifying level={level}')
82def when_add_heading_specifying_level(context, level):
83    context.document.add_heading(level=int(level))
84
85
86@when('I add a heading specifying only its text')
87def when_add_heading_specifying_only_its_text(context):
88    document = context.document
89    context.heading_text = text = 'Spam vs. Eggs'
90    document.add_heading(text)
91
92
93@when('I add a page break to the document')
94def when_add_page_break_to_document(context):
95    document = context.document
96    document.add_page_break()
97
98
99@when('I add a paragraph specifying its style as a {kind}')
100def when_I_add_a_paragraph_specifying_its_style_as_a(context, kind):
101    document = context.document
102    style = context.style = document.styles['Heading 1']
103    style_spec = {
104        'style object': style,
105        'style name':   'Heading 1',
106    }[kind]
107    document.add_paragraph(style=style_spec)
108
109
110@when('I add a paragraph specifying its text')
111def when_add_paragraph_specifying_text(context):
112    document = context.document
113    context.paragraph_text = 'foobar'
114    document.add_paragraph(context.paragraph_text)
115
116
117@when('I add a paragraph without specifying text or style')
118def when_add_paragraph_without_specifying_text_or_style(context):
119    document = context.document
120    document.add_paragraph()
121
122
123@when('I add a picture specifying 1.75" width and 2.5" height')
124def when_add_picture_specifying_width_and_height(context):
125    document = context.document
126    context.picture = document.add_picture(
127        test_file('monty-truth.png'),
128        width=Inches(1.75), height=Inches(2.5)
129    )
130
131
132@when('I add a picture specifying a height of 1.5 inches')
133def when_add_picture_specifying_height(context):
134    document = context.document
135    context.picture = document.add_picture(
136        test_file('monty-truth.png'), height=Inches(1.5)
137    )
138
139
140@when('I add a picture specifying a width of 1.5 inches')
141def when_add_picture_specifying_width(context):
142    document = context.document
143    context.picture = document.add_picture(
144        test_file('monty-truth.png'), width=Inches(1.5)
145    )
146
147
148@when('I add a picture specifying only the image file')
149def when_add_picture_specifying_only_image_file(context):
150    document = context.document
151    context.picture = document.add_picture(test_file('monty-truth.png'))
152
153
154@when('I add an even-page section to the document')
155def when_I_add_an_even_page_section_to_the_document(context):
156    context.section = context.document.add_section(WD_SECTION.EVEN_PAGE)
157
158
159@when('I change the new section layout to landscape')
160def when_I_change_the_new_section_layout_to_landscape(context):
161    new_height, new_width = context.original_dimensions
162    section = context.section
163    section.orientation = WD_ORIENT.LANDSCAPE
164    section.page_width = new_width
165    section.page_height = new_height
166
167
168@when("I execute section = document.add_section()")
169def when_I_execute_section_eq_document_add_section(context):
170    context.section = context.document.add_section()
171
172
173# then ====================================================
174
175@then('document.inline_shapes is an InlineShapes object')
176def then_document_inline_shapes_is_an_InlineShapes_object(context):
177    document = context.document
178    inline_shapes = document.inline_shapes
179    assert isinstance(inline_shapes, InlineShapes)
180
181
182@then('document.paragraphs is a list containing three paragraphs')
183def then_document_paragraphs_is_a_list_containing_three_paragraphs(context):
184    document = context.document
185    paragraphs = document.paragraphs
186    assert isinstance(paragraphs, list)
187    assert len(paragraphs) == 3
188    for paragraph in paragraphs:
189        assert isinstance(paragraph, Paragraph)
190
191
192@then('document.sections is a Sections object')
193def then_document_sections_is_a_Sections_object(context):
194    sections = context.document.sections
195    msg = 'document.sections not instance of Sections'
196    assert isinstance(sections, Sections), msg
197
198
199@then('document.styles is a Styles object')
200def then_document_styles_is_a_Styles_object(context):
201    styles = context.document.styles
202    assert isinstance(styles, Styles)
203
204
205@then('document.tables is a list containing three tables')
206def then_document_tables_is_a_list_containing_three_tables(context):
207    document = context.document
208    tables = document.tables
209    assert isinstance(tables, list)
210    assert len(tables) == 3
211    for table in tables:
212        assert isinstance(table, Table)
213
214
215@then('the document contains a 2 x 2 table')
216def then_the_document_contains_a_2x2_table(context):
217    table = context.document.tables[-1]
218    assert isinstance(table, Table)
219    assert len(table.rows) == 2
220    assert len(table.columns) == 2
221    context.table_ = table
222
223
224@then('the document has two sections')
225def then_the_document_has_two_sections(context):
226    assert len(context.document.sections) == 2
227
228
229@then('the first section is portrait')
230def then_the_first_section_is_portrait(context):
231    first_section = context.document.sections[0]
232    expected_width, expected_height = context.original_dimensions
233    assert first_section.orientation == WD_ORIENT.PORTRAIT
234    assert first_section.page_width == expected_width
235    assert first_section.page_height == expected_height
236
237
238@then('the last paragraph contains only a page break')
239def then_last_paragraph_contains_only_a_page_break(context):
240    document = context.document
241    paragraph = document.paragraphs[-1]
242    assert len(paragraph.runs) == 1
243    assert len(paragraph.runs[0]._r) == 1
244    assert paragraph.runs[0]._r[0].type == 'page'
245
246
247@then('the last paragraph contains the heading text')
248def then_last_p_contains_heading_text(context):
249    document = context.document
250    text = context.heading_text
251    paragraph = document.paragraphs[-1]
252    assert paragraph.text == text
253
254
255@then('the second section is landscape')
256def then_the_second_section_is_landscape(context):
257    new_section = context.document.sections[-1]
258    expected_height, expected_width = context.original_dimensions
259    assert new_section.orientation == WD_ORIENT.LANDSCAPE
260    assert new_section.page_width == expected_width
261    assert new_section.page_height == expected_height
262
263
264@then('the style of the last paragraph is \'{style_name}\'')
265def then_the_style_of_the_last_paragraph_is_style(context, style_name):
266    document = context.document
267    paragraph = document.paragraphs[-1]
268    assert paragraph.style.name == style_name, (
269        'got %s' % paragraph.style.name
270    )
271