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 8, 2018
1 parent c7c8a53 commit 8f54781
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 106 deletions.
136 changes: 121 additions & 15 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 @@ -133,6 +166,23 @@ class ListBase(flowable.Flowable):
def __init__(self, *args, **kw):
super(ListBase, self).__init__(*args, **kw)

def getRootStyle(self):
parent = self
root = None
while True:
parent = parent.parent
if isinstance(parent, ListItem):
continue
if isinstance(parent, ListBase):
root = parent
else:
break

manager = attr.getManager(self)
for style in manager.document.automaticstyles.childNodes:
if style.getAttribute('name') == root.stylename:
return style

def process(self):
# Keeps track of the root list (in the case of nested lists)
# Keeps track of the level of each list
Expand All @@ -144,32 +194,88 @@ def process(self):
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(
style_attr = dict(self.getAttributeValues(
select=['style'], attrMapping=self.attrMapping))
if attrs:
style = attrs['style']

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

attrs = dict(self.getAttributeValues(
select=self.styleAttributes, attrMapping=self.attrMapping))

# Always make a special style for each root level list, or numbering
# is messed up when you convert to docx.
if self.level == 1:
# Register style
attrs = dict(self.getAttributeValues(
select=self.styleAttributes, attrMapping=self.attrMapping))
stylesheet.registerListStyle(manager.document, newstylename,
newstyle, attrs)
if isinstance(self, OrderedList):
newstylename = newstylename + '-ol'
else:
newstylename = newstylename + '-ul'
self.stylename = newstylename

self.item = odf.text.List(stylename=newstylename)
else:
newstylename = None
self.item = odf.text.List()

if newstyle is not None:
# A non-top level list with a style name.
# Attempt to copy that styles list styling over to the current
# level.

# We only care about these right now:
newattrs = {'bulletType': newstyle.bulletType,
'bulletFormat': newstyle.bulletFormat,
}
# Get any local overrides
newattrs.update(attrs)
# OK, we have the new attrs
attrs = newattrs

if attrs:
# We must now find the correct level style, and modify it.
style = self.getRootStyle()
for levelstyle in style.childNodes:
if not levelstyle.tagName.startswith('text:list-level-style'):
# We only care about levels now
continue
if int(levelstyle.getAttribute('level')) != self.level:
continue

# Modify this level
if levelstyle.tagName == 'text:list-level-style-number':
# Ordered list

if 'bulletType' in attrs:
bulletType = attrs['bulletType']
if bulletType.lower() not in '1ai':
# ODF doesn't support fancy formats like
# '1st' or 'First'.
bulletType = '1'

levelstyle.setAttribute('numformat', bulletType)

if 'bulletFormat' in attrs:
bulletFormat = attrs['bulletFormat']
pre, post = bulletFormat.split('%s')
levelstyle.setAttribute('numprefix', pre)
levelstyle.setAttribute('numsuffix', post)

if levelstyle.tagName == 'text:list-level-style-bullet':
# Unordered list
if 'bulletType' in attrs:
bulletType = attrs['bulletType']
bulletChar = stylesheet.BULLETS[bulletType]
levelstyle.setAttribute('bulletchar', bulletChar)

self.item = odf.text.List(stylename=newstylename)
self.parent.contents.addElement(self.item)
# Add all list items.
self.processSubDirectives()
Expand Down
Loading

0 comments on commit 8f54781

Please sign in to comment.