Skip to content

Commit

Permalink
Yet more numbering fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
regebro committed Jan 4, 2018
1 parent c7c8a53 commit 9d5940a
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 101 deletions.
74 changes: 55 additions & 19 deletions src/shoobx/rml2odt/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,50 @@ def modifyStyle(self):
level=str(self.parent.level),
)

def _getParaStyle(self):
# Any childnodes that are paragraphs must have a special style
# for indentation purposes.
node = top = self.parent

while node.parent is not None:
node = node.parent
if isinstance(node, ListBase):
top = node

top_style = dict(top.getAttributeValues(
select=['style'],
attrMapping=top.attrMapping))
if 'style' in top_style:
top_style = top_style['style'].name
else:
top_style = 'Default'

if isinstance(top, OrderedList):
top_style += '-ol'
else:
top_style += '-ul'
return 'P' + top_style

def _convertSimpleContent(self):
# Check whether we need to create a para element.
# 1. Is there text in the element?
# 2. Are any of the children valid Flow elements?
if (self.element.text is not None and
not self.element.text.strip() or
any([sub.tag in flowable.Flow.factories
for sub in self.element])):
not self.element.text.strip()):
return

# Any paragraphs should specifically have the lists paragraph style:
para_style = self._getParaStyle()
for sub in self.element:
if sub.tag == 'para':
sub.attrib['style'] = para_style

# If there is anything flowable here, we are done.
if any([sub.tag in flowable.Flow.factories
for sub in self.element]):
return
# Create a <para> element.

# Else create a <para> element.
para = lxml.etree.Element('para')
# Transfer text.
para.text = self.element.text
Expand All @@ -94,7 +128,6 @@ def _convertSimpleContent(self):
self.element.append(para)

def process(self):
self.styleID = str(uuid.uuid4())
self._convertSimpleContent()

if not self.parent.item.childNodes:
Expand Down Expand Up @@ -140,22 +173,26 @@ def process(self):
parent_list = self.parent.parent
self.level = parent_list.level + 1
self.rootList = parent_list.rootList
# Let's ignore all attributes set on sub lists. I mean, come on.
self.item = odf.text.List()
else:
self.level = 1
self.rootList = self

# Always make a special style for each list, or numbering is messed
# up when you convert to docx.
manager = attr.getManager(self)
self.styleID = str(uuid.uuid4())
attrs = dict(self.getAttributeValues(
select=['style'], attrMapping=self.attrMapping))
if attrs:
style = attrs['style']
# Always make a special style for each list, or numbering is messed
# up when you convert to docx.
manager = attr.getManager(self)
attrs = dict(self.getAttributeValues(
select=['style'], attrMapping=self.attrMapping))

newstylename = manager.getNextStyleName(style.name)
newstyle = copy.deepcopy(manager.styles[style.name])
newstyle.name = newstylename
if 'style' in attrs:
style = attrs['style']
newstylename = manager.getNextStyleName(style.name)
newstyle = copy.deepcopy(manager.styles[style.name])
newstyle.name = newstylename
else:
newstylename = manager.getNextStyleName('Default')
newstyle = None

# Register style
attrs = dict(self.getAttributeValues(
Expand All @@ -166,10 +203,9 @@ def process(self):
newstylename = newstylename + '-ol'
else:
newstylename = newstylename + '-ul'
else:
newstylename = None

self.item = odf.text.List(stylename=newstylename)
self.item = odf.text.List(stylename=newstylename)

self.parent.contents.addElement(self.item)
# Add all list items.
self.processSubDirectives()
Expand Down
168 changes: 98 additions & 70 deletions src/shoobx/rml2odt/stylesheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,26 +457,31 @@ def registerListStyle(doc, name, rmlStyle, attributes=None, ulol=None):
rmlStyles have information both for ordered and unordered lists,
ODF styles do not, so we need to register two different, but similar lists.
"""

if ulol is None:
# Register both the unordered and ordered lists:
registerListStyle(doc, name, rmlStyle, attributes=attributes, ulol='ul')
registerListStyle(doc, name, rmlStyle, attributes=attributes, ulol='ol')
# Register both the unordered and ordered lists. odf seem to only
# include the ones actually used anyway.
registerListStyle(doc, name, rmlStyle, attributes=attributes,
ulol='ul')
registerListStyle(doc, name, rmlStyle, attributes=attributes,
ulol='ol')
return

name = '%s-%s' % (name, ulol)

if attributes is None:
attributes = {}
start = attributes.get('start', rmlStyle.start)
start = attributes.get('start', getattr(rmlStyle, 'start', 1))
if isinstance(start, int):
bulletType = None
else:
bulletType = start

bulletFormat = attributes.get('bulletFormat', rmlStyle.bulletFormat)
bulletDedent = attributes.get('bulletDedent', rmlStyle.bulletDedent) # XXX use this!
numType = attributes.get('bulletType', rmlStyle.bulletType)
bulletFormat = attributes.get('bulletFormat',
getattr(rmlStyle, 'bulletFormat', None))
bulletDedent = attributes.get('bulletDedent',
getattr(rmlStyle, 'bulletDedent', 'auto'))
numType = attributes.get('bulletType',
getattr(rmlStyle, 'bulletType', None))

bulletDict = {
'bulletchar': u'\u2022',
Expand All @@ -488,72 +493,95 @@ def registerListStyle(doc, name, rmlStyle, attributes=None, ulol=None):
}

odtStyle = odf.text.ListStyle(name=name)
# Declare properties of the list style
listProps = odf.style.ListLevelProperties()
if bulletDedent == 'auto':
bulletDedent = '0.25in'
elif not isinstance(bulletDedent, six.string_types):
bulletDedent = '%spt' % bulletDedent

listProps.setAttribute('minlabelwidth', bulletDedent)
listProps.setAttribute('minlabeldistance', '0.15in')

if rmlStyle.bulletFontName is not None:
odf_font_name = rmlFont2odfFont(rmlStyle.bulletFontName)
doc.fontfacedecls.addElement(
odf.style.FontFace(
name=odf_font_name,
fontfamily=odf_font_name))
listProps.setAttribute('fontname', odf_font_name)

retrievedBullet = bulletDict.get(bulletType)
# Add the level properties:
for level in range(1, 11):

# Declare properties of the list style
listProps = odf.style.ListLevelProperties()
listProps.setAttribute('listlevelpositionandspacemode',
'label-alignment')
if getattr(rmlStyle, 'bulletFontName', None) is not None:
odf_font_name = rmlFont2odfFont(rmlStyle.bulletFontName)

if odf_font_name not in [x.getAttribute('name')
for x in doc.fontfacedecls.childNodes]:
doc.fontfacedecls.addElement(
odf.style.FontFace(
name=odf_font_name,
fontfamily=odf_font_name))
listProps.setAttribute('fontname', odf_font_name)

level_indent = 12.7 + (6.35 * level)
label_align = odf.style.ListLevelLabelAlignment(
labelfollowedby="listtab",
listtabstopposition="%smm" % level_indent,
textindent="-6.35mm",
marginleft="%smm" % level_indent)
listProps.appendChild(label_align)

retrievedBullet = bulletDict.get(bulletType)

# Make the number (ol) style:
if ulol == 'ol':
# A numType that is just one character (or None) means some sort of number
if bulletFormat is not None:
pre, post = bulletFormat.split('%s')
else:
pre = post = ''

if numType and numType.lower() not in '1ai':
# ODF doesn't support fancy formats like '1st' or 'First'.
numType = '1'

# Make the number (ol) style:
if ulol == 'ol':
# A numType that is just one character (or None) means some sort of number
if bulletFormat is not None:
pre, post = bulletFormat.split('%s')
else:
pre = post = ''

if numType and numType.lower() not in '1ai':
# ODF doesn't support fancy formats like '1st' or 'First'.
numType = '1'

lvl_style = odf.text.ListLevelStyleNumber(
level='1',
numsuffix=post,
numprefix=pre,
numformat=numType,
startvalue=start,
)

else:
if bulletType and retrievedBullet is None:
# The bullet is a text, such as "RESOLVED:" etc
lvl_style = odf.text.ListLevelStyleNumber(
level='1',
# A bug in the DOCX conversion removes the first character.
# A space first in the prefix and a space as suffix fixes that.
numprefix=' ' + bulletType,
numsuffix=' ',
numformat='')

label_align = odf.style.ListLevelLabelAlignment(
labelfollowedby="listtab",
listtabstopposition="28.22mm",
textindent="-28.22mm",
marginleft="12.7mm")
listProps.appendChild(label_align)
level=level,
numsuffix=post,
numprefix=pre,
numformat=numType,
startvalue=start,
)

else:
# Make the bullet (ul) style:
lvl_style = odf.text.ListLevelStyleBullet(
bulletchar=retrievedBullet,
level='1',
bulletrelativesize='75%')

lvl_style.addElement(listProps)
odtStyle.addElement(lvl_style)
if bulletType and retrievedBullet is None:
# The bullet is a text, such as "RESOLVED:" etc
lvl_style = odf.text.ListLevelStyleNumber(
level=level,
# A bug in the DOCX conversion removes the first character.
# A space first in the prefix and a space as suffix fixes that.
numprefix=' ' + bulletType,
numsuffix=' ',
numformat='')

else:
# Make the bullet (ul) style:
if retrievedBullet is None:
retrievedBullet = bulletDict['bulletchar']
lvl_style = odf.text.ListLevelStyleBullet(
bulletchar=retrievedBullet,
level=level,
bulletrelativesize='75%')

lvl_style.addElement(listProps)
odtStyle.addElement(lvl_style)

# Make the accompanying P style for indents
if bulletDedent == 'auto':
bulletDedent = '0.25in'
elif not isinstance(bulletDedent, six.string_types):
bulletDedent = '%spt' % bulletDedent

pstyle = odf.style.Style(name='P%s' % name,
parentstylename='Standard',
liststylename=name,
family='paragraph'
)
pprops = odf.style.ParagraphProperties(marginleft=bulletDedent,
textindent='-' + bulletDedent)
pstyle.appendChild(pprops)
doc.automaticstyles.addElement(pstyle)

# Add the style to the doc
doc.automaticstyles.addElement(odtStyle)


Expand Down
Binary file modified src/shoobx/rml2odt/tests/test_data/expected/numberingTest.odt
Binary file not shown.
Binary file modified src/shoobx/rml2odt/tests/test_data/expected/tag-para-base.odt
Binary file not shown.
Binary file modified src/shoobx/rml2odt/tests/test_data/expected/tag-ul-ol-li.odt
Binary file not shown.
53 changes: 41 additions & 12 deletions src/shoobx/rml2odt/tests/test_data/input/tag-ul-ol-li.rml
Original file line number Diff line number Diff line change
Expand Up @@ -78,32 +78,31 @@
<h1>Unordered lists</h1>

<h2>Multi-level</h2>
<para>A lot of formatting that isn't yet supported.</para>

<ul bulletColor="orange" bulletFontName="Times-Roman">
<li bulletColor="gray" bulletFontName="Helvetica"><para>Welcome to RML 1</para></li>
<ul>
<li><para>Welcome to RML 1</para></li>
<li>
<ul bulletColor="red" bulletFontName="Times-Roman" bulletFontSize="8">
<li value="disc" bulletFontName="Helvetica"><para>unordered 1</para></li>
<li value="square" bulletColor="blue"><para>unordered 2</para></li>
<ul>
<li value="disc"><para>unordered 1</para></li>
<li value="square"><para>unordered 2</para></li>
<li>
<ul>
<li><para>Unordered - another one</para></li>
<li><para>Unordered - another one</para></li>
</ul>
</li>
<li value="diamond" bulletColor="green"><para>unordered 3</para></li>
<li value="rarrowhead" bulletColor="yellow"><para>unordered 4</para></li>
<li value="diamond"><para>unordered 3</para></li>
<li value="rarrowhead"><para>unordered 4</para></li>
<li><para>unordered 5</para></li>
<li><para>unordered 6</para></li>
<li value="disc" bulletColor="green"><para>unordered 3</para></li>
<li bulletColor="yellow"><para>unordered 4</para></li>
<li value="disc"><para>unordered 3</para></li>
<li><para>unordered 4</para></li>
</ul>
</li>
<li><para>Welcome to RML 2</para></li>
<li><para>Welcome to RML 3</para></li>
<ul bulletColor="orange" bulletFontName="Times-Roman">
<li bulletColor="gray" bulletFontName="Chalkduster"><para>Item 1</para></li>
<ul>
<li><para>Item 1</para></li>
<li><para>Item 2</para></li>
</ul>
</ul>
Expand Down Expand Up @@ -202,5 +201,35 @@
<li><para>Three</para></li>
</ol>

<para>Multiple levels</para>

<ol>
<li><para>Welcome to RML 1</para></li>
<li>
<ol>
<li><para>Ordered 1</para></li>
<li><para>Ordered 2</para></li>
<li>
<ol>
<li><para>Ordered - another one</para></li>
<li><para>Ordered - another one</para></li>
</ol>
</li>
<li><para>Ordered 3</para></li>
<li><para>Ordered 4</para></li>
<li><para>Ordered 5</para></li>
<li><para>Ordered 6</para></li>
<li><para>Ordered 3</para></li>
<li><para>Ordered 4</para></li>
</ol>
</li>
<li><para>Welcome to RML 2</para></li>
<li><para>Welcome to RML 3</para></li>
<ol>
<li><para>Item 1</para></li>
<li><para>Item 2</para></li>
</ol>
</ol>

</story>
</document>

0 comments on commit 9d5940a

Please sign in to comment.