Skip to content

Commit 84bdbbe

Browse files
committed
Cleaned up underline, started adding table cell properties
underline module almost done, need to work on tests. created class for `<w:tcPr>` to handle cell properties like `gridSpan`
1 parent cd3c86e commit 84bdbbe

6 files changed

Lines changed: 129 additions & 18 deletions

File tree

docx/enum/text.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,50 @@ class WD_BREAK_TYPE(object):
2525
TEXT_WRAPPING = 11
2626

2727
WD_BREAK = WD_BREAK_TYPE
28+
29+
class WD_UNDERLINE_TYPE(object):
30+
"""
31+
Underline types, corresponding to WdUnderline enumeration
32+
http://msdn.microsoft.com/en-us/library/office/ff822388(v=office.15).aspx
33+
"""
34+
DASH = 7 # Dashes.
35+
DASH_HEAVY = 23 # Heavy dashes.
36+
DASH_LONG = 39 # Long dashes.
37+
LONG_HEAVY = 55 # Long heavy dashes.
38+
DOT_DASH = 9 # Alternating dots and dashes.
39+
DOT_DASH_HEAVY = 25 # Alternating heavy dots and heavy dashes.
40+
DOT_DOT_DASH = 10 # An alternating dot-dot-dash pattern.
41+
DOT_DOT_DASH_HEAVY = 26 # An alternating heavy dot-dot-dash pattern.
42+
DOTTED = 4 # Dots.
43+
DOTTED_HEAVY = 20 # Heavy dots.
44+
DOUBLE = 3 # A double line.
45+
NONE = 0 # No underline.
46+
SINGLE = 1 # A single line. default.
47+
THICK = 6 # A single thick line.
48+
WAVY = 11 #A single wavy line.
49+
WAVY_DOUBLE = 43 # A double wavy line.
50+
WAVY_HEAVY = 27 # A heavy wavy line.
51+
WORDS = 2 # Underline individual words only.
52+
53+
stringDict={
54+
DASH:'dash',
55+
DASH_HEAVY:'dashHeavy',
56+
DASH_LONG:'dashLong',
57+
LONG_HEAVY:'longHeavy',
58+
DOT_DASH:'dotDash',
59+
DOT_DASH_HEAVY:'dotDashHeavy',
60+
DOT_DOT_DASH:'dotDotDash',
61+
DOT_DOT_DASH_HEAVY:'dotDotDashHeavy',
62+
DOTTED:'dotted',
63+
DOTTED_HEAVY:'dottedHeavy',
64+
DOUBLE:'double',
65+
NONE:'none',
66+
SINGLE:'single',
67+
THICK:'thick',
68+
WAVY:'wavy',
69+
WAVY_DOUBLE:'wavyDouble',
70+
WAVY_HEAVY:'wavyHeavy',
71+
WORDS:'words',
72+
}
73+
74+
WD_UNDERLINE = WD_UNDERLINE_TYPE

docx/oxml/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@
4545
register_custom_element_class('w:style', CT_Style)
4646
register_custom_element_class('w:styles', CT_Styles)
4747

48-
from docx.oxml.table import CT_Row, CT_Tbl, CT_TblGrid, CT_TblPr, CT_Tc
48+
from docx.oxml.table import CT_Row, CT_Tbl, CT_TblGrid, CT_TblPr, CT_Tc, CT_TcPr
4949
register_custom_element_class('w:tbl', CT_Tbl)
5050
register_custom_element_class('w:tblGrid', CT_TblGrid)
5151
register_custom_element_class('w:tblPr', CT_TblPr)
5252
register_custom_element_class('w:tblStyle', CT_String)
5353
register_custom_element_class('w:tc', CT_Tc)
5454
register_custom_element_class('w:tr', CT_Row)
55+
register_custom_element_class('w:tcPr', CT_TcPr)
5556

5657
from docx.oxml.text import CT_Br, CT_P, CT_PPr, CT_R, CT_RPr, CT_Text
5758
register_custom_element_class('w:b', CT_OnOff)

docx/oxml/table.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,52 @@ def tcPr(self):
251251
<w:tcPr> child element or |None| if not present.
252252
"""
253253
return self.find(qn('w:tcPr'))
254+
255+
def get_or_add_tcPr(self):
256+
"""
257+
Return the tcPr child element, newly added if not present.
258+
"""
259+
tcPr = self.tcPr
260+
if tcPr is None:
261+
tcPr = self._add_tcPr()
262+
return tcPr
263+
264+
def _add_tcPr(self):
265+
"""
266+
Return a newly added tcPr child element. Assumes one is not present.
267+
"""
268+
tcPr = CT_TcPr.new()
269+
self.append(tcPr)
270+
return tcPr
271+
272+
class CT_TcPr(OxmlBaseElement):
273+
"""
274+
``<w:tcPr>`` element, child of ``<w:tc>``, holds child elements that
275+
define cell properties such as gridSpan.
276+
"""
277+
@classmethod
278+
def new(cls):
279+
"""
280+
Return a new ``<w:tcPr>`` element.
281+
"""
282+
return OxmlElement('w:tcPr')
283+
284+
def add_gridSpan(self, span):
285+
"""
286+
Return a new <w:gridSpan> element newly inserted in sequence among
287+
the existing child elements.gridSpan
288+
"""
289+
gridSpan = CT_String.new('w:gridSpan', str(span))
290+
self.append(gridSpan) # append or insert?
291+
return gridSpan
292+
293+
@property
294+
def gridSpan(self):
295+
"""
296+
Optional <w:gridSpan> child element, or |None| if not present.
297+
"""
298+
return self.find(qn('w:gridSpan'))
299+
300+
301+
302+

docx/oxml/text.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def add_underline(self, style):
299299
"""
300300
Return a newly added <w:u w:val=style/> child element.
301301
"""
302-
u = CT_String.new('w:u', style)
302+
u = CT_String.new('w:u', str(style))
303303
self.insert(0, u)
304304
return u
305305

docx/table.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,24 @@ def text(self, text):
113113
p = tc.add_p()
114114
r = p.add_r()
115115
r.add_t(text)
116-
116+
117+
@property
118+
def colSpan(self):
119+
"""
120+
Set the column span
121+
"""
122+
span = self._tc.get_or_add_tcPr().gridSpan
123+
if span is None:
124+
return None
125+
return span.val
126+
127+
@colSpan.setter
128+
def colSpan(self, val):
129+
span = self._tc.get_or_add_tcPr().gridSpan
130+
if span is None:
131+
self._tc.get_or_add_tcPr().add_gridSpan(val)
132+
else:
133+
span.val = val
117134

118135
class _Column(object):
119136
"""

docx/text.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from __future__ import absolute_import, print_function, unicode_literals
88

9-
from docx.enum.text import WD_BREAK
9+
from docx.enum.text import WD_BREAK, WD_UNDERLINE
1010

1111

1212
def boolproperty(f):
@@ -215,12 +215,14 @@ def italic(self):
215215
@property
216216
def underline(self):
217217
"""
218-
String name of underline style to be applied. If "none" or False, then no underline
219-
is applied. If True, single underline is applied.
218+
Underline text with style of *underline_type*. *underline_type* can
219+
take the values `WD_UNDERLINE.SINGLE`, `WD_UNDERLINE.DOUBLE`, etc.
220+
where `WD_UNDERLINE` is imported from `docx.enum.text`.
220221
221-
Valid Values: True, False, 'single', 'words', 'double', 'thick', 'dotted', 'dottedHeavy',
222-
'dash', 'dashedHeavy', 'dashLong', 'dashLongHeavy', 'dotDash', 'dashDotHeavy',
223-
'dotDotDash', 'dashDotDotHeavy', 'wave', 'wavyHeavy', 'wavyDouble', 'none'
222+
Shorthand:
223+
setting to True results in `WD_UNDERLINE.SINGLE`.
224+
setting to False results in `WD_UNDERLINE.NONE`.
225+
setting to None results in `WD_UNDERLINE.NONE`.
224226
"""
225227
u = self._r.get_or_add_rPr().underline
226228
if u is None:
@@ -231,16 +233,11 @@ def underline(self):
231233
def underline(self, style):
232234
# interperate style
233235
if style is None:
234-
style = 'none'
236+
style = WD_UNDERLINE.NONE
235237
if type(style)==bool:
236-
style = 'single' if style else 'none'
237-
238-
validStyles = ['single', 'words', 'double', 'thick', 'dotted', 'dottedHeavy', 'dash',
239-
'dashedHeavy', 'dashLong', 'dashLongHeavy', 'dotDash', 'dashDotHeavy', 'dotDotDash', 'dashDotDotHeavy',
240-
'wave', 'wavyHeavy', 'wavyDouble', 'none']
241-
242-
if style not in validStyles:
243-
raise ValueError('"'+style+'" is not valid. Needs to be: '+', '.join(validStyles))
238+
style = WD_UNDERLINE.SINGLE if style else WD_UNDERLINE.NONE
239+
240+
style = WD_UNDERLINE.stringDict[style]
244241

245242
u = self._r.get_or_add_rPr().underline
246243
if u is None:

0 commit comments

Comments
 (0)