Skip to content

Commit 538ed19

Browse files
ApteryksSteve Canny
authored and
Steve Canny
committed
tbl: add CT_Tc.merge()
1 parent 3a447d3 commit 538ed19

File tree

2 files changed

+97
-3
lines changed

2 files changed

+97
-3
lines changed

docx/oxml/table.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ class CT_Row(BaseOxmlElement):
2424
"""
2525
tc = ZeroOrMore('w:tc')
2626

27+
def tc_at_grid_col(self, idx):
28+
"""
29+
The ``<w:tc>`` element appearing at grid column *idx*. Raises
30+
|ValueError| if no ``w:tc`` element begins at that grid column.
31+
"""
32+
raise NotImplementedError
33+
2734
@property
2835
def tr_idx(self):
2936
"""
@@ -227,11 +234,14 @@ def grid_span(self):
227234

228235
def merge(self, other_tc):
229236
"""
230-
Return the top-left ``<w:tc>`` element of the span formed by merging
231-
the rectangular region defined by using this tc element and
237+
Return the top-left ``<w:tc>`` element of a new span formed by
238+
merging the rectangular region defined by using this tc element and
232239
*other_tc* as diagonal corners.
233240
"""
234-
raise NotImplementedError
241+
top, left, height, width = self._span_dimensions(other_tc)
242+
top_tc = self._tbl.tr_lst[top].tc_at_grid_col(left)
243+
top_tc._grow_to(width, height)
244+
return top_tc
235245

236246
@classmethod
237247
def new(cls):
@@ -272,6 +282,14 @@ def width(self, value):
272282
tcPr = self.get_or_add_tcPr()
273283
tcPr.width = value
274284

285+
def _grow_to(self, width, height, top_tc=None):
286+
"""
287+
Grow this cell to *width* grid columns and *height* rows by expanding
288+
horizontal spans and creating continuation cells to form vertical
289+
spans.
290+
"""
291+
raise NotImplementedError
292+
275293
def _insert_tcPr(self, tcPr):
276294
"""
277295
``tcPr`` has a bunch of successors, but it comes first if it appears,
@@ -284,6 +302,21 @@ def _insert_tcPr(self, tcPr):
284302
def _new_tbl(self):
285303
return CT_Tbl.new()
286304

305+
def _span_dimensions(self, other_tc):
306+
"""
307+
Return a (top, left, height, width) 4-tuple specifying the extents of
308+
the merged cell formed by using this tc and *other_tc* as opposite
309+
corner extents.
310+
"""
311+
raise NotImplementedError
312+
313+
@property
314+
def _tbl(self):
315+
"""
316+
The tbl element this tc element appears in.
317+
"""
318+
raise NotImplementedError
319+
287320

288321
class CT_TcPr(BaseOxmlElement):
289322
"""

tests/oxml/test_table.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for the docx.oxml.text module.
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, division, print_function, unicode_literals
9+
)
10+
11+
import pytest
12+
13+
from docx.oxml.table import CT_Row, CT_Tc
14+
15+
from ..unitutil.cxml import element
16+
from ..unitutil.mock import instance_mock, method_mock, property_mock
17+
18+
19+
class DescribeCT_Tc(object):
20+
21+
def it_can_merge_to_another_tc(self, merge_fixture):
22+
tc, other_tc, top_tr_, top_tc_, left, height, width = merge_fixture
23+
merged_tc = tc.merge(other_tc)
24+
tc._span_dimensions.assert_called_once_with(other_tc)
25+
top_tr_.tc_at_grid_col.assert_called_once_with(left)
26+
top_tc_._grow_to.assert_called_once_with(width, height)
27+
assert merged_tc is top_tc_
28+
29+
# fixtures -------------------------------------------------------
30+
31+
@pytest.fixture
32+
def merge_fixture(
33+
self, tr_, _span_dimensions_, _tbl_, _grow_to_, top_tc_):
34+
tc, other_tc = element('w:tc'), element('w:tc')
35+
top, left, height, width = 0, 1, 2, 3
36+
_span_dimensions_.return_value = top, left, height, width
37+
_tbl_.return_value.tr_lst = [tr_]
38+
tr_.tc_at_grid_col.return_value = top_tc_
39+
return tc, other_tc, tr_, top_tc_, left, height, width
40+
41+
# fixture components ---------------------------------------------
42+
43+
@pytest.fixture
44+
def _grow_to_(self, request):
45+
return method_mock(request, CT_Tc, '_grow_to')
46+
47+
@pytest.fixture
48+
def _span_dimensions_(self, request):
49+
return method_mock(request, CT_Tc, '_span_dimensions')
50+
51+
@pytest.fixture
52+
def _tbl_(self, request):
53+
return property_mock(request, CT_Tc, '_tbl')
54+
55+
@pytest.fixture
56+
def top_tc_(self, request):
57+
return instance_mock(request, CT_Tc)
58+
59+
@pytest.fixture
60+
def tr_(self, request):
61+
return instance_mock(request, CT_Row)

0 commit comments

Comments
 (0)