/documentor/libraries/docutils-0.9.1-py3.2/docutils/writers/odf_odt/__init__.py
Python | 3266 lines | 3100 code | 101 blank | 65 comment | 76 complexity | e5cb5316ba91e8388738a17d68aacd31 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, GPL-2.0
- # $Id: __init__.py 7422 2012-05-03 10:55:30Z milde $
- # Author: Dave Kuhlman <dkuhlman@rexx.com>
- # Copyright: This module has been placed in the public domain.
- """
- Open Document Format (ODF) Writer.
- """
- VERSION = '1.0a'
- __docformat__ = 'reStructuredText'
- import sys
- import os
- import os.path
- import tempfile
- import zipfile
- from xml.dom import minidom
- import time
- import re
- import io
- import inspect
- import imp
- import copy
- import urllib.request, urllib.error, urllib.parse
- import docutils
- from docutils import frontend, nodes, utils, writers, languages
- from docutils.parsers import rst
- from docutils.readers import standalone
- from docutils.transforms import references
- WhichElementTree = ''
- try:
- # 1. Try to use lxml.
- #from lxml import etree
- #WhichElementTree = 'lxml'
- raise ImportError('Ignoring lxml')
- except ImportError as e:
- try:
- # 2. Try to use ElementTree from the Python standard library.
- from xml.etree import ElementTree as etree
- WhichElementTree = 'elementtree'
- except ImportError as e:
- try:
- # 3. Try to use a version of ElementTree installed as a separate
- # product.
- from elementtree import ElementTree as etree
- WhichElementTree = 'elementtree'
- except ImportError as e:
- s1 = 'Must install either a version of Python containing ' \
- 'ElementTree (Python version >=2.5) or install ElementTree.'
- raise ImportError(s1)
- #
- # Import pygments and odtwriter pygments formatters if possible.
- try:
- import pygments
- import pygments.lexers
- from .pygmentsformatter import OdtPygmentsProgFormatter, \
- OdtPygmentsLaTeXFormatter
- except ImportError as exp:
- pygments = None
- try: # check for the Python Imaging Library
- import PIL
- except ImportError:
- try: # sometimes PIL modules are put in PYTHONPATH's root
- import Image
- class PIL(object): pass # dummy wrapper
- PIL.Image = Image
- except ImportError:
- PIL = None
- ## import warnings
- ## warnings.warn('importing IPShellEmbed', UserWarning)
- ## from IPython.Shell import IPShellEmbed
- ## args = ['-pdb', '-pi1', 'In <\\#>: ', '-pi2', ' .\\D.: ',
- ## '-po', 'Out<\\#>: ', '-nosep']
- ## ipshell = IPShellEmbed(args,
- ## banner = 'Entering IPython. Press Ctrl-D to exit.',
- ## exit_msg = 'Leaving Interpreter, back to program.')
- #
- # ElementTree does not support getparent method (lxml does).
- # This wrapper class and the following support functions provide
- # that support for the ability to get the parent of an element.
- #
- if WhichElementTree == 'elementtree':
- class _ElementInterfaceWrapper(etree._ElementInterface):
- def __init__(self, tag, attrib=None):
- etree._ElementInterface.__init__(self, tag, attrib)
- if attrib is None:
- attrib = {}
- self.parent = None
- def setparent(self, parent):
- self.parent = parent
- def getparent(self):
- return self.parent
- #
- # Constants and globals
- SPACES_PATTERN = re.compile(r'( +)')
- TABS_PATTERN = re.compile(r'(\t+)')
- FILL_PAT1 = re.compile(r'^ +')
- FILL_PAT2 = re.compile(r' {2,}')
- TABLESTYLEPREFIX = 'rststyle-table-'
- TABLENAMEDEFAULT = '%s0' % TABLESTYLEPREFIX
- TABLEPROPERTYNAMES = ('border', 'border-top', 'border-left',
- 'border-right', 'border-bottom', )
- GENERATOR_DESC = 'Docutils.org/odf_odt'
- NAME_SPACE_1 = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'
- CONTENT_NAMESPACE_DICT = CNSD = {
- # 'office:version': '1.0',
- 'chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
- 'dc': 'http://purl.org/dc/elements/1.1/',
- 'dom': 'http://www.w3.org/2001/xml-events',
- 'dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
- 'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
- 'fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
- 'form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
- 'math': 'http://www.w3.org/1998/Math/MathML',
- 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
- 'office': NAME_SPACE_1,
- 'ooo': 'http://openoffice.org/2004/office',
- 'oooc': 'http://openoffice.org/2004/calc',
- 'ooow': 'http://openoffice.org/2004/writer',
- 'presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0',
-
- 'script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
- 'style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
- 'svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
- 'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
- 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
- 'xforms': 'http://www.w3.org/2002/xforms',
- 'xlink': 'http://www.w3.org/1999/xlink',
- 'xsd': 'http://www.w3.org/2001/XMLSchema',
- 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
- }
- STYLES_NAMESPACE_DICT = SNSD = {
- # 'office:version': '1.0',
- 'chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
- 'dc': 'http://purl.org/dc/elements/1.1/',
- 'dom': 'http://www.w3.org/2001/xml-events',
- 'dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
- 'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
- 'fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
- 'form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
- 'math': 'http://www.w3.org/1998/Math/MathML',
- 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
- 'office': NAME_SPACE_1,
- 'presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0',
- 'ooo': 'http://openoffice.org/2004/office',
- 'oooc': 'http://openoffice.org/2004/calc',
- 'ooow': 'http://openoffice.org/2004/writer',
- 'script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
- 'style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
- 'svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
- 'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
- 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
- 'xlink': 'http://www.w3.org/1999/xlink',
- }
- MANIFEST_NAMESPACE_DICT = MANNSD = {
- 'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0',
- }
- META_NAMESPACE_DICT = METNSD = {
- # 'office:version': '1.0',
- 'dc': 'http://purl.org/dc/elements/1.1/',
- 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'office': NAME_SPACE_1,
- 'ooo': 'http://openoffice.org/2004/office',
- 'xlink': 'http://www.w3.org/1999/xlink',
- }
- #
- # Attribute dictionaries for use with ElementTree (not lxml), which
- # does not support use of nsmap parameter on Element() and SubElement().
- CONTENT_NAMESPACE_ATTRIB = {
- #'office:version': '1.0',
- 'xmlns:chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
- 'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
- 'xmlns:dom': 'http://www.w3.org/2001/xml-events',
- 'xmlns:dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
- 'xmlns:draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
- 'xmlns:fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
- 'xmlns:form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
- 'xmlns:math': 'http://www.w3.org/1998/Math/MathML',
- 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'xmlns:number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
- 'xmlns:office': NAME_SPACE_1,
- 'xmlns:presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0',
- 'xmlns:ooo': 'http://openoffice.org/2004/office',
- 'xmlns:oooc': 'http://openoffice.org/2004/calc',
- 'xmlns:ooow': 'http://openoffice.org/2004/writer',
- 'xmlns:script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
- 'xmlns:style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
- 'xmlns:svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
- 'xmlns:table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
- 'xmlns:text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
- 'xmlns:xforms': 'http://www.w3.org/2002/xforms',
- 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
- 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
- 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
- }
- STYLES_NAMESPACE_ATTRIB = {
- #'office:version': '1.0',
- 'xmlns:chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
- 'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
- 'xmlns:dom': 'http://www.w3.org/2001/xml-events',
- 'xmlns:dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
- 'xmlns:draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
- 'xmlns:fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
- 'xmlns:form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
- 'xmlns:math': 'http://www.w3.org/1998/Math/MathML',
- 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'xmlns:number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
- 'xmlns:office': NAME_SPACE_1,
- 'xmlns:presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0',
- 'xmlns:ooo': 'http://openoffice.org/2004/office',
- 'xmlns:oooc': 'http://openoffice.org/2004/calc',
- 'xmlns:ooow': 'http://openoffice.org/2004/writer',
- 'xmlns:script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
- 'xmlns:style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
- 'xmlns:svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
- 'xmlns:table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
- 'xmlns:text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
- 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
- }
- MANIFEST_NAMESPACE_ATTRIB = {
- 'xmlns:manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0',
- }
- META_NAMESPACE_ATTRIB = {
- #'office:version': '1.0',
- 'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
- 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
- 'xmlns:office': NAME_SPACE_1,
- 'xmlns:ooo': 'http://openoffice.org/2004/office',
- 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
- }
- #
- # Functions
- #
- #
- # ElementTree support functions.
- # In order to be able to get the parent of elements, must use these
- # instead of the functions with same name provided by ElementTree.
- #
- def Element(tag, attrib=None, nsmap=None, nsdict=CNSD):
- if attrib is None:
- attrib = {}
- tag, attrib = fix_ns(tag, attrib, nsdict)
- if WhichElementTree == 'lxml':
- el = etree.Element(tag, attrib, nsmap=nsmap)
- else:
- el = _ElementInterfaceWrapper(tag, attrib)
- return el
- def SubElement(parent, tag, attrib=None, nsmap=None, nsdict=CNSD):
- if attrib is None:
- attrib = {}
- tag, attrib = fix_ns(tag, attrib, nsdict)
- if WhichElementTree == 'lxml':
- el = etree.SubElement(parent, tag, attrib, nsmap=nsmap)
- else:
- el = _ElementInterfaceWrapper(tag, attrib)
- parent.append(el)
- el.setparent(parent)
- return el
- def fix_ns(tag, attrib, nsdict):
- nstag = add_ns(tag, nsdict)
- nsattrib = {}
- for key, val in attrib.items():
- nskey = add_ns(key, nsdict)
- nsattrib[nskey] = val
- return nstag, nsattrib
- def add_ns(tag, nsdict=CNSD):
- if WhichElementTree == 'lxml':
- nstag, name = tag.split(':')
- ns = nsdict.get(nstag)
- if ns is None:
- raise RuntimeError('Invalid namespace prefix: %s' % nstag)
- tag = '{%s}%s' % (ns, name,)
- return tag
- def ToString(et):
- outstream = io.StringIO()
- if sys.version_info >= (3, 2):
- et.write(outstream, encoding="unicode")
- else:
- et.write(outstream)
- s1 = outstream.getvalue()
- outstream.close()
- return s1
- def escape_cdata(text):
- text = text.replace("&", "&")
- text = text.replace("<", "<")
- text = text.replace(">", ">")
- ascii = ''
- for char in text:
- if ord(char) >= ord("\x7f"):
- ascii += "&#x%X;" % ( ord(char), )
- else:
- ascii += char
- return ascii
- WORD_SPLIT_PAT1 = re.compile(r'\b(\w*)\b\W*')
- def split_words(line):
- # We need whitespace at the end of the string for our regexpr.
- line += ' '
- words = []
- pos1 = 0
- mo = WORD_SPLIT_PAT1.search(line, pos1)
- while mo is not None:
- word = mo.groups()[0]
- words.append(word)
- pos1 = mo.end()
- mo = WORD_SPLIT_PAT1.search(line, pos1)
- return words
- #
- # Classes
- #
- class TableStyle(object):
- def __init__(self, border=None, backgroundcolor=None):
- self.border = border
- self.backgroundcolor = backgroundcolor
- def get_border_(self):
- return self.border_
- def set_border_(self, border):
- self.border_ = border
- border = property(get_border_, set_border_)
- def get_backgroundcolor_(self):
- return self.backgroundcolor_
- def set_backgroundcolor_(self, backgroundcolor):
- self.backgroundcolor_ = backgroundcolor
- backgroundcolor = property(get_backgroundcolor_, set_backgroundcolor_)
- BUILTIN_DEFAULT_TABLE_STYLE = TableStyle(
- border = '0.0007in solid #000000')
- #
- # Information about the indentation level for lists nested inside
- # other contexts, e.g. dictionary lists.
- class ListLevel(object):
- def __init__(self, level, sibling_level=True, nested_level=True):
- self.level = level
- self.sibling_level = sibling_level
- self.nested_level = nested_level
- def set_sibling(self, sibling_level): self.sibling_level = sibling_level
- def get_sibling(self): return self.sibling_level
- def set_nested(self, nested_level): self.nested_level = nested_level
- def get_nested(self): return self.nested_level
- def set_level(self, level): self.level = level
- def get_level(self): return self.level
- class Writer(writers.Writer):
- MIME_TYPE = 'application/vnd.oasis.opendocument.text'
- EXTENSION = '.odt'
- supported = ('odt', )
- """Formats this writer supports."""
- default_stylesheet = 'styles' + EXTENSION
- default_stylesheet_path = utils.relative_path(
- os.path.join(os.getcwd(), 'dummy'),
- os.path.join(os.path.dirname(__file__), default_stylesheet))
- default_template = 'template.txt'
- default_template_path = utils.relative_path(
- os.path.join(os.getcwd(), 'dummy'),
- os.path.join(os.path.dirname(__file__), default_template))
- settings_spec = (
- 'ODF-Specific Options',
- None,
- (
- ('Specify a stylesheet. '
- 'Default: "%s"' % default_stylesheet_path,
- ['--stylesheet'],
- {
- 'default': default_stylesheet_path,
- 'dest': 'stylesheet'
- }),
- ('Specify a configuration/mapping file relative to the '
- 'current working '
- 'directory for additional ODF options. '
- 'In particular, this file may contain a section named '
- '"Formats" that maps default style names to '
- 'names to be used in the resulting output file allowing for '
- 'adhering to external standards. '
- 'For more info and the format of the configuration/mapping file, '
- 'see the odtwriter doc.',
- ['--odf-config-file'],
- {'metavar': '<file>'}),
- ('Obfuscate email addresses to confuse harvesters while still '
- 'keeping email links usable with standards-compliant browsers.',
- ['--cloak-email-addresses'],
- {'default': False,
- 'action': 'store_true',
- 'dest': 'cloak_email_addresses',
- 'validator': frontend.validate_boolean}),
- ('Do not obfuscate email addresses.',
- ['--no-cloak-email-addresses'],
- {'default': False,
- 'action': 'store_false',
- 'dest': 'cloak_email_addresses',
- 'validator': frontend.validate_boolean}),
- ('Specify the thickness of table borders in thousands of a cm. '
- 'Default is 35.',
- ['--table-border-thickness'],
- {'default': None,
- 'validator': frontend.validate_nonnegative_int}),
- ('Add syntax highlighting in literal code blocks.',
- ['--add-syntax-highlighting'],
- {'default': False,
- 'action': 'store_true',
- 'dest': 'add_syntax_highlighting',
- 'validator': frontend.validate_boolean}),
- ('Do not add syntax highlighting in literal code blocks. (default)',
- ['--no-syntax-highlighting'],
- {'default': False,
- 'action': 'store_false',
- 'dest': 'add_syntax_highlighting',
- 'validator': frontend.validate_boolean}),
- ('Create sections for headers. (default)',
- ['--create-sections'],
- {'default': True,
- 'action': 'store_true',
- 'dest': 'create_sections',
- 'validator': frontend.validate_boolean}),
- ('Do not create sections for headers.',
- ['--no-sections'],
- {'default': True,
- 'action': 'store_false',
- 'dest': 'create_sections',
- 'validator': frontend.validate_boolean}),
- ('Create links.',
- ['--create-links'],
- {'default': False,
- 'action': 'store_true',
- 'dest': 'create_links',
- 'validator': frontend.validate_boolean}),
- ('Do not create links. (default)',
- ['--no-links'],
- {'default': False,
- 'action': 'store_false',
- 'dest': 'create_links',
- 'validator': frontend.validate_boolean}),
- ('Generate endnotes at end of document, not footnotes '
- 'at bottom of page.',
- ['--endnotes-end-doc'],
- {'default': False,
- 'action': 'store_true',
- 'dest': 'endnotes_end_doc',
- 'validator': frontend.validate_boolean}),
- ('Generate footnotes at bottom of page, not endnotes '
- 'at end of document. (default)',
- ['--no-endnotes-end-doc'],
- {'default': False,
- 'action': 'store_false',
- 'dest': 'endnotes_end_doc',
- 'validator': frontend.validate_boolean}),
- ('Generate a bullet list table of contents, not '
- 'an ODF/oowriter table of contents.',
- ['--generate-list-toc'],
- {'default': True,
- 'action': 'store_false',
- 'dest': 'generate_oowriter_toc',
- 'validator': frontend.validate_boolean}),
- ('Generate an ODF/oowriter table of contents, not '
- 'a bullet list. (default)',
- ['--generate-oowriter-toc'],
- {'default': True,
- 'action': 'store_true',
- 'dest': 'generate_oowriter_toc',
- 'validator': frontend.validate_boolean}),
- ('Specify the contents of an custom header line. '
- 'See odf_odt writer documentation for details '
- 'about special field character sequences.',
- ['--custom-odt-header'],
- { 'default': '',
- 'dest': 'custom_header',
- }),
- ('Specify the contents of an custom footer line. '
- 'See odf_odt writer documentation for details '
- 'about special field character sequences.',
- ['--custom-odt-footer'],
- { 'default': '',
- 'dest': 'custom_footer',
- }),
- )
- )
- settings_defaults = {
- 'output_encoding_error_handler': 'xmlcharrefreplace',
- }
- relative_path_settings = (
- 'stylesheet_path',
- )
- config_section = 'opendocument odf writer'
- config_section_dependencies = (
- 'writers',
- )
- def __init__(self):
- writers.Writer.__init__(self)
- self.translator_class = ODFTranslator
- def translate(self):
- self.settings = self.document.settings
- self.visitor = self.translator_class(self.document)
- self.visitor.retrieve_styles(self.EXTENSION)
- self.document.walkabout(self.visitor)
- self.visitor.add_doc_title()
- self.assemble_my_parts()
- self.output = self.parts['whole']
- def assemble_my_parts(self):
- """Assemble the `self.parts` dictionary. Extend in subclasses.
- """
- writers.Writer.assemble_parts(self)
- f = tempfile.NamedTemporaryFile()
- zfile = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
- self.write_zip_str(zfile, 'mimetype', self.MIME_TYPE,
- compress_type=zipfile.ZIP_STORED)
- content = self.visitor.content_astext()
- self.write_zip_str(zfile, 'content.xml', content)
- s1 = self.create_manifest()
- self.write_zip_str(zfile, 'META-INF/manifest.xml', s1)
- s1 = self.create_meta()
- self.write_zip_str(zfile, 'meta.xml', s1)
- s1 = self.get_stylesheet()
- self.write_zip_str(zfile, 'styles.xml', s1)
- self.store_embedded_files(zfile)
- self.copy_from_stylesheet(zfile)
- zfile.close()
- f.seek(0)
- whole = f.read()
- f.close()
- self.parts['whole'] = whole
- self.parts['encoding'] = self.document.settings.output_encoding
- self.parts['version'] = docutils.__version__
- def write_zip_str(self, zfile, name, bytes, compress_type=zipfile.ZIP_DEFLATED):
- localtime = time.localtime(time.time())
- zinfo = zipfile.ZipInfo(name, localtime)
- # Add some standard UNIX file access permissions (-rw-r--r--).
- zinfo.external_attr = (0x81a4 & 0xFFFF) << 16
- zinfo.compress_type = compress_type
- zfile.writestr(zinfo, bytes)
- def store_embedded_files(self, zfile):
- embedded_files = self.visitor.get_embedded_file_list()
- for source, destination in embedded_files:
- if source is None:
- continue
- try:
- # encode/decode
- destination1 = destination.decode('latin-1').encode('utf-8')
- zfile.write(source, destination1)
- except OSError as e:
- self.document.reporter.warning(
- "Can't open file %s." % (source, ))
- def get_settings(self):
- """
- modeled after get_stylesheet
- """
- stylespath = self.settings.stylesheet
- zfile = zipfile.ZipFile(stylespath, 'r')
- s1 = zfile.read('settings.xml')
- zfile.close()
- return s1
- def get_stylesheet(self):
- """Get the stylesheet from the visitor.
- Ask the visitor to setup the page.
- """
- s1 = self.visitor.setup_page()
- return s1
- def copy_from_stylesheet(self, outzipfile):
- """Copy images, settings, etc from the stylesheet doc into target doc.
- """
- stylespath = self.settings.stylesheet
- inzipfile = zipfile.ZipFile(stylespath, 'r')
- # Copy the styles.
- s1 = inzipfile.read('settings.xml')
- self.write_zip_str(outzipfile, 'settings.xml', s1)
- # Copy the images.
- namelist = inzipfile.namelist()
- for name in namelist:
- if name.startswith('Pictures/'):
- imageobj = inzipfile.read(name)
- outzipfile.writestr(name, imageobj)
- inzipfile.close()
- def assemble_parts(self):
- pass
- def create_manifest(self):
- if WhichElementTree == 'lxml':
- root = Element('manifest:manifest',
- nsmap=MANIFEST_NAMESPACE_DICT,
- nsdict=MANIFEST_NAMESPACE_DICT,
- )
- else:
- root = Element('manifest:manifest',
- attrib=MANIFEST_NAMESPACE_ATTRIB,
- nsdict=MANIFEST_NAMESPACE_DICT,
- )
- doc = etree.ElementTree(root)
- SubElement(root, 'manifest:file-entry', attrib={
- 'manifest:media-type': self.MIME_TYPE,
- 'manifest:full-path': '/',
- }, nsdict=MANNSD)
- SubElement(root, 'manifest:file-entry', attrib={
- 'manifest:media-type': 'text/xml',
- 'manifest:full-path': 'content.xml',
- }, nsdict=MANNSD)
- SubElement(root, 'manifest:file-entry', attrib={
- 'manifest:media-type': 'text/xml',
- 'manifest:full-path': 'styles.xml',
- }, nsdict=MANNSD)
- SubElement(root, 'manifest:file-entry', attrib={
- 'manifest:media-type': 'text/xml',
- 'manifest:full-path': 'settings.xml',
- }, nsdict=MANNSD)
- SubElement(root, 'manifest:file-entry', attrib={
- 'manifest:media-type': 'text/xml',
- 'manifest:full-path': 'meta.xml',
- }, nsdict=MANNSD)
- s1 = ToString(doc)
- doc = minidom.parseString(s1)
- s1 = doc.toprettyxml(' ')
- return s1
- def create_meta(self):
- if WhichElementTree == 'lxml':
- root = Element('office:document-meta',
- nsmap=META_NAMESPACE_DICT,
- nsdict=META_NAMESPACE_DICT,
- )
- else:
- root = Element('office:document-meta',
- attrib=META_NAMESPACE_ATTRIB,
- nsdict=META_NAMESPACE_DICT,
- )
- doc = etree.ElementTree(root)
- root = SubElement(root, 'office:meta', nsdict=METNSD)
- el1 = SubElement(root, 'meta:generator', nsdict=METNSD)
- el1.text = 'Docutils/rst2odf.py/%s' % (VERSION, )
- s1 = os.environ.get('USER', '')
- el1 = SubElement(root, 'meta:initial-creator', nsdict=METNSD)
- el1.text = s1
- s2 = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime())
- el1 = SubElement(root, 'meta:creation-date', nsdict=METNSD)
- el1.text = s2
- el1 = SubElement(root, 'dc:creator', nsdict=METNSD)
- el1.text = s1
- el1 = SubElement(root, 'dc:date', nsdict=METNSD)
- el1.text = s2
- el1 = SubElement(root, 'dc:language', nsdict=METNSD)
- el1.text = 'en-US'
- el1 = SubElement(root, 'meta:editing-cycles', nsdict=METNSD)
- el1.text = '1'
- el1 = SubElement(root, 'meta:editing-duration', nsdict=METNSD)
- el1.text = 'PT00M01S'
- title = self.visitor.get_title()
- el1 = SubElement(root, 'dc:title', nsdict=METNSD)
- if title:
- el1.text = title
- else:
- el1.text = '[no title]'
- meta_dict = self.visitor.get_meta_dict()
- keywordstr = meta_dict.get('keywords')
- if keywordstr is not None:
- keywords = split_words(keywordstr)
- for keyword in keywords:
- el1 = SubElement(root, 'meta:keyword', nsdict=METNSD)
- el1.text = keyword
- description = meta_dict.get('description')
- if description is not None:
- el1 = SubElement(root, 'dc:description', nsdict=METNSD)
- el1.text = description
- s1 = ToString(doc)
- #doc = minidom.parseString(s1)
- #s1 = doc.toprettyxml(' ')
- return s1
- # class ODFTranslator(nodes.SparseNodeVisitor):
- class ODFTranslator(nodes.GenericNodeVisitor):
- used_styles = (
- 'attribution', 'blockindent', 'blockquote', 'blockquote-bulletitem',
- 'blockquote-bulletlist', 'blockquote-enumitem', 'blockquote-enumlist',
- 'bulletitem', 'bulletlist',
- 'caption', 'legend',
- 'centeredtextbody', 'codeblock', 'codeblock-indented',
- 'codeblock-classname', 'codeblock-comment', 'codeblock-functionname',
- 'codeblock-keyword', 'codeblock-name', 'codeblock-number',
- 'codeblock-operator', 'codeblock-string', 'emphasis', 'enumitem',
- 'enumlist', 'epigraph', 'epigraph-bulletitem', 'epigraph-bulletlist',
- 'epigraph-enumitem', 'epigraph-enumlist', 'footer',
- 'footnote', 'citation',
- 'header', 'highlights', 'highlights-bulletitem',
- 'highlights-bulletlist', 'highlights-enumitem', 'highlights-enumlist',
- 'horizontalline', 'inlineliteral', 'quotation', 'rubric',
- 'strong', 'table-title', 'textbody', 'tocbulletlist', 'tocenumlist',
- 'title',
- 'subtitle',
- 'heading1',
- 'heading2',
- 'heading3',
- 'heading4',
- 'heading5',
- 'heading6',
- 'heading7',
- 'admon-attention-hdr',
- 'admon-attention-body',
- 'admon-caution-hdr',
- 'admon-caution-body',
- 'admon-danger-hdr',
- 'admon-danger-body',
- 'admon-error-hdr',
- 'admon-error-body',
- 'admon-generic-hdr',
- 'admon-generic-body',
- 'admon-hint-hdr',
- 'admon-hint-body',
- 'admon-important-hdr',
- 'admon-important-body',
- 'admon-note-hdr',
- 'admon-note-body',
- 'admon-tip-hdr',
- 'admon-tip-body',
- 'admon-warning-hdr',
- 'admon-warning-body',
- 'tableoption',
- 'tableoption.%c', 'tableoption.%c%d', 'Table%d', 'Table%d.%c',
- 'Table%d.%c%d',
- 'lineblock1',
- 'lineblock2',
- 'lineblock3',
- 'lineblock4',
- 'lineblock5',
- 'lineblock6',
- 'image', 'figureframe',
- )
- def __init__(self, document):
- #nodes.SparseNodeVisitor.__init__(self, document)
- nodes.GenericNodeVisitor.__init__(self, document)
- self.settings = document.settings
- lcode = self.settings.language_code
- self.language = languages.get_language(lcode, document.reporter)
- self.format_map = { }
- if self.settings.odf_config_file:
- from configparser import ConfigParser
- parser = ConfigParser()
- parser.read(self.settings.odf_config_file)
- for rststyle, format in parser.items("Formats"):
- if rststyle not in self.used_styles:
- self.document.reporter.warning(
- 'Style "%s" is not a style used by odtwriter.' % (
- rststyle, ))
- self.format_map[rststyle] = format.decode('utf-8')
- self.section_level = 0
- self.section_count = 0
- # Create ElementTree content and styles documents.
- if WhichElementTree == 'lxml':
- root = Element(
- 'office:document-content',
- nsmap=CONTENT_NAMESPACE_DICT,
- )
- else:
- root = Element(
- 'office:document-content',
- attrib=CONTENT_NAMESPACE_ATTRIB,
- )
- self.content_tree = etree.ElementTree(element=root)
- self.current_element = root
- SubElement(root, 'office:scripts')
- SubElement(root, 'office:font-face-decls')
- el = SubElement(root, 'office:automatic-styles')
- self.automatic_styles = el
- el = SubElement(root, 'office:body')
- el = self.generate_content_element(el)
- self.current_element = el
- self.body_text_element = el
- self.paragraph_style_stack = [self.rststyle('textbody'), ]
- self.list_style_stack = []
- self.table_count = 0
- self.column_count = ord('A') - 1
- self.trace_level = -1
- self.optiontablestyles_generated = False
- self.field_name = None
- self.field_element = None
- self.title = None
- self.image_count = 0
- self.image_style_count = 0
- self.image_dict = {}
- self.embedded_file_list = []
- self.syntaxhighlighting = 1
- self.syntaxhighlight_lexer = 'python'
- self.header_content = []
- self.footer_content = []
- self.in_header = False
- self.in_footer = False
- self.blockstyle = ''
- self.in_table_of_contents = False
- self.table_of_content_index_body = None
- self.list_level = 0
- self.def_list_level = 0
- self.footnote_ref_dict = {}
- self.footnote_list = []
- self.footnote_chars_idx = 0
- self.footnote_level = 0
- self.pending_ids = [ ]
- self.in_paragraph = False
- self.found_doc_title = False
- self.bumped_list_level_stack = []
- self.meta_dict = {}
- self.line_block_level = 0
- self.line_indent_level = 0
- self.citation_id = None
- self.style_index = 0 # use to form unique style names
- self.str_stylesheet = ''
- self.str_stylesheetcontent = ''
- self.dom_stylesheet = None
- self.table_styles = None
- self.in_citation = False
- def get_str_stylesheet(self):
- return self.str_stylesheet
- def retrieve_styles(self, extension):
- """Retrieve the stylesheet from either a .xml file or from
- a .odt (zip) file. Return the content as a string.
- """
- s2 = None
- stylespath = self.settings.stylesheet
- ext = os.path.splitext(stylespath)[1]
- if ext == '.xml':
- stylesfile = open(stylespath, 'r')
- s1 = stylesfile.read()
- stylesfile.close()
- elif ext == extension:
- zfile = zipfile.ZipFile(stylespath, 'r')
- s1 = zfile.read('styles.xml')
- s2 = zfile.read('content.xml')
- zfile.close()
- else:
- raise RuntimeError('stylesheet path (%s) must be %s or .xml file' %(stylespath, extension))
- self.str_stylesheet = s1
- self.str_stylesheetcontent = s2
- self.dom_stylesheet = etree.fromstring(self.str_stylesheet)
- self.dom_stylesheetcontent = etree.fromstring(self.str_stylesheetcontent)
- self.table_styles = self.extract_table_styles(s2)
- def extract_table_styles(self, styles_str):
- root = etree.fromstring(styles_str)
- table_styles = {}
- auto_styles = root.find(
- '{%s}automatic-styles' % (CNSD['office'], ))
- for stylenode in auto_styles:
- name = stylenode.get('{%s}name' % (CNSD['style'], ))
- tablename = name.split('.')[0]
- family = stylenode.get('{%s}family' % (CNSD['style'], ))
- if name.startswith(TABLESTYLEPREFIX):
- tablestyle = table_styles.get(tablename)
- if tablestyle is None:
- tablestyle = TableStyle()
- table_styles[tablename] = tablestyle
- if family == 'table':
- properties = stylenode.find(
- '{%s}table-properties' % (CNSD['style'], ))
- property = properties.get('{%s}%s' % (CNSD['fo'],
- 'background-color', ))
- if property is not None and property != 'none':
- tablestyle.backgroundcolor = property
- elif family == 'table-cell':
- properties = stylenode.find(
- '{%s}table-cell-properties' % (CNSD['style'], ))
- if properties is not None:
- border = self.get_property(properties)
- if border is not None:
- tablestyle.border = border
- return table_styles
- def get_property(self, stylenode):
- border = None
- for propertyname in TABLEPROPERTYNAMES:
- border = stylenode.get('{%s}%s' % (CNSD['fo'], propertyname, ))
- if border is not None and border != 'none':
- return border
- return border
- def add_doc_title(self):
- text = self.settings.title
- if text:
- self.title = text
- if not self.found_doc_title:
- el = Element('text:p', attrib = {
- 'text:style-name': self.rststyle('title'),
- })
- el.text = text
- self.body_text_element.insert(0, el)
- def rststyle(self, name, parameters=( )):
- """
- Returns the style name to use for the given style.
- If `parameters` is given `name` must contain a matching number of ``%`` and
- is used as a format expression with `parameters` as the value.
- """
- name1 = name % parameters
- stylename = self.format_map.get(name1, 'rststyle-%s' % name1)
- return stylename
- def generate_content_element(self, root):
- return SubElement(root, 'office:text')
- def setup_page(self):
- self.setup_paper(self.dom_stylesheet)
- if (len(self.header_content) > 0 or len(self.footer_content) > 0 or
- self.settings.custom_header or self.settings.custom_footer):
- self.add_header_footer(self.dom_stylesheet)
- new_content = etree.tostring(self.dom_stylesheet)
- return new_content
- def setup_paper(self, root_el):
- try:
- fin = os.popen("paperconf -s 2> /dev/null")
- w, h = list(map(float, fin.read().split()))
- fin.close()
- except:
- w, h = 612, 792 # default to Letter
- def walk(el):
- if el.tag == "{%s}page-layout-properties" % SNSD["style"] and \
- "{%s}page-width" % SNSD["fo"] not in el.attrib:
- el.attrib["{%s}page-width" % SNSD["fo"]] = "%.3fpt" % w
- el.attrib["{%s}page-height" % SNSD["fo"]] = "%.3fpt" % h
- el.attrib["{%s}margin-left" % SNSD["fo"]] = \
- el.attrib["{%s}margin-right" % SNSD["fo"]] = \
- "%.3fpt" % (.1 * w)
- el.attrib["{%s}margin-top" % SNSD["fo"]] = \
- el.attrib["{%s}margin-bottom" % SNSD["fo"]] = \
- "%.3fpt" % (.1 * h)
- else:
- for subel in el.getchildren(): walk(subel)
- walk(root_el)
- def add_header_footer(self, root_el):
- automatic_styles = root_el.find(
- '{%s}automatic-styles' % SNSD['office'])
- path = '{%s}master-styles' % (NAME_SPACE_1, )
- master_el = root_el.find(path)
- if master_el is None:
- return
- path = '{%s}master-page' % (SNSD['style'], )
- master_el = master_el.find(path)
- if master_el is None:
- return
- el1 = master_el
- if self.header_content or self.settings.custom_header:
- if WhichElementTree == 'lxml':
- el2 = SubElement(el1, 'style:header', nsdict=SNSD)
- else:
- el2 = SubElement(el1, 'style:header',
- attrib=STYLES_NAMESPACE_ATTRIB,
- nsdict=STYLES_NAMESPACE_DICT,
- )
- for el in self.header_content:
- attrkey = add_ns('text:style-name', nsdict=SNSD)
- el.attrib[attrkey] = self.rststyle('header')
- el2.append(el)
- if self.settings.custom_header:
- elcustom = self.create_custom_headfoot(el2,
- self.settings.custom_header, 'header', automatic_styles)
- if self.footer_content or self.settings.custom_footer:
- if WhichElementTree == 'lxml':
- el2 = SubElement(el1, 'style:footer', nsdict=SNSD)
- else:
- el2 = SubElement(el1, 'style:footer',
- attrib=STYLES_NAMESPACE_ATTRIB,
- nsdict=STYLES_NAMESPACE_DICT,
- )
- for el in self.footer_content:
- attrkey = add_ns('text:style-name', nsdict=SNSD)
- el.attrib[attrkey] = self.rststyle('footer')
- el2.append(el)
- if self.settings.custom_footer:
- elcustom = self.create_custom_headfoot(el2,
- self.settings.custom_footer, 'footer', automatic_styles)
- code_none, code_field, code_text = list(range(3))
- field_pat = re.compile(r'%(..?)%')
- def create_custom_headfoot(self, parent, text, style_name, automatic_styles):
- parent = SubElement(parent, 'text:p', attrib={
- 'text:style-name': self.rststyle(style_name),
- })
- current_element = None
- field_iter = self.split_field_specifiers_iter(text)
- for item in field_iter:
- if item[0] == ODFTranslator.code_field:
- if item[1] not in ('p', 'P',
- 't1', 't2', 't3', 't4',
- 'd1', 'd2', 'd3', 'd4', 'd5',
- 's', 't', 'a'):
- msg = 'bad field spec: %%%s%%' % (item[1], )
- raise RuntimeError(msg)
- el1 = self.make_field_element(parent,
- item[1], style_name, automatic_styles)
- if el1 is None:
- msg = 'bad field spec: %%%s%%' % (item[1], )
- raise RuntimeError(msg)
- else:
- current_element = el1
- else:
- if current_element is None:
- parent.text = item[1]
- else:
- current_element.tail = item[1]
- def make_field_element(self, parent, text, style_name, automatic_styles):
- if text == 'p':
- el1 = SubElement(parent, 'text:page-number', attrib={
- #'text:style-name': self.rststyle(style_name),
- 'text:select-page': 'current',
- })
- elif text == 'P':
- el1 = SubElement(parent, 'text:page-count', attrib={
- #'text:style-name': self.rststyle(style_name),
- })
- elif text == 't1':
- self.style_index += 1
- el1 = SubElement(parent, 'text:time', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'text:fixed': 'true',
- 'style:data-style-name': 'rst-time-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:time-style', attrib={
- 'style:name': 'rst-time-style-%d' % self.style_index,
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:hours', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:minutes', attrib={
- 'number:style': 'long',
- })
- elif text == 't2':
- self.style_index += 1
- el1 = SubElement(parent, 'text:time', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'text:fixed': 'true',
- 'style:data-style-name': 'rst-time-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:time-style', attrib={
- 'style:name': 'rst-time-style-%d' % self.style_index,
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:hours', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:minutes', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:seconds', attrib={
- 'number:style': 'long',
- })
- elif text == 't3':
- self.style_index += 1
- el1 = SubElement(parent, 'text:time', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'text:fixed': 'true',
- 'style:data-style-name': 'rst-time-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:time-style', attrib={
- 'style:name': 'rst-time-style-%d' % self.style_index,
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:hours', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:minutes', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ' '
- el3 = SubElement(el2, 'number:am-pm')
- elif text == 't4':
- self.style_index += 1
- el1 = SubElement(parent, 'text:time', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'text:fixed': 'true',
- 'style:data-style-name': 'rst-time-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:time-style', attrib={
- 'style:name': 'rst-time-style-%d' % self.style_index,
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:hours', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:minutes', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ':'
- el3 = SubElement(el2, 'number:seconds', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ' '
- el3 = SubElement(el2, 'number:am-pm')
- elif text == 'd1':
- self.style_index += 1
- el1 = SubElement(parent, 'text:date', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'style:data-style-name': 'rst-date-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:date-style', attrib={
- 'style:name': 'rst-date-style-%d' % self.style_index,
- 'number:automatic-order': 'true',
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:month', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '/'
- el3 = SubElement(el2, 'number:day', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '/'
- el3 = SubElement(el2, 'number:year')
- elif text == 'd2':
- self.style_index += 1
- el1 = SubElement(parent, 'text:date', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'style:data-style-name': 'rst-date-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:date-style', attrib={
- 'style:name': 'rst-date-style-%d' % self.style_index,
- 'number:automatic-order': 'true',
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:month', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '/'
- el3 = SubElement(el2, 'number:day', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '/'
- el3 = SubElement(el2, 'number:year', attrib={
- 'number:style': 'long',
- })
- elif text == 'd3':
- self.style_index += 1
- el1 = SubElement(parent, 'text:date', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'style:data-style-name': 'rst-date-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:date-style', attrib={
- 'style:name': 'rst-date-style-%d' % self.style_index,
- 'number:automatic-order': 'true',
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:month', attrib={
- 'number:textual': 'true',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ' '
- el3 = SubElement(el2, 'number:day', attrib={
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ', '
- el3 = SubElement(el2, 'number:year', attrib={
- 'number:style': 'long',
- })
- elif text == 'd4':
- self.style_index += 1
- el1 = SubElement(parent, 'text:date', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'style:data-style-name': 'rst-date-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:date-style', attrib={
- 'style:name': 'rst-date-style-%d' % self.style_index,
- 'number:automatic-order': 'true',
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:month', attrib={
- 'number:textual': 'true',
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ' '
- el3 = SubElement(el2, 'number:day', attrib={
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = ', '
- el3 = SubElement(el2, 'number:year', attrib={
- 'number:style': 'long',
- })
- elif text == 'd5':
- self.style_index += 1
- el1 = SubElement(parent, 'text:date', attrib={
- 'text:style-name': self.rststyle(style_name),
- 'style:data-style-name': 'rst-date-style-%d' % self.style_index,
- })
- el2 = SubElement(automatic_styles, 'number:date-style', attrib={
- 'style:name': 'rst-date-style-%d' % self.style_index,
- 'xmlns:number': SNSD['number'],
- 'xmlns:style': SNSD['style'],
- })
- el3 = SubElement(el2, 'number:year', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '-'
- el3 = SubElement(el2, 'number:month', attrib={
- 'number:style': 'long',
- })
- el3 = SubElement(el2, 'number:text')
- el3.text = '-'
- el3 = SubElement(el2, 'number:day', attrib={
- 'number:style': 'long',
- })
- elif text == 's':
- el1 = SubElement(parent, 'text:subject', attrib={
- 'text:style-name': self.rststyle(style_name),
- })
- elif text == 't':
- el1 = SubElement(parent, 'text:title', attrib={
- 'text:style-name': self.rststyle(style_name),
- })
- elif text == 'a':
- el1 = SubElement(parent, 'text:author-name', attrib={
- 'text:fixed': 'false',
- })
- else:
- el1 = None
- return el1
- def split_field_specifiers_iter(self, text):
- pos1 = 0
- pos_end = len(text)
- while True:
- mo = ODFTranslator.field_pat.search(text, pos1)
- if mo:
- pos2 = mo.start()
- if pos2 > pos1:
- yield (ODFTranslator.code_text, text[pos1:pos2])
- yield (ODFTranslator.code_field, mo.group(1))
- pos1 = mo.end()
- else:
- break
- trailing = text[pos1:]
- if trailing:
- yield (ODFTranslator.code_text, trailing)
- def astext(self):
- root = self.content_tree.getroot()
- et = etree.ElementTree(root)
- s1 = ToString(et)
- return s1
- def content_astext(self):
- return self.astext()
- def set_title(self, title): self.title = title
- def get_title(self): return self.title
- def set_embedded_file_list(self, embedded_file_list):
- self.embedded_file_list = embedded_file_list
- def get_embedded_file_list(self): return self.embedded_file_list
- def get_meta_dict(self): return self.meta_dict
- def process_footnotes(self):
- for node, el1 in self.footnote_list:
- backrefs = node.attributes.get('backrefs', [])
- first = True
- for ref in backrefs:
- el2 = self.footnote_ref_dict.get(ref)
- if el2 is not None:
- if first:
- first = False
- el3 = copy.deepcopy(el1)
- el2.append(el3)
- else:
- children = el2.getchildren()
- if len(children) > 0: # and 'id' in el2.attrib:
- child = children[0]
- ref1 = child.text
- attribkey = add_ns('text:id', nsdict=SNSD)
- id1 = el2.get(attribkey, 'footnote-error')
- if id1 is None:
- id1 = ''
- tag = add_ns('text:note-ref', nsdict=SNSD)
- el2.tag = tag
- if self.settings.endnotes_end_doc:
- note_class = 'endnote'
- else:
- note_class = 'footnote'
- el2.attrib.clear()
- attribkey = add_ns('text:note-class', nsdict=SNSD)
- el2.attrib[attribkey] = note_class
- attribkey = add_ns('text:ref-name', nsdict=SNSD)
- el2.attrib[attribkey] = id1
- attribkey = add_ns('text:reference-format', nsdict=SNSD)
- el2.attrib[attribkey] = 'page'
- el2.text = ref1
- #
- # Utility methods
- def append_child(self, tag, attrib=None, parent=None):
- if parent is None:
- parent = self.current_element
- if attrib is None:
- el = SubElement(parent, tag)
- else:
- el = SubElement(parent, tag, attrib)
- return el
- def append_p(self, style, text=None):
- result = self.append_child('text:p', attrib={
- 'text:style-name': self.rststyle(style)})
- self.append_pending_ids(result)
- if text is not None:
- result.text = text
- return result
- def append_pending_ids(self, el):
- if self.settings.create_links:
- for id in self.pending_ids:
- SubElement(el, 'text:reference-mark', attrib={
- 'text:name': id})
- self.pending_ids = [ ]
- def set_current_element(self, el):
- self.current_element = el
- def set_to_parent(self):
- self.current_element = self.current_element.getparent()
- def generate_labeled_block(self, node, label):
- label = '%s:' % (self.language.labels[label], )
- el = self.append_p('textbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- el1.text = label
- el = self.append_p('blockindent')
- return el
- def generate_labeled_line(self, node, label):
- label = '%s:' % (self.language.labels[label], )
- el = self.append_p('textbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- el1.text = label
- el1.tail = node.astext()
- return el
- def encode(self, text):
- text = text.replace('\u00a0', " ")
- return text
- #
- # Visitor functions
- #
- # In alphabetic order, more or less.
- # See docutils.docutils.nodes.node_class_names.
- #
- def dispatch_visit(self, node):
- """Override to catch basic attributes which many nodes have."""
- self.handle_basic_atts(node)
- nodes.GenericNodeVisitor.dispatch_visit(self, node)
- def handle_basic_atts(self, node):
- if isinstance(node, nodes.Element) and node['ids']:
- self.pending_ids += node['ids']
- def default_visit(self, node):
- self.document.reporter.warning('missing visit_%s' % (node.tagname, ))
- def default_departure(self, node):
- self.document.reporter.warning('missing depart_%s' % (node.tagname, ))
- ## def add_text_to_element(self, text):
- ## # Are we in a citation. If so, add text to current element, not
- ## # to children.
- ## # Are we in mixed content? If so, add the text to the
- ## # etree tail of the previous sibling element.
- ## if not self.in_citation and len(self.current_element.getchildren()) > 0:
- ## if self.current_element.getchildren()[-1].tail:
- ## self.current_element.getchildren()[-1].tail += text
- ## else:
- ## self.current_element.getchildren()[-1].tail = text
- ## else:
- ## if self.current_element.text:
- ## self.current_element.text += text
- ## else:
- ## self.current_element.text = text
- ##
- ## def visit_Text(self, node):
- ## # Skip nodes whose text has been processed in parent nodes.
- ## if isinstance(node.parent, docutils.nodes.literal_block):
- ## return
- ## text = node.astext()
- ## self.add_text_to_element(text)
- def visit_Text(self, node):
- # Skip nodes whose text has been processed in parent nodes.
- if isinstance(node.parent, docutils.nodes.literal_block):
- return
- text = node.astext()
- # Are we in mixed content? If so, add the text to the
- # etree tail of the previous sibling element.
- if len(self.current_element.getchildren()) > 0:
- if self.current_element.getchildren()[-1].tail:
- self.current_element.getchildren()[-1].tail += text
- else:
- self.current_element.getchildren()[-1].tail = text
- else:
- if self.current_element.text:
- self.current_element.text += text
- else:
- self.current_element.text = text
- def depart_Text(self, node):
- pass
- #
- # Pre-defined fields
- #
- def visit_address(self, node):
- el = self.generate_labeled_block(node, 'address')
- self.set_current_element(el)
- def depart_address(self, node):
- self.set_to_parent()
- def visit_author(self, node):
- if isinstance(node.parent, nodes.authors):
- el = self.append_p('blockindent')
- else:
- el = self.generate_labeled_block(node, 'author')
- self.set_current_element(el)
- def depart_author(self, node):
- self.set_to_parent()
- def visit_authors(self, node):
- label = '%s:' % (self.language.labels['authors'], )
- el = self.append_p('textbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- el1.text = label
- def depart_authors(self, node):
- pass
- def visit_contact(self, node):
- el = self.generate_labeled_block(node, 'contact')
- self.set_current_element(el)
- def depart_contact(self, node):
- self.set_to_parent()
- def visit_copyright(self, node):
- el = self.generate_labeled_block(node, 'copyright')
- self.set_current_element(el)
- def depart_copyright(self, node):
- self.set_to_parent()
- def visit_date(self, node):
- self.generate_labeled_line(node, 'date')
- def depart_date(self, node):
- pass
- def visit_organization(self, node):
- el = self.generate_labeled_block(node, 'organization')
- self.set_current_element(el)
- def depart_organization(self, node):
- self.set_to_parent()
- def visit_status(self, node):
- el = self.generate_labeled_block(node, 'status')
- self.set_current_element(el)
- def depart_status(self, node):
- self.set_to_parent()
- def visit_revision(self, node):
- el = self.generate_labeled_line(node, 'revision')
- def depart_revision(self, node):
- pass
- def visit_version(self, node):
- el = self.generate_labeled_line(node, 'version')
- #self.set_current_element(el)
- def depart_version(self, node):
- #self.set_to_parent()
- pass
- def visit_attribution(self, node):
- el = self.append_p('attribution', node.astext())
- def depart_attribution(self, node):
- pass
- def visit_block_quote(self, node):
- if 'epigraph' in node.attributes['classes']:
- self.paragraph_style_stack.append(self.rststyle('epigraph'))
- self.blockstyle = self.rststyle('epigraph')
- elif 'highlights' in node.attributes['classes']:
- self.paragraph_style_stack.append(self.rststyle('highlights'))
- self.blockstyle = self.rststyle('highlights')
- else:
- self.paragraph_style_stack.append(self.rststyle('blockquote'))
- self.blockstyle = self.rststyle('blockquote')
- self.line_indent_level += 1
- def depart_block_quote(self, node):
- self.paragraph_style_stack.pop()
- self.blockstyle = ''
- self.line_indent_level -= 1
- def visit_bullet_list(self, node):
- self.list_level +=1
- if self.in_table_of_contents:
- if self.settings.generate_oowriter_toc:
- pass
- else:
- if 'classes' in node and \
- 'auto-toc' in node.attributes['classes']:
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('tocenumlist'),
- })
- self.list_style_stack.append(self.rststyle('enumitem'))
- else:
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('tocbulletlist'),
- })
- self.list_style_stack.append(self.rststyle('bulletitem'))
- self.set_current_element(el)
- else:
- if self.blockstyle == self.rststyle('blockquote'):
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('blockquote-bulletlist'),
- })
- self.list_style_stack.append(
- self.rststyle('blockquote-bulletitem'))
- elif self.blockstyle == self.rststyle('highlights'):
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('highlights-bulletlist'),
- })
- self.list_style_stack.append(
- self.rststyle('highlights-bulletitem'))
- elif self.blockstyle == self.rststyle('epigraph'):
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('epigraph-bulletlist'),
- })
- self.list_style_stack.append(
- self.rststyle('epigraph-bulletitem'))
- else:
- el = SubElement(self.current_element, 'text:list', attrib={
- 'text:style-name': self.rststyle('bulletlist'),
- })
- self.list_style_stack.append(self.rststyle('bulletitem'))
- self.set_current_element(el)
- def depart_bullet_list(self, node):
- if self.in_table_of_contents:
- if self.settings.generate_oowriter_toc:
- pass
- else:
- self.set_to_parent()
- self.list_style_stack.pop()
- else:
- self.set_to_parent()
- self.list_style_stack.pop()
- self.list_level -=1
- def visit_caption(self, node):
- raise nodes.SkipChildren()
- pass
- def depart_caption(self, node):
- pass
- def visit_comment(self, node):
- el = self.append_p('textbody')
- el1 = SubElement(el, 'office:annotation', attrib={})
- el2 = SubElement(el1, 'dc:creator', attrib={})
- s1 = os.environ.get('USER', '')
- el2.text = s1
- el2 = SubElement(el1, 'text:p', attrib={})
- el2.text = node.astext()
- def depart_comment(self, node):
- pass
- def visit_compound(self, node):
- # The compound directive currently receives no special treatment.
- pass
- def depart_compound(self, node):
- pass
- def visit_container(self, node):
- styles = node.attributes.get('classes', ())
- if len(styles) > 0:
- self.paragraph_style_stack.append(self.rststyle(styles[0]))
- def depart_container(self, node):
- styles = node.attributes.get('classes', ())
- if len(styles) > 0:
- self.paragraph_style_stack.pop()
- def visit_decoration(self, node):
- pass
- def depart_decoration(self, node):
- pass
- def visit_definition_list(self, node):
- self.def_list_level +=1
- if self.list_level > 5:
- raise RuntimeError(
- 'max definition list nesting level exceeded')
- def depart_definition_list(self, node):
- self.def_list_level -=1
- def visit_definition_list_item(self, node):
- pass
- def depart_definition_list_item(self, node):
- pass
- def visit_term(self, node):
- el = self.append_p('deflist-term-%d' % self.def_list_level)
- el.text = node.astext()
- self.set_current_element(el)
- raise nodes.SkipChildren()
- def depart_term(self, node):
- self.set_to_parent()
- def visit_definition(self, node):
- self.paragraph_style_stack.append(
- self.rststyle('deflist-def-%d' % self.def_list_level))
- self.bumped_list_level_stack.append(ListLevel(1))
- def depart_definition(self, node):
- self.paragraph_style_stack.pop()
- self.bumped_list_level_stack.pop()
- def visit_classifier(self, node):
- els = self.current_element.getchildren()
- if len(els) > 0:
- el = els[-1]
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('emphasis')
- })
- el1.text = ' (%s)' % (node.astext(), )
- def depart_classifier(self, node):
- pass
- def visit_document(self, node):
- pass
- def depart_document(self, node):
- self.process_footnotes()
- def visit_docinfo(self, node):
- self.section_level += 1
- self.section_count += 1
- if self.settings.create_sections:
- el = self.append_child('text:section', attrib={
- 'text:name': 'Section%d' % self.section_count,
- 'text:style-name': 'Sect%d' % self.section_level,
- })
- self.set_current_element(el)
- def depart_docinfo(self, node):
- self.section_level -= 1
- if self.settings.create_sections:
- self.set_to_parent()
- def visit_emphasis(self, node):
- el = SubElement(self.current_element, 'text:span',
- attrib={'text:style-name': self.rststyle('emphasis')})
- self.set_current_element(el)
- def depart_emphasis(self, node):
- self.set_to_parent()
- def visit_enumerated_list(self, node):
- el1 = self.current_element
- if self.blockstyle == self.rststyle('blockquote'):
- el2 = SubElement(el1, 'text:list', attrib={
- 'text:style-name': self.rststyle('blockquote-enumlist'),
- })
- self.list_style_stack.append(self.rststyle('blockquote-enumitem'))
- elif self.blockstyle == self.rststyle('highlights'):
- el2 = SubElement(el1, 'text:list', attrib={
- 'text:style-name': self.rststyle('highlights-enumlist'),
- })
- self.list_style_stack.append(self.rststyle('highlights-enumitem'))
- elif self.blockstyle == self.rststyle('epigraph'):
- el2 = SubElement(el1, 'text:list', attrib={
- 'text:style-name': self.rststyle('epigraph-enumlist'),
- })
- self.list_style_stack.append(self.rststyle('epigraph-enumitem'))
- else:
- liststylename = 'enumlist-%s' % (node.get('enumtype', 'arabic'), )
- el2 = SubElement(el1, 'text:list', attrib={
- 'text:style-name': self.rststyle(liststylename),
- })
- self.list_style_stack.append(self.rststyle('enumitem'))
- self.set_current_element(el2)
- def depart_enumerated_list(self, node):
- self.set_to_parent()
- self.list_style_stack.pop()
- def visit_list_item(self, node):
- # If we are in a "bumped" list level, then wrap this
- # list in an outer lists in order to increase the
- # indentation level.
- if self.in_table_of_contents:
- if self.settings.generate_oowriter_toc:
- self.paragraph_style_stack.append(
- self.rststyle('contents-%d' % (self.list_level, )))
- else:
- el1 = self.append_child('text:list-item')
- self.set_current_element(el1)
- else:
- el1 = self.append_child('text:list-item')
- el3 = el1
- if len(self.bumped_list_level_stack) > 0:
- level_obj = self.bumped_list_level_stack[-1]
- if level_obj.get_sibling():
- level_obj.set_nested(False)
- for level_obj1 in self.bumped_list_level_stack:
- for idx in range(level_obj1.get_level()):
- el2 = self.append_child('text:list', parent=el3)
- el3 = self.append_child(
- 'text:list-item', parent=el2)
- self.paragraph_style_stack.append(self.list_style_stack[-1])
- self.set_current_element(el3)
- def depart_list_item(self, node):
- if self.in_table_of_contents:
- if self.settings.generate_oowriter_toc:
- self.paragraph_style_stack.pop()
- else:
- self.set_to_parent()
- else:
- if len(self.bumped_list_level_stack) > 0:
- level_obj = self.bumped_list_level_stack[-1]
- if level_obj.get_sibling():
- level_obj.set_nested(True)
- for level_obj1 in self.bumped_list_level_stack:
- for idx in range(level_obj1.get_level()):
- self.set_to_parent()
- self.set_to_parent()
- self.paragraph_style_stack.pop()
- self.set_to_parent()
- def visit_header(self, node):
- self.in_header = True
- def depart_header(self, node):
- self.in_header = False
- def visit_footer(self, node):
- self.in_footer = True
- def depart_footer(self, node):
- self.in_footer = False
- def visit_field(self, node):
- pass
- def depart_field(self, node):
- pass
- def visit_field_list(self, node):
- pass
- def depart_field_list(self, node):
- pass
- def visit_field_name(self, node):
- el = self.append_p('textbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- el1.text = node.astext()
- def depart_field_name(self, node):
- pass
- def visit_field_body(self, node):
- self.paragraph_style_stack.append(self.rststyle('blockindent'))
- def depart_field_body(self, node):
- self.paragraph_style_stack.pop()
- def visit_figure(self, node):
- pass
- def depart_figure(self, node):
- pass
- def visit_footnote(self, node):
- self.footnote_level += 1
- self.save_footnote_current = self.current_element
- el1 = Element('text:note-body')
- self.current_element = el1
- self.footnote_list.append((node, el1))
- if isinstance(node, docutils.nodes.citation):
- self.paragraph_style_stack.append(self.rststyle('citation'))
- else:
- self.paragraph_style_stack.append(self.rststyle('footnote'))
- def depart_footnote(self, node):
- self.paragraph_style_stack.pop()
- self.current_element = self.save_footnote_current
- self.footnote_level -= 1
- footnote_chars = [
- '*', '**', '***',
- '++', '+++',
- '##', '###',
- '@@', '@@@',
- ]
- def visit_footnote_reference(self, node):
- if self.footnote_level <= 0:
- id = node.attributes['ids'][0]
- refid = node.attributes.get('refid')
- if refid is None:
- refid = ''
- if self.settings.endnotes_end_doc:
- note_class = 'endnote'
- else:
- note_class = 'footnote'
- el1 = self.append_child('text:note', attrib={
- 'text:id': '%s' % (refid, ),
- 'text:note-class': note_class,
- })
- note_auto = str(node.attributes.get('auto', 1))
- if isinstance(node, docutils.nodes.citation_reference):
- citation = '[%s]' % node.astext()
- el2 = SubElement(el1, 'text:note-citation', attrib={
- 'text:label': citation,
- })
- el2.text = citation
- elif note_auto == '1':
- el2 = SubElement(el1, 'text:note-citation', attrib={
- 'text:label': node.astext(),
- })
- el2.text = node.astext()
- elif note_auto == '*':
- if self.footnote_chars_idx >= len(
- ODFTranslator.footnote_chars):
- self.footnote_chars_idx = 0
- footnote_char = ODFTranslator.footnote_chars[
- self.footnote_chars_idx]
- self.footnote_chars_idx += 1
- el2 = SubElement(el1, 'text:note-citation', attrib={
- 'text:label': footnote_char,
- })
- el2.text = footnote_char
- self.footnote_ref_dict[id] = el1
- raise nodes.SkipChildren()
- def depart_footnote_reference(self, node):
- pass
- def visit_citation(self, node):
- self.in_citation = True
- for id in node.attributes['ids']:
- self.citation_id = id
- break
- self.paragraph_style_stack.append(self.rststyle('blockindent'))
- self.bumped_list_level_stack.append(ListLevel(1))
- def depart_citation(self, node):
- self.citation_id = None
- self.paragraph_style_stack.pop()
- self.bumped_list_level_stack.pop()
- self.in_citation = False
- def visit_citation_reference(self, node):
- if self.settings.create_links:
- id = node.attributes['refid']
- el = self.append_child('text:reference-ref', attrib={
- 'text:ref-name': '%s' % (id, ),
- 'text:reference-format': 'text',
- })
- el.text = '['
- self.set_current_element(el)
- elif self.current_element.text is None:
- self.current_element.text = '['
- else:
- self.current_element.text += '['
- def depart_citation_reference(self, node):
- self.current_element.text += ']'
- if self.settings.create_links:
- self.set_to_parent()
- def visit_label(self, node):
- if isinstance(node.parent, docutils.nodes.footnote):
- raise nodes.SkipChildren()
- elif self.citation_id is not None:
- el = self.append_p('textbody')
- self.set_current_element(el)
- el.text = '['
- if self.settings.create_links:
- el1 = self.append_child('text:reference-mark-start', attrib={
- 'text:name': '%s' % (self.citation_id, ),
- })
- def depart_label(self, node):
- if isinstance(node.parent, docutils.nodes.footnote):
- pass
- elif self.citation_id is not None:
- self.current_element.text += ']'
- if self.settings.create_links:
- el = self.append_child('text:reference-mark-end', attrib={
- 'text:name': '%s' % (self.citation_id, ),
- })
- self.set_to_parent()
- def visit_generated(self, node):
- pass
- def depart_generated(self, node):
- pass
- def check_file_exists(self, path):
- if os.path.exists(path):
- return 1
- else:
- return 0
- def visit_image(self, node):
- # Capture the image file.
- if 'uri' in node.attributes:
- source = node.attributes['uri']
- if not source.startswith('http:'):
- if not source.startswith(os.sep):
- docsource, line = utils.get_source_line(node)
- if docsource:
- dirname = os.path.dirname(docsource)
- if dirname:
- source = '%s%s%s' % (dirname, os.sep, source, )
- if not self.check_file_exists(source):
- self.document.reporter.warning(
- 'Cannot find image file %s.' % (source, ))
- return
- else:
- return
- if source in self.image_dict:
- filename, destination = self.image_dict[source]
- else:
- self.image_count += 1
- filename = os.path.split(source)[1]
- destination = 'Pictures/1%08x%s' % (self.image_count, filename, )
- if source.startswith('http:'):
- try:
- imgfile = urllib.request.urlopen(source)
- content = imgfile.read()
- imgfile.close()
- imgfile2 = tempfile.NamedTemporaryFile('wb', delete=False)
- imgfile2.write(content)
- imgfile2.close()
- imgfilename = imgfile2.name
- source = imgfilename
- except urllib.error.HTTPError as e:
- self.document.reporter.warning(
- "Can't open image url %s." % (source, ))
- spec = (source, destination,)
- else:
- spec = (os.path.abspath(source), destination,)
- self.embedded_file_list.append(spec)
- self.image_dict[source] = (source, destination,)
- # Is this a figure (containing an image) or just a plain image?
- if self.in_paragraph:
- el1 = self.current_element
- else:
- el1 = SubElement(self.current_element, 'text:p',
- attrib={'text:style-name': self.rststyle('textbody')})
- el2 = el1
- if isinstance(node.parent, docutils.nodes.figure):
- el3, el4, el5, caption = self.generate_figure(node, source,
- destination, el2)
- attrib = {}
- el6, width = self.generate_image(node, source, destination,
- el5, attrib)
- if caption is not None:
- el6.tail = caption
- else: #if isinstance(node.parent, docutils.nodes.image):
- el3 = self.generate_image(node, source, destination, el2)
- def depart_image(self, node):
- pass
- def get_image_width_height(self, node, attr):
- size = None
- if attr in node.attributes:
- size = node.attributes[attr]
- unit = size[-2:]
- if unit.isalpha():
- size = size[:-2]
- else:
- unit = 'px'
- try:
- size = float(size)
- except ValueError as e:
- self.document.reporter.warning(
- 'Invalid %s for image: "%s"' % (
- attr, node.attributes[attr]))
- size = [size, unit]
- return size
- def get_image_scale(self, node):
- if 'scale' in node.attributes:
- try:
- scale = int(node.attributes['scale'])
- if scale < 1: # or scale > 100:
- self.document.reporter.warning(
- 'scale out of range (%s), using 1.' % (scale, ))
- scale = 1
- scale = scale * 0.01
- except ValueError as e:
- self.document.reporter.warning(
- 'Invalid scale for image: "%s"' % (
- node.attributes['scale'], ))
- else:
- scale = 1.0
- return scale
- def get_image_scaled_width_height(self, node, source):
- scale = self.get_image_scale(node)
- width = self.get_image_width_height(node, 'width')
- height = self.get_image_width_height(node, 'height')
- dpi = (72, 72)
- if PIL is not None and source in self.image_dict:
- filename, destination = self.image_dict[source]
- imageobj = PIL.Image.open(filename, 'r')
- dpi = imageobj.info.get('dpi', dpi)
- # dpi information can be (xdpi, ydpi) or xydpi
- try: iter(dpi)
- except: dpi = (dpi, dpi)
- else:
- imageobj = None
- if width is None or height is None:
- if imageobj is None:
- raise RuntimeError(
- 'image size not fully specified and PIL not installed')
- if width is None: width = [imageobj.size[0], 'px']
- if height is None: height = [imageobj.size[1], 'px']
- width[0] *= scale
- height[0] *= scale
- if width[1] == 'px': width = [width[0] / dpi[0], 'in']
- if height[1] == 'px': height = [height[0] / dpi[1], 'in']
- width[0] = str(width[0])
- height[0] = str(height[0])
- return ''.join(width), ''.join(height)
- def generate_figure(self, node, source, destination, current_element):
- caption = None
- width, height = self.get_image_scaled_width_height(node, source)
- for node1 in node.parent.children:
- if node1.tagname == 'caption':
- caption = node1.astext()
- self.image_style_count += 1
- #
- # Add the style for the caption.
- if caption is not None:
- attrib = {
- 'style:class': 'extra',
- 'style:family': 'paragraph',
- 'style:name': 'Caption',
- 'style:parent-style-name': 'Standard',
- }
- el1 = SubElement(self.automatic_styles, 'style:style',
- attrib=attrib, nsdict=SNSD)
- attrib = {
- 'fo:margin-bottom': '0.0835in',
- 'fo:margin-top': '0.0835in',
- 'text:line-number': '0',
- 'text:number-lines': 'false',
- }
- el2 = SubElement(el1, 'style:paragraph-properties',
- attrib=attrib, nsdict=SNSD)
- attrib = {
- 'fo:font-size': '12pt',
- 'fo:font-style': 'italic',
- 'style:font-name': 'Times',
- 'style:font-name-complex': 'Lucidasans1',
- 'style:font-size-asian': '12pt',
- 'style:font-size-complex': '12pt',
- 'style:font-style-asian': 'italic',
- 'style:font-style-complex': 'italic',
- }
- el2 = SubElement(el1, 'style:text-properties',
- attrib=attrib, nsdict=SNSD)
- style_name = 'rstframestyle%d' % self.image_style_count
- # Add the styles
- attrib = {
- 'style:name': style_name,
- 'style:family': 'graphic',
- 'style:parent-style-name': self.rststyle('figureframe'),
- }
- el1 = SubElement(self.automatic_styles,
- 'style:style', attrib=attrib, nsdict=SNSD)
- halign = 'center'
- valign = 'top'
- if 'align' in node.attributes:
- align = node.attributes['align'].split()
- for val in align:
- if val in ('left', 'center', 'right'):
- halign = val
- elif val in ('top', 'middle', 'bottom'):
- valign = val
- attrib = {}
- wrap = False
- classes = node.parent.attributes.get('classes')
- if classes and 'wrap' in classes:
- wrap = True
- if wrap:
- attrib['style:wrap'] = 'dynamic'
- else:
- attrib['style:wrap'] = 'none'
- el2 = SubElement(el1,
- 'style:graphic-properties', attrib=attrib, nsdict=SNSD)
- attrib = {
- 'draw:style-name': style_name,
- 'draw:name': 'Frame1',
- 'text:anchor-type': 'paragraph',
- 'draw:z-index': '0',
- }
- attrib['svg:width'] = width
- # dbg
- #attrib['svg:height'] = height
- el3 = SubElement(current_element, 'draw:frame', attrib=attrib)
- attrib = {}
- el4 = SubElement(el3, 'draw:text-box', attrib=attrib)
- attrib = {
- 'text:style-name': self.rststyle('caption'),
- }
- el5 = SubElement(el4, 'text:p', attrib=attrib)
- return el3, el4, el5, caption
- def generate_image(self, node, source, destination, current_element,
- frame_attrs=None):
- width, height = self.get_image_scaled_width_height(node, source)
- self.image_style_count += 1
- style_name = 'rstframestyle%d' % self.image_style_count
- # Add the style.
- attrib = {
- 'style:name': style_name,
- 'style:family': 'graphic',
- 'style:parent-style-name': self.rststyle('image'),
- }
- el1 = SubElement(self.automatic_styles,
- 'style:style', attrib=attrib, nsdict=SNSD)
- halign = None
- valign = None
- if 'align' in node.attributes:
- align = node.attributes['align'].split()
- for val in align:
- if val in ('left', 'center', 'right'):
- halign = val
- elif val in ('top', 'middle', 'bottom'):
- valign = val
- if frame_attrs is None:
- attrib = {
- 'style:vertical-pos': 'top',
- 'style:vertical-rel': 'paragraph',
- 'style:horizontal-rel': 'paragraph',
- 'style:mirror': 'none',
- 'fo:clip': 'rect(0cm 0cm 0cm 0cm)',
- 'draw:luminance': '0%',
- 'draw:contrast': '0%',
- 'draw:red': '0%',
- 'draw:green': '0%',
- 'draw:blue': '0%',
- 'draw:gamma': '100%',
- 'draw:color-inversion': 'false',
- 'draw:image-opacity': '100%',
- 'draw:color-mode': 'standard',
- }
- else:
- attrib = frame_attrs
- if halign is not None:
- attrib['style:horizontal-pos'] = halign
- if valign is not None:
- attrib['style:vertical-pos'] = valign
- # If there is a classes/wrap directive or we are
- # inside a table, add a no-wrap style.
- wrap = False
- classes = node.attributes.get('classes')
- if classes and 'wrap' in classes:
- wrap = True
- if wrap:
- attrib['style:wrap'] = 'dynamic'
- else:
- attrib['style:wrap'] = 'none'
- # If we are inside a table, add a no-wrap style.
- if self.is_in_table(node):
- attrib['style:wrap'] = 'none'
- el2 = SubElement(el1,
- 'style:graphic-properties', attrib=attrib, nsdict=SNSD)
- # Add the content.
- #el = SubElement(current_element, 'text:p',
- # attrib={'text:style-name': self.rststyle('textbody')})
- attrib={
- 'draw:style-name': style_name,
- 'draw:name': 'graphics2',
- 'draw:z-index': '1',
- }
- if isinstance(node.parent, nodes.TextElement):
- attrib['text:anchor-type'] = 'as-char' #vds
- else:
- attrib['text:anchor-type'] = 'paragraph'
- attrib['svg:width'] = width
- attrib['svg:height'] = height
- el1 = SubElement(current_element, 'draw:frame', attrib=attrib)
- el2 = SubElement(el1, 'draw:image', attrib={
- 'xlink:href': '%s' % (destination, ),
- 'xlink:type': 'simple',
- 'xlink:show': 'embed',
- 'xlink:actuate': 'onLoad',
- })
- return el1, width
- def is_in_table(self, node):
- node1 = node.parent
- while node1:
- if isinstance(node1, docutils.nodes.entry):
- return True
- node1 = node1.parent
- return False
- def visit_legend(self, node):
- if isinstance(node.parent, docutils.nodes.figure):
- el1 = self.current_element[-1]
- el1 = el1[0][0]
- self.current_element = el1
- self.paragraph_style_stack.append(self.rststyle('legend'))
- def depart_legend(self, node):
- if isinstance(node.parent, docutils.nodes.figure):
- self.paragraph_style_stack.pop()
- self.set_to_parent()
- self.set_to_parent()
- self.set_to_parent()
- def visit_line_block(self, node):
- self.line_indent_level += 1
- self.line_block_level += 1
- def depart_line_block(self, node):
- self.line_indent_level -= 1
- self.line_block_level -= 1
- def visit_line(self, node):
- style = 'lineblock%d' % self.line_indent_level
- el1 = SubElement(self.current_element, 'text:p', attrib={
- 'text:style-name': self.rststyle(style),
- })
- self.current_element = el1
- def depart_line(self, node):
- self.set_to_parent()
- def visit_literal(self, node):
- el = SubElement(self.current_element, 'text:span',
- attrib={'text:style-name': self.rststyle('inlineliteral')})
- self.set_current_element(el)
- def depart_literal(self, node):
- self.set_to_parent()
- def visit_inline(self, node):
- styles = node.attributes.get('classes', ())
- if len(styles) > 0:
- inline_style = styles[0]
- el = SubElement(self.current_element, 'text:span',
- attrib={'text:style-name': self.rststyle(inline_style)})
- self.set_current_element(el)
- def depart_inline(self, node):
- self.set_to_parent()
- def _calculate_code_block_padding(self, line):
- count = 0
- matchobj = SPACES_PATTERN.match(line)
- if matchobj:
- pad = matchobj.group()
- count = len(pad)
- else:
- matchobj = TABS_PATTERN.match(line)
- if matchobj:
- pad = matchobj.group()
- count = len(pad) * 8
- return count
- def _add_syntax_highlighting(self, insource, language):
- lexer = pygments.lexers.get_lexer_by_name(language, stripall=True)
- if language in ('latex', 'tex'):
- fmtr = OdtPygmentsLaTeXFormatter(lambda name, parameters=():
- self.rststyle(name, parameters),
- escape_function=escape_cdata)
- else:
- fmtr = OdtPygmentsProgFormatter(lambda name, parameters=():
- self.rststyle(name, parameters),
- escape_function=escape_cdata)
- outsource = pygments.highlight(insource, lexer, fmtr)
- return outsource
- def fill_line(self, line):
- line = FILL_PAT1.sub(self.fill_func1, line)
- line = FILL_PAT2.sub(self.fill_func2, line)
- return line
- def fill_func1(self, matchobj):
- spaces = matchobj.group(0)
- repl = '<text:s text:c="%d"/>' % (len(spaces), )
- return repl
- def fill_func2(self, matchobj):
- spaces = matchobj.group(0)
- repl = ' <text:s text:c="%d"/>' % (len(spaces) - 1, )
- return repl
- def visit_literal_block(self, node):
- if len(self.paragraph_style_stack) > 1:
- wrapper1 = '<text:p text:style-name="%s">%%s</text:p>' % (
- self.rststyle('codeblock-indented'), )
- else:
- wrapper1 = '<text:p text:style-name="%s">%%s</text:p>' % (
- self.rststyle('codeblock'), )
- source = node.astext()
- if (pygments and
- self.settings.add_syntax_highlighting
- #and
- #node.get('hilight', False)
- ):
- language = node.get('language', 'python')
- source = self._add_syntax_highlighting(source, language)
- else:
- source = escape_cdata(source)
- lines = source.split('\n')
- # If there is an empty last line, remove it.
- if lines[-1] == '':
- del lines[-1]
- lines1 = ['<wrappertag1 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">']
- my_lines = []
- for my_line in lines:
- my_line = self.fill_line(my_line)
- my_line = my_line.replace(" ", "\n")
- my_lines.append(my_line)
- my_lines_str = '<text:line-break/>'.join(my_lines)
- my_lines_str2 = wrapper1 % (my_lines_str, )
- lines1.append(my_lines_str2)
- lines1.append('</wrappertag1>')
- s1 = ''.join(lines1)
- if WhichElementTree != "lxml":
- s1 = s1.encode("utf-8")
- el1 = etree.fromstring(s1)
- children = el1.getchildren()
- for child in children:
- self.current_element.append(child)
- def depart_literal_block(self, node):
- pass
- visit_doctest_block = visit_literal_block
- depart_doctest_block = depart_literal_block
- # placeholder for math (see docs/dev/todo.txt)
- def visit_math(self, node):
- self.document.reporter.warning('"math" role not supported',
- base_node=node)
- self.visit_literal(node)
- def depart_math(self, node):
- self.depart_literal(node)
- def visit_math_block(self, node):
- self.document.reporter.warning('"math" directive not supported',
- base_node=node)
- self.visit_literal_block(node)
- def depart_math_block(self, node):
- self.depart_literal_block(node)
- def visit_meta(self, node):
- name = node.attributes.get('name')
- content = node.attributes.get('content')
- if name is not None and content is not None:
- self.meta_dict[name] = content
- def depart_meta(self, node):
- pass
- def visit_option_list(self, node):
- table_name = 'tableoption'
- #
- # Generate automatic styles
- if not self.optiontablestyles_generated:
- self.optiontablestyles_generated = True
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(table_name),
- 'style:family': 'table'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-properties', attrib={
- 'style:width': '17.59cm',
- 'table:align': 'left',
- 'style:shadow': 'none'}, nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle('%s.%%c' % table_name, ( 'A', )),
- 'style:family': 'table-column'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-column-properties', attrib={
- 'style:column-width': '4.999cm'}, nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle('%s.%%c' % table_name, ( 'B', )),
- 'style:family': 'table-column'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-column-properties', attrib={
- 'style:column-width': '12.587cm'}, nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'A', 1, )),
- 'style:family': 'table-cell'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-cell-properties', attrib={
- 'fo:background-color': 'transparent',
- 'fo:padding': '0.097cm',
- 'fo:border-left': '0.035cm solid #000000',
- 'fo:border-right': 'none',
- 'fo:border-top': '0.035cm solid #000000',
- 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD)
- el2 = SubElement(el1, 'style:background-image', nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'B', 1, )),
- 'style:family': 'table-cell'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-cell-properties', attrib={
- 'fo:padding': '0.097cm',
- 'fo:border': '0.035cm solid #000000'}, nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'A', 2, )),
- 'style:family': 'table-cell'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-cell-properties', attrib={
- 'fo:padding': '0.097cm',
- 'fo:border-left': '0.035cm solid #000000',
- 'fo:border-right': 'none',
- 'fo:border-top': 'none',
- 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD)
- el = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'B', 2, )),
- 'style:family': 'table-cell'}, nsdict=SNSD)
- el1 = SubElement(el, 'style:table-cell-properties', attrib={
- 'fo:padding': '0.097cm',
- 'fo:border-left': '0.035cm solid #000000',
- 'fo:border-right': '0.035cm solid #000000',
- 'fo:border-top': 'none',
- 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD)
- #
- # Generate table data
- el = self.append_child('table:table', attrib={
- 'table:name': self.rststyle(table_name),
- 'table:style-name': self.rststyle(table_name),
- })
- el1 = SubElement(el, 'table:table-column', attrib={
- 'table:style-name': self.rststyle(
- '%s.%%c' % table_name, ( 'A', ))})
- el1 = SubElement(el, 'table:table-column', attrib={
- 'table:style-name': self.rststyle(
- '%s.%%c' % table_name, ( 'B', ))})
- el1 = SubElement(el, 'table:table-header-rows')
- el2 = SubElement(el1, 'table:table-row')
- el3 = SubElement(el2, 'table:table-cell', attrib={
- 'table:style-name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'A', 1, )),
- 'office:value-type': 'string'})
- el4 = SubElement(el3, 'text:p', attrib={
- 'text:style-name': 'Table_20_Heading'})
- el4.text= 'Option'
- el3 = SubElement(el2, 'table:table-cell', attrib={
- 'table:style-name': self.rststyle(
- '%s.%%c%%d' % table_name, ( 'B', 1, )),
- 'office:value-type': 'string'})
- el4 = SubElement(el3, 'text:p', attrib={
- 'text:style-name': 'Table_20_Heading'})
- el4.text= 'Description'
- self.set_current_element(el)
- def depart_option_list(self, node):
- self.set_to_parent()
- def visit_option_list_item(self, node):
- el = self.append_child('table:table-row')
- self.set_current_element(el)
- def depart_option_list_item(self, node):
- self.set_to_parent()
- def visit_option_group(self, node):
- el = self.append_child('table:table-cell', attrib={
- 'table:style-name': 'Table%d.A2' % self.table_count,
- 'office:value-type': 'string',
- })
- self.set_current_element(el)
- def depart_option_group(self, node):
- self.set_to_parent()
- def visit_option(self, node):
- el = self.append_child('text:p', attrib={
- 'text:style-name': 'Table_20_Contents'})
- el.text = node.astext()
- def depart_option(self, node):
- pass
- def visit_option_string(self, node):
- pass
- def depart_option_string(self, node):
- pass
- def visit_option_argument(self, node):
- pass
- def depart_option_argument(self, node):
- pass
- def visit_description(self, node):
- el = self.append_child('table:table-cell', attrib={
- 'table:style-name': 'Table%d.B2' % self.table_count,
- 'office:value-type': 'string',
- })
- el1 = SubElement(el, 'text:p', attrib={
- 'text:style-name': 'Table_20_Contents'})
- el1.text = node.astext()
- raise nodes.SkipChildren()
- def depart_description(self, node):
- pass
- def visit_paragraph(self, node):
- self.in_paragraph = True
- if self.in_header:
- el = self.append_p('header')
- elif self.in_footer:
- el = self.append_p('footer')
- else:
- style_name = self.paragraph_style_stack[-1]
- el = self.append_child('text:p',
- attrib={'text:style-name': style_name})
- self.append_pending_ids(el)
- self.set_current_element(el)
- def depart_paragraph(self, node):
- self.in_paragraph = False
- self.set_to_parent()
- if self.in_header:
- self.header_content.append(
- self.current_element.getchildren()[-1])
- self.current_element.remove(
- self.current_element.getchildren()[-1])
- elif self.in_footer:
- self.footer_content.append(
- self.current_element.getchildren()[-1])
- self.current_element.remove(
- self.current_element.getchildren()[-1])
- def visit_problematic(self, node):
- pass
- def depart_problematic(self, node):
- pass
- def visit_raw(self, node):
- if 'format' in node.attributes:
- formats = node.attributes['format']
- formatlist = formats.split()
- if 'odt' in formatlist:
- rawstr = node.astext()
- attrstr = ' '.join(['%s="%s"' % (k, v, )
- for k,v in list(CONTENT_NAMESPACE_ATTRIB.items())])
- contentstr = '<stuff %s>%s</stuff>' % (attrstr, rawstr, )
- if WhichElementTree != "lxml":
- contentstr = contentstr.encode("utf-8")
- content = etree.fromstring(contentstr)
- elements = content.getchildren()
- if len(elements) > 0:
- el1 = elements[0]
- if self.in_header:
- pass
- elif self.in_footer:
- pass
- else:
- self.current_element.append(el1)
- raise nodes.SkipChildren()
- def depart_raw(self, node):
- if self.in_header:
- pass
- elif self.in_footer:
- pass
- else:
- pass
- def visit_reference(self, node):
- text = node.astext()
- if self.settings.create_links:
- if 'refuri' in node:
- href = node['refuri']
- if ( self.settings.cloak_email_addresses
- and href.startswith('mailto:')):
- href = self.cloak_mailto(href)
- el = self.append_child('text:a', attrib={
- 'xlink:href': '%s' % href,
- 'xlink:type': 'simple',
- })
- self.set_current_element(el)
- elif 'refid' in node:
- if self.settings.create_links:
- href = node['refid']
- el = self.append_child('text:reference-ref', attrib={
- 'text:ref-name': '%s' % href,
- 'text:reference-format': 'text',
- })
- else:
- self.document.reporter.warning(
- 'References must have "refuri" or "refid" attribute.')
- if (self.in_table_of_contents and
- len(node.children) >= 1 and
- isinstance(node.children[0], docutils.nodes.generated)):
- node.remove(node.children[0])
- def depart_reference(self, node):
- if self.settings.create_links:
- if 'refuri' in node:
- self.set_to_parent()
- def visit_rubric(self, node):
- style_name = self.rststyle('rubric')
- classes = node.get('classes')
- if classes:
- class1 = classes[0]
- if class1:
- style_name = class1
- el = SubElement(self.current_element, 'text:h', attrib = {
- #'text:outline-level': '%d' % section_level,
- #'text:style-name': 'Heading_20_%d' % section_level,
- 'text:style-name': style_name,
- })
- text = node.astext()
- el.text = self.encode(text)
- def depart_rubric(self, node):
- pass
- def visit_section(self, node, move_ids=1):
- self.section_level += 1
- self.section_count += 1
- if self.settings.create_sections:
- el = self.append_child('text:section', attrib={
- 'text:name': 'Section%d' % self.section_count,
- 'text:style-name': 'Sect%d' % self.section_level,
- })
- self.set_current_element(el)
- def depart_section(self, node):
- self.section_level -= 1
- if self.settings.create_sections:
- self.set_to_parent()
- def visit_strong(self, node):
- el = SubElement(self.current_element, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- self.set_current_element(el)
- def depart_strong(self, node):
- self.set_to_parent()
- def visit_substitution_definition(self, node):
- raise nodes.SkipChildren()
- def depart_substitution_definition(self, node):
- pass
- def visit_system_message(self, node):
- pass
- def depart_system_message(self, node):
- pass
- def get_table_style(self, node):
- table_style = None
- table_name = None
- use_predefined_table_style = False
- str_classes = node.get('classes')
- if str_classes is not None:
- for str_class in str_classes:
- if str_class.startswith(TABLESTYLEPREFIX):
- table_name = str_class
- use_predefined_table_style = True
- break
- if table_name is not None:
- table_style = self.table_styles.get(table_name)
- if table_style is None:
- # If we can't find the table style, issue warning
- # and use the default table style.
- self.document.reporter.warning(
- 'Can\'t find table style "%s". Using default.' % (
- table_name, ))
- table_name = TABLENAMEDEFAULT
- table_style = self.table_styles.get(table_name)
- if table_style is None:
- # If we can't find the default table style, issue a warning
- # and use a built-in default style.
- self.document.reporter.warning(
- 'Can\'t find default table style "%s". Using built-in default.' % (
- table_name, ))
- table_style = BUILTIN_DEFAULT_TABLE_STYLE
- else:
- table_name = TABLENAMEDEFAULT
- table_style = self.table_styles.get(table_name)
- if table_style is None:
- # If we can't find the default table style, issue a warning
- # and use a built-in default style.
- self.document.reporter.warning(
- 'Can\'t find default table style "%s". Using built-in default.' % (
- table_name, ))
- table_style = BUILTIN_DEFAULT_TABLE_STYLE
- return table_style
- def visit_table(self, node):
- self.table_count += 1
- table_style = self.get_table_style(node)
- table_name = '%s%%d' % TABLESTYLEPREFIX
- el1 = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s' % table_name, ( self.table_count, )),
- 'style:family': 'table',
- }, nsdict=SNSD)
- if table_style.backgroundcolor is None:
- el1_1 = SubElement(el1, 'style:table-properties', attrib={
- #'style:width': '17.59cm',
- #'table:align': 'margins',
- 'table:align': 'left',
- 'fo:margin-top': '0in',
- 'fo:margin-bottom': '0.10in',
- }, nsdict=SNSD)
- else:
- el1_1 = SubElement(el1, 'style:table-properties', attrib={
- #'style:width': '17.59cm',
- 'table:align': 'margins',
- 'fo:margin-top': '0in',
- 'fo:margin-bottom': '0.10in',
- 'fo:background-color': table_style.backgroundcolor,
- }, nsdict=SNSD)
- # We use a single cell style for all cells in this table.
- # That's probably not correct, but seems to work.
- el2 = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': self.rststyle(
- '%s.%%c%%d' % table_name, ( self.table_count, 'A', 1, )),
- 'style:family': 'table-cell',
- }, nsdict=SNSD)
- thickness = self.settings.table_border_thickness
- if thickness is None:
- line_style1 = table_style.border
- else:
- line_style1 = '0.%03dcm solid #000000' % (thickness, )
- el2_1 = SubElement(el2, 'style:table-cell-properties', attrib={
- 'fo:padding': '0.049cm',
- 'fo:border-left': line_style1,
- 'fo:border-right': line_style1,
- 'fo:border-top': line_style1,
- 'fo:border-bottom': line_style1,
- }, nsdict=SNSD)
- title = None
- for child in node.children:
- if child.tagname == 'title':
- title = child.astext()
- break
- if title is not None:
- el3 = self.append_p('table-title', title)
- else:
- pass
- el4 = SubElement(self.current_element, 'table:table', attrib={
- 'table:name': self.rststyle(
- '%s' % table_name, ( self.table_count, )),
- 'table:style-name': self.rststyle(
- '%s' % table_name, ( self.table_count, )),
- })
- self.set_current_element(el4)
- self.current_table_style = el1
- self.table_width = 0.0
- def depart_table(self, node):
- attribkey = add_ns('style:width', nsdict=SNSD)
- attribval = '%.4fin' % (self.table_width, )
- el1 = self.current_table_style
- el2 = el1[0]
- el2.attrib[attribkey] = attribval
- self.set_to_parent()
- def visit_tgroup(self, node):
- self.column_count = ord('A') - 1
- def depart_tgroup(self, node):
- pass
- def visit_colspec(self, node):
- self.column_count += 1
- colspec_name = self.rststyle(
- '%s%%d.%%s' % TABLESTYLEPREFIX,
- (self.table_count, chr(self.column_count), )
- )
- colwidth = node['colwidth'] / 12.0
- el1 = SubElement(self.automatic_styles, 'style:style', attrib={
- 'style:name': colspec_name,
- 'style:family': 'table-column',
- }, nsdict=SNSD)
- el1_1 = SubElement(el1, 'style:table-column-properties', attrib={
- 'style:column-width': '%.4fin' % colwidth
- },
- nsdict=SNSD)
- el2 = self.append_child('table:table-column', attrib={
- 'table:style-name': colspec_name,
- })
- self.table_width += colwidth
- def depart_colspec(self, node):
- pass
- def visit_thead(self, node):
- el = self.append_child('table:table-header-rows')
- self.set_current_element(el)
- self.in_thead = True
- self.paragraph_style_stack.append('Table_20_Heading')
- def depart_thead(self, node):
- self.set_to_parent()
- self.in_thead = False
- self.paragraph_style_stack.pop()
- def visit_row(self, node):
- self.column_count = ord('A') - 1
- el = self.append_child('table:table-row')
- self.set_current_element(el)
- def depart_row(self, node):
- self.set_to_parent()
- def visit_entry(self, node):
- self.column_count += 1
- cellspec_name = self.rststyle(
- '%s%%d.%%c%%d' % TABLESTYLEPREFIX,
- (self.table_count, 'A', 1, )
- )
- attrib={
- 'table:style-name': cellspec_name,
- 'office:value-type': 'string',
- }
- morecols = node.get('morecols', 0)
- if morecols > 0:
- attrib['table:number-columns-spanned'] = '%d' % (morecols + 1,)
- self.column_count += morecols
- morerows = node.get('morerows', 0)
- if morerows > 0:
- attrib['table:number-rows-spanned'] = '%d' % (morerows + 1,)
- el1 = self.append_child('table:table-cell', attrib=attrib)
- self.set_current_element(el1)
- def depart_entry(self, node):
- self.set_to_parent()
- def visit_tbody(self, node):
- pass
- def depart_tbody(self, node):
- pass
- def visit_target(self, node):
- #
- # I don't know how to implement targets in ODF.
- # How do we create a target in oowriter? A cross-reference?
- if not ('refuri' in node or 'refid' in node
- or 'refname' in node):
- pass
- else:
- pass
- def depart_target(self, node):
- pass
- def visit_title(self, node, move_ids=1, title_type='title'):
- if isinstance(node.parent, docutils.nodes.section):
- section_level = self.section_level
- if section_level > 7:
- self.document.reporter.warning(
- 'Heading/section levels greater than 7 not supported.')
- self.document.reporter.warning(
- ' Reducing to heading level 7 for heading: "%s"' % (
- node.astext(), ))
- section_level = 7
- el1 = self.append_child('text:h', attrib = {
- 'text:outline-level': '%d' % section_level,
- #'text:style-name': 'Heading_20_%d' % section_level,
- 'text:style-name': self.rststyle(
- 'heading%d', (section_level, )),
- })
- self.append_pending_ids(el1)
- self.set_current_element(el1)
- elif isinstance(node.parent, docutils.nodes.document):
- # text = self.settings.title
- #else:
- # text = node.astext()
- el1 = SubElement(self.current_element, 'text:p', attrib = {
- 'text:style-name': self.rststyle(title_type),
- })
- self.append_pending_ids(el1)
- text = node.astext()
- self.title = text
- self.found_doc_title = True
- self.set_current_element(el1)
- def depart_title(self, node):
- if (isinstance(node.parent, docutils.nodes.section) or
- isinstance(node.parent, docutils.nodes.document)):
- self.set_to_parent()
- def visit_subtitle(self, node, move_ids=1):
- self.visit_title(node, move_ids, title_type='subtitle')
- def depart_subtitle(self, node):
- self.depart_title(node)
- def visit_title_reference(self, node):
- el = self.append_child('text:span', attrib={
- 'text:style-name': self.rststyle('quotation')})
- el.text = self.encode(node.astext())
- raise nodes.SkipChildren()
- def depart_title_reference(self, node):
- pass
- def generate_table_of_content_entry_template(self, el1):
- for idx in range(1, 11):
- el2 = SubElement(el1,
- 'text:table-of-content-entry-template',
- attrib={
- 'text:outline-level': "%d" % (idx, ),
- 'text:style-name': self.rststyle('contents-%d' % (idx, )),
- })
- el3 = SubElement(el2, 'text:index-entry-chapter')
- el3 = SubElement(el2, 'text:index-entry-text')
- el3 = SubElement(el2, 'text:index-entry-tab-stop', attrib={
- 'style:leader-char': ".",
- 'style:type': "right",
- })
- el3 = SubElement(el2, 'text:index-entry-page-number')
- def find_title_label(self, node, class_type, label_key):
- label = ''
- title_node = None
- for child in node.children:
- if isinstance(child, class_type):
- title_node = child
- break
- if title_node is not None:
- label = title_node.astext()
- else:
- label = self.language.labels[label_key]
- return label
- def visit_topic(self, node):
- if 'classes' in node.attributes:
- if 'contents' in node.attributes['classes']:
- label = self.find_title_label(node, docutils.nodes.title,
- 'contents')
- if self.settings.generate_oowriter_toc:
- el1 = self.append_child('text:table-of-content', attrib={
- 'text:name': 'Table of Contents1',
- 'text:protected': 'true',
- 'text:style-name': 'Sect1',
- })
- el2 = SubElement(el1,
- 'text:table-of-content-source',
- attrib={
- 'text:outline-level': '10',
- })
- el3 =SubElement(el2, 'text:index-title-template', attrib={
- 'text:style-name': 'Contents_20_Heading',
- })
- el3.text = label
- self.generate_table_of_content_entry_template(el2)
- el4 = SubElement(el1, 'text:index-body')
- el5 = SubElement(el4, 'text:index-title')
- el6 = SubElement(el5, 'text:p', attrib={
- 'text:style-name': self.rststyle('contents-heading'),
- })
- el6.text = label
- self.save_current_element = self.current_element
- self.table_of_content_index_body = el4
- self.set_current_element(el4)
- else:
- el = self.append_p('horizontalline')
- el = self.append_p('centeredtextbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- el1.text = label
- self.in_table_of_contents = True
- elif 'abstract' in node.attributes['classes']:
- el = self.append_p('horizontalline')
- el = self.append_p('centeredtextbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- label = self.find_title_label(node, docutils.nodes.title,
- 'abstract')
- el1.text = label
- elif 'dedication' in node.attributes['classes']:
- el = self.append_p('horizontalline')
- el = self.append_p('centeredtextbody')
- el1 = SubElement(el, 'text:span',
- attrib={'text:style-name': self.rststyle('strong')})
- label = self.find_title_label(node, docutils.nodes.title,
- 'dedication')
- el1.text = label
- def depart_topic(self, node):
- if 'classes' in node.attributes:
- if 'contents' in node.attributes['classes']:
- if self.settings.generate_oowriter_toc:
- self.update_toc_page_numbers(
- self.table_of_content_index_body)
- self.set_current_element(self.save_current_element)
- else:
- el = self.append_p('horizontalline')
- self.in_table_of_contents = False
- def update_toc_page_numbers(self, el):
- collection = []
- self.update_toc_collect(el, 0, collection)
- self.update_toc_add_numbers(collection)
- def update_toc_collect(self, el, level, collection):
- collection.append((level, el))
- level += 1
- for child_el in el.getchildren():
- if child_el.tag != 'text:index-body':
- self.update_toc_collect(child_el, level, collection)
- def update_toc_add_numbers(self, collection):
- for level, el1 in collection:
- if (el1.tag == 'text:p' and
- el1.text != 'Table of Contents'):
- el2 = SubElement(el1, 'text:tab')
- el2.tail = '9999'
- def visit_transition(self, node):
- el = self.append_p('horizontalline')
- def depart_transition(self, node):
- pass
- #
- # Admonitions
- #
- def visit_warning(self, node):
- self.generate_admonition(node, 'warning')
- def depart_warning(self, node):
- self.paragraph_style_stack.pop()
- def visit_attention(self, node):
- self.generate_admonition(node, 'attention')
- depart_attention = depart_warning
- def visit_caution(self, node):
- self.generate_admonition(node, 'caution')
- depart_caution = depart_warning
- def visit_danger(self, node):
- self.generate_admonition(node, 'danger')
- depart_danger = depart_warning
- def visit_error(self, node):
- self.generate_admonition(node, 'error')
- depart_error = depart_warning
- def visit_hint(self, node):
- self.generate_admonition(node, 'hint')
- depart_hint = depart_warning
- def visit_important(self, node):
- self.generate_admonition(node, 'important')
- depart_important = depart_warning
- def visit_note(self, node):
- self.generate_admonition(node, 'note')
- depart_note = depart_warning
- def visit_tip(self, node):
- self.generate_admonition(node, 'tip')
- depart_tip = depart_warning
- def visit_admonition(self, node):
- title = None
- for child in node.children:
- if child.tagname == 'title':
- title = child.astext()
- if title is None:
- classes1 = node.get('classes')
- if classes1:
- title = classes1[0]
- self.generate_admonition(node, 'generic', title)
- depart_admonition = depart_warning
- def generate_admonition(self, node, label, title=None):
- el1 = SubElement(self.current_element, 'text:p', attrib = {
- 'text:style-name': self.rststyle('admon-%s-hdr', ( label, )),
- })
- if title:
- el1.text = title
- else:
- el1.text = '%s!' % (label.capitalize(), )
- s1 = self.rststyle('admon-%s-body', ( label, ))
- self.paragraph_style_stack.append(s1)
- #
- # Roles (e.g. subscript, superscript, strong, ...
- #
- def visit_subscript(self, node):
- el = self.append_child('text:span', attrib={
- 'text:style-name': 'rststyle-subscript',
- })
- self.set_current_element(el)
- def depart_subscript(self, node):
- self.set_to_parent()
- def visit_superscript(self, node):
- el = self.append_child('text:span', attrib={
- 'text:style-name': 'rststyle-superscript',
- })
- self.set_current_element(el)
- def depart_superscript(self, node):
- self.set_to_parent()
- # Use an own reader to modify transformations done.
- class Reader(standalone.Reader):
- def get_transforms(self):
- default = standalone.Reader.get_transforms(self)
- if self.settings.create_links:
- return default
- return [ i
- for i in default
- if i is not references.DanglingReferences ]