[pod+gen] Added POD rendering based on ODS templates. Integrated with gen.

This commit is contained in:
Gaetan Delannay 2013-02-05 08:51:25 +01:00
parent d5d99b67eb
commit 43261fde60
8 changed files with 144 additions and 92 deletions

View file

@ -272,6 +272,12 @@ class ZopeInstaller:
appyType.template) appyType.template)
if os.path.exists(fileName): if os.path.exists(fileName):
setattr(appyTool, attrName, fileName) setattr(appyTool, attrName, fileName)
# If the template is ods, set the default format to ods
# (because default is odt)
if fileName.endswith('.ods'):
formats = appyTool.getAttributeName('formats',
appyClass, appyType.name)
setattr(appyTool, formats, ['ods'])
appyTool.log('Imported "%s" in the tool in ' \ appyTool.log('Imported "%s" in the tool in ' \
'attribute "%s"'% (fileName, attrName)) 'attribute "%s"'% (fileName, attrName))
else: else:

View file

@ -94,6 +94,8 @@ appyLabels = [
('pdf', 'PDF'), ('pdf', 'PDF'),
('doc', 'DOC'), ('doc', 'DOC'),
('rtf', 'RTF'), ('rtf', 'RTF'),
('ods', 'ODS'),
('xls', 'XLS'),
('front_page_text', 'Welcome to this Appy-powered site.'), ('front_page_text', 'Welcome to this Appy-powered site.'),
('captcha_text', 'Please type "${text}" (without the double quotes) in the ' \ ('captcha_text', 'Please type "${text}" (without the double quotes) in the ' \
'field besides, but without the character at position ' \ 'field besides, but without the character at position ' \

BIN
gen/ui/ods.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

BIN
gen/ui/xls.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

View file

@ -54,7 +54,7 @@ class ToolWrapper(AbstractWrapper):
(user.o.absolute_url(), user.title,access)) (user.o.absolute_url(), user.title,access))
return res + '\n'.join(rows) + '</table>' return res + '\n'.join(rows) + '</table>'
podOutputFormats = ('odt', 'pdf', 'doc', 'rtf') podOutputFormats = ('odt', 'pdf', 'doc', 'rtf', 'ods', 'xls')
def getPodOutputFormats(self): def getPodOutputFormats(self):
'''Gets the available output formats for POD documents.''' '''Gets the available output formats for POD documents.'''
return [(of, self.translate(of)) for of in self.podOutputFormats] return [(of, self.translate(of)) for of in self.podOutputFormats]
@ -185,4 +185,36 @@ class ToolWrapper(AbstractWrapper):
except Exception, e: except Exception, e:
failed.append(startObject) failed.append(startObject)
return nb, failed return nb, failed
def validate(self, new, errors):
'''Validates that uploaded POD templates and output types are
compatible.'''
page = self.request.get('page', 'main')
if page == 'documents':
# Check that uploaded templates and output formats are compatible.
for fieldName in dir(new):
# Ignore fields which are not POD templates.
if not fieldName.startswith('podTemplate'): continue
# Get the file name, either from the newly uploaded file or
# from the existing file stored in the database.
if getattr(new, fieldName):
fileName = getattr(new, fieldName).filename
else:
fileName = getattr(self, fieldName).name
# Get the extension of the uploaded file.
ext = os.path.splitext(fileName)[1][1:]
# Get the chosen output formats for this template.
formatsFieldName = 'formatsFor%s' % fieldName[14:]
formats = getattr(new, formatsFieldName)
error = False
if ext == 'odt':
error = ('ods' in formats) or ('xls' in formats)
elif ext == 'ods':
error = ('odt' in formats) or ('pdf' in formats) or \
('doc' in formats) or ('rtf' in formats)
if error:
msg = 'This (these) format(s) cannot be used with ' \
'this template.'
setattr(errors, formatsFieldName, msg)
return self._callCustom('validate', new, errors)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -51,15 +51,15 @@ DOC_NOT_FOUND = 'Document "%s" was not found.'
URL_NOT_FOUND = 'Doc URL "%s" is wrong. %s' URL_NOT_FOUND = 'Doc URL "%s" is wrong. %s'
BAD_RESULT_TYPE = 'Bad result type "%s". Available types are %s.' BAD_RESULT_TYPE = 'Bad result type "%s". Available types are %s.'
CANNOT_WRITE_RESULT = 'I cannot write result "%s". %s' CANNOT_WRITE_RESULT = 'I cannot write result "%s". %s'
CONNECT_ERROR = 'Could not connect to OpenOffice on port %d. UNO ' \ CONNECT_ERROR = 'Could not connect to LibreOffice on port %d. UNO ' \
'(OpenOffice API) says: %s.' '(LibreOffice API) says: %s.'
# Some constants --------------------------------------------------------------- # Some constants ---------------------------------------------------------------
DEFAULT_PORT = 2002 DEFAULT_PORT = 2002
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Converter: class Converter:
'''Converts a document readable by OpenOffice into pdf, doc, txt, rtf...''' '''Converts a document readable by LibreOffice into pdf, doc, txt, rtf...'''
exeVariants = ('soffice.exe', 'soffice') exeVariants = ('soffice.exe', 'soffice')
pathReplacements = {'program files': 'progra~1', pathReplacements = {'program files': 'progra~1',
'openoffice.org 1': 'openof~1', 'openoffice.org 1': 'openof~1',
@ -72,9 +72,9 @@ class Converter:
self.resultType = resultType self.resultType = resultType
self.resultFilter = self.getResultFilter() self.resultFilter = self.getResultFilter()
self.resultUrl = self.getResultUrl() self.resultUrl = self.getResultUrl()
self.ooContext = None self.loContext = None
self.oo = None # The OpenOffice application object self.oo = None # The LibreOffice application object
self.doc = None # The OpenOffice loaded document self.doc = None # The LibreOffice loaded document
def getInputUrls(self, docPath): def getInputUrls(self, docPath):
'''Returns the absolute path of the input file. In fact, it returns a '''Returns the absolute path of the input file. In fact, it returns a
@ -100,7 +100,7 @@ class Converter:
return res return res
def getResultUrl(self): def getResultUrl(self):
'''Returns the path of the result file in the format needed by OO. If '''Returns the path of the result file in the format needed by LO. If
the result type and the input type are the same (ie the user wants to the result type and the input type are the same (ie the user wants to
refresh indexes or some other action and not perform a real refresh indexes or some other action and not perform a real
conversion), the result file is named conversion), the result file is named
@ -126,7 +126,7 @@ class Converter:
raise ConverterError(CANNOT_WRITE_RESULT % (res, ioe)) raise ConverterError(CANNOT_WRITE_RESULT % (res, ioe))
def connect(self): def connect(self):
'''Connects to OpenOffice''' '''Connects to LibreOffice'''
if os.name == 'nt': if os.name == 'nt':
import socket import socket
import uno import uno
@ -138,17 +138,17 @@ class Converter:
resolver = localContext.ServiceManager.createInstanceWithContext( resolver = localContext.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", localContext) "com.sun.star.bridge.UnoUrlResolver", localContext)
# Connect to the running office # Connect to the running office
self.ooContext = resolver.resolve( self.loContext = resolver.resolve(
'uno:socket,host=localhost,port=%d;urp;StarOffice.' \ 'uno:socket,host=localhost,port=%d;urp;StarOffice.' \
'ComponentContext' % self.port) 'ComponentContext' % self.port)
# Is seems that we can't define a timeout for this method. # Is seems that we can't define a timeout for this method.
# I need it because, for example, when a web server already listens # I need it because, for example, when a web server already listens
# to the given port (thus, not a OpenOffice instance), this method # to the given port (thus, not a LibreOffice instance), this method
# blocks. # blocks.
smgr = self.ooContext.ServiceManager smgr = self.loContext.ServiceManager
# Get the central desktop object # Get the central desktop object
self.oo = smgr.createInstanceWithContext( self.oo = smgr.createInstanceWithContext(
'com.sun.star.frame.Desktop', self.ooContext) 'com.sun.star.frame.Desktop', self.loContext)
except NoConnectException, nce: except NoConnectException, nce:
raise ConverterError(CONNECT_ERROR % (self.port, nce)) raise ConverterError(CONNECT_ERROR % (self.port, nce))
@ -220,7 +220,7 @@ class Converter:
raise ConverterError(URL_NOT_FOUND % (self.docPath, iae)) raise ConverterError(URL_NOT_FOUND % (self.docPath, iae))
def convertDocument(self): def convertDocument(self):
'''Calls OO to perform a document conversion. Note that the conversion '''Calls LO to perform a document conversion. Note that the conversion
is not really done if the source and target documents have the same is not really done if the source and target documents have the same
type.''' type.'''
properties = [] properties = []
@ -238,7 +238,7 @@ class Converter:
self.doc.storeToURL(self.resultUrl, tuple(properties)) self.doc.storeToURL(self.resultUrl, tuple(properties))
def run(self): def run(self):
'''Connects to OO, does the job and disconnects.''' '''Connects to LO, does the job and disconnects.'''
self.connect() self.connect()
self.loadDocument() self.loadDocument()
self.convertDocument() self.convertDocument()
@ -257,12 +257,12 @@ class ConverterScript:
' and outputType is the output format, that must be one of\n' \ ' and outputType is the output format, that must be one of\n' \
' %s.\n' \ ' %s.\n' \
' "python" should be a UNO-enabled Python interpreter (ie the ' \ ' "python" should be a UNO-enabled Python interpreter (ie the ' \
' one which is included in the OpenOffice.org distribution).' % \ ' one which is included in the LibreOffice distribution).' % \
str(FILE_TYPES.keys()) str(FILE_TYPES.keys())
def run(self): def run(self):
optParser = OptionParser(usage=ConverterScript.usage) optParser = OptionParser(usage=ConverterScript.usage)
optParser.add_option("-p", "--port", dest="port", optParser.add_option("-p", "--port", dest="port",
help="The port on which OpenOffice runs " \ help="The port on which LibreOffice runs " \
"Default is %d." % DEFAULT_PORT, "Default is %d." % DEFAULT_PORT,
default=DEFAULT_PORT, metavar="PORT", type='int') default=DEFAULT_PORT, metavar="PORT", type='int')
(options, args) = optParser.parse_args() (options, args) = optParser.parse_args()

View file

@ -23,7 +23,7 @@ from UserDict import UserDict
import appy.pod, time, cgi import appy.pod, time, cgi
from appy.pod import PodError from appy.pod import PodError
from appy.shared import mimeTypesExts from appy.shared import mimeTypes, mimeTypesExts
from appy.shared.xml_parser import XmlElement from appy.shared.xml_parser import XmlElement
from appy.shared.utils import FolderDeleter, executeCommand from appy.shared.utils import FolderDeleter, executeCommand
from appy.shared.utils import FileWrapper from appy.shared.utils import FileWrapper
@ -40,10 +40,10 @@ RESULT_FILE_EXISTS = 'Result file "%s" exists.'
CANT_WRITE_RESULT = 'I cannot write result file "%s". %s' CANT_WRITE_RESULT = 'I cannot write result file "%s". %s'
CANT_WRITE_TEMP_FOLDER = 'I cannot create temp folder "%s". %s' CANT_WRITE_TEMP_FOLDER = 'I cannot create temp folder "%s". %s'
NO_PY_PATH = 'Extension of result file is "%s". In order to perform ' \ NO_PY_PATH = 'Extension of result file is "%s". In order to perform ' \
'conversion from ODT to this format we need to call OpenOffice. ' \ 'conversion from ODT to this format we need to call LibreOffice. ' \
'But the Python interpreter which runs the current script does ' \ 'But the Python interpreter which runs the current script does ' \
'not know UNO, the library that allows to connect to ' \ 'not know UNO, the library that allows to connect to ' \
'OpenOffice in server mode. If you can\'t install UNO in this ' \ 'LibreOffice in server mode. If you can\'t install UNO in this ' \
'Python interpreter, you can specify, in parameter ' \ 'Python interpreter, you can specify, in parameter ' \
'"pythonWithUnoPath", the path to a UNO-enabled Python ' \ '"pythonWithUnoPath", the path to a UNO-enabled Python ' \
'interpreter. One such interpreter may be found in ' \ 'interpreter. One such interpreter may be found in ' \
@ -57,12 +57,11 @@ BLANKS_IN_PATH = 'Blanks were found in path "%s". Please use the DOS-names ' \
BAD_RESULT_TYPE = 'Result "%s" has a wrong extension. Allowed extensions ' \ BAD_RESULT_TYPE = 'Result "%s" has a wrong extension. Allowed extensions ' \
'are: "%s".' 'are: "%s".'
CONVERT_ERROR = 'An error occurred during the conversion. %s' CONVERT_ERROR = 'An error occurred during the conversion. %s'
BAD_OO_PORT = 'Bad OpenOffice port "%s". Make sure it is an integer.' BAD_OO_PORT = 'Bad LibreOffice port "%s". Make sure it is an integer.'
XHTML_ERROR = 'An error occurred while rendering XHTML content.' XHTML_ERROR = 'An error occurred while rendering XHTML content.'
WARNING_INCOMPLETE_ODT = 'Warning: your ODT file may not be complete (ie ' \ WARNING_INCOMPLETE_OD = 'Warning: your OpenDocument file may not be complete ' \
'imported documents may not be present). This is ' \ '(ie imported documents may not be present). This is because we could not ' \
'because we could not connect to OpenOffice in ' \ 'connect to LibreOffice in server mode: %s'
'server mode: %s'
DOC_NOT_SPECIFIED = 'Please specify a document to import, either with a ' \ DOC_NOT_SPECIFIED = 'Please specify a document to import, either with a ' \
'stream (parameter "content") or with a path (parameter ' \ 'stream (parameter "content") or with a path (parameter ' \
'"at")' '"at")'
@ -92,6 +91,8 @@ STYLES_POD_FONTS = '<@style@:font-face @style@:name="PodStarSymbol" ' \
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Renderer: class Renderer:
templateTypes = ('odt', 'ods') # Types of POD templates
def __init__(self, template, context, result, pythonWithUnoPath=None, def __init__(self, template, context, result, pythonWithUnoPath=None,
ooPort=2002, stylesMapping={}, forceOoCall=False, ooPort=2002, stylesMapping={}, forceOoCall=False,
finalizeFunction=None, overwriteExisting=False, finalizeFunction=None, overwriteExisting=False,
@ -416,20 +417,9 @@ class Renderer:
FolderDeleter.delete(self.tempFolder) FolderDeleter.delete(self.tempFolder)
raise po raise po
def reportProblem(self, msg, resultType): def callLibreOffice(self, resultName, resultType):
'''When trying to call OO in server mode for producing ODT '''Call LibreOffice in server mode to convert or update the result.'''
(=forceOoCall=True), if an error occurs we still have an ODT to loOutput = ''
return to the user. So we produce a warning instead of raising an
error.'''
if (resultType == 'odt') and self.forceOoCall:
print WARNING_INCOMPLETE_ODT % msg
else:
raise msg
def callOpenOffice(self, resultOdtName, resultType):
'''Call Open Office in server mode to convert or update the ODT
result.'''
ooOutput = ''
try: try:
if (not isinstance(self.ooPort, int)) and \ if (not isinstance(self.ooPort, int)) and \
(not isinstance(self.ooPort, long)): (not isinstance(self.ooPort, long)):
@ -437,7 +427,7 @@ class Renderer:
try: try:
from appy.pod.converter import Converter, ConverterError from appy.pod.converter import Converter, ConverterError
try: try:
Converter(resultOdtName, resultType, self.ooPort).run() Converter(resultName, resultType, self.ooPort).run()
except ConverterError, ce: except ConverterError, ce:
raise PodError(CONVERT_ERROR % str(ce)) raise PodError(CONVERT_ERROR % str(ce))
except ImportError: except ImportError:
@ -449,35 +439,54 @@ class Renderer:
raise PodError(BLANKS_IN_PATH % self.pyPath) raise PodError(BLANKS_IN_PATH % self.pyPath)
if not os.path.isfile(self.pyPath): if not os.path.isfile(self.pyPath):
raise PodError(PY_PATH_NOT_FILE % self.pyPath) raise PodError(PY_PATH_NOT_FILE % self.pyPath)
if resultOdtName.find(' ') != -1: if resultName.find(' ') != -1:
qResultOdtName = '"%s"' % resultOdtName qResultName = '"%s"' % resultName
else: else:
qResultOdtName = resultOdtName qResultName = resultName
convScript = '%s/converter.py' % \ convScript = '%s/converter.py' % \
os.path.dirname(appy.pod.__file__) os.path.dirname(appy.pod.__file__)
if convScript.find(' ') != -1: if convScript.find(' ') != -1:
convScript = '"%s"' % convScript convScript = '"%s"' % convScript
cmd = '%s %s %s %s -p%d' % \ cmd = '%s %s %s %s -p%d' % \
(self.pyPath, convScript, qResultOdtName, resultType, (self.pyPath, convScript, qResultName, resultType,
self.ooPort) self.ooPort)
ooOutput = executeCommand(cmd) loOutput = executeCommand(cmd)
except PodError, pe: except PodError, pe:
# When trying to call OO in server mode for producing # When trying to call LO in server mode for producing ODT or ODS
# ODT (=forceOoCall=True), if an error occurs we still # (=forceOoCall=True), if an error occurs we have nevertheless
# have an ODT to return to the user. So we produce a # an ODT or ODS to return to the user. So we produce a warning
# warning instead of raising an error. # instead of raising an error.
if (resultType == 'odt') and self.forceOoCall: if (resultType in self.templateTypes) and self.forceOoCall:
print WARNING_INCOMPLETE_ODT % str(pe) print WARNING_INCOMPLETE_OD % str(pe)
else: else:
raise pe raise pe
return ooOutput return loOutput
def getTemplateType(self):
'''Identifies the type of the pod template in self.template
(ods or odt). If self.template is a string, it is a file name and we
simply get its extension. Else, it is a binary file in a StringIO
instance, and we seek the mime type from the first bytes.'''
if isinstance(self.template, basestring):
res = os.path.splitext(self.template)[1][1:]
else:
# A StringIO instance
self.template.seek(0)
firstBytes = self.template.read(90)
firstBytes = firstBytes[firstBytes.index('mimetype')+8:]
if firstBytes.startswith(mimeTypes['ods']):
res = 'ods'
else:
# We suppose this is ODT
res = 'odt'
return res
def finalize(self): def finalize(self):
'''Re-zip the result and potentially call OpenOffice if target format is '''Re-zip the result and potentially call LibreOffice if target format
not ODT or if forceOoCall is True.''' is not among self.templateTypes or if forceOoCall is True.'''
for odtFile in ('content.xml', 'styles.xml'): for innerFile in ('content.xml', 'styles.xml'):
shutil.copy(os.path.join(self.tempFolder, odtFile), shutil.copy(os.path.join(self.tempFolder, innerFile),
os.path.join(self.unzipFolder, odtFile)) os.path.join(self.unzipFolder, innerFile))
# Insert dynamic styles # Insert dynamic styles
contentXml = os.path.join(self.unzipFolder, 'content.xml') contentXml = os.path.join(self.unzipFolder, 'content.xml')
f = file(contentXml) f = file(contentXml)
@ -493,27 +502,28 @@ class Renderer:
self.finalizeFunction(self.unzipFolder) self.finalizeFunction(self.unzipFolder)
except Exception, e: except Exception, e:
print WARNING_FINALIZE_ERROR % str(e) print WARNING_FINALIZE_ERROR % str(e)
# Re-zip the result. # Re-zip the result, first as an OpenDocument file of the same type as
resExt = os.path.splitext(self.template)[1] # the POD template (odt, ods...)
resultOdtName = os.path.join(self.tempFolder, 'result%s' % resExt) resultExt = self.getTemplateType()
resultName = os.path.join(self.tempFolder, 'result.%s' % resultExt)
try: try:
resultOdt = zipfile.ZipFile(resultOdtName,'w', zipfile.ZIP_DEFLATED) resultZip = zipfile.ZipFile(resultName, 'w', zipfile.ZIP_DEFLATED)
except RuntimeError: except RuntimeError:
resultOdt = zipfile.ZipFile(resultOdtName,'w') resultZip = zipfile.ZipFile(resultName,'w')
# Insert first the file "mimetype" (uncompressed), in order to be # Insert first the file "mimetype" (uncompressed), in order to be
# compliant with the OpenDocument Format specification, section 17.4, # compliant with the OpenDocument Format specification, section 17.4,
# that expresses this restriction. Else, libraries like "magic", under # that expresses this restriction. Else, libraries like "magic", under
# Linux/Unix, are unable to detect the correct mimetype for a pod result # Linux/Unix, are unable to detect the correct mimetype for a pod result
# (it simply recognizes it as a "application/zip" and not a # (it simply recognizes it as a "application/zip" and not a
# "application/vnd.oasis.opendocument.text)". # "application/vnd.oasis.opendocument.text)".
resultOdt.write(os.path.join(self.unzipFolder, 'mimetype'), resultZip.write(os.path.join(self.unzipFolder, 'mimetype'),
'mimetype', zipfile.ZIP_STORED) 'mimetype', zipfile.ZIP_STORED)
for dir, dirnames, filenames in os.walk(self.unzipFolder): for dir, dirnames, filenames in os.walk(self.unzipFolder):
for f in filenames: for f in filenames:
folderName = dir[len(self.unzipFolder)+1:] folderName = dir[len(self.unzipFolder)+1:]
# Ignore file "mimetype" that was already inserted. # Ignore file "mimetype" that was already inserted.
if (folderName == '') and (f == 'mimetype'): continue if (folderName == '') and (f == 'mimetype'): continue
resultOdt.write(os.path.join(dir, f), resultZip.write(os.path.join(dir, f),
os.path.join(folderName, f)) os.path.join(folderName, f))
if not dirnames and not filenames: if not dirnames and not filenames:
# This is an empty leaf folder. We must create an entry in the # This is an empty leaf folder. We must create an entry in the
@ -521,35 +531,34 @@ class Renderer:
folderName = dir[len(self.unzipFolder):] folderName = dir[len(self.unzipFolder):]
zInfo = zipfile.ZipInfo("%s/" % folderName,time.localtime()[:6]) zInfo = zipfile.ZipInfo("%s/" % folderName,time.localtime()[:6])
zInfo.external_attr = 48 zInfo.external_attr = 48
resultOdt.writestr(zInfo, '') resultZip.writestr(zInfo, '')
resultOdt.close() resultZip.close()
resultType = os.path.splitext(self.result)[1] resultType = os.path.splitext(self.result)[1].strip('.')
try: try:
if (resultType == '.odt') and not self.forceOoCall: if (resultType in self.templateTypes) and not self.forceOoCall:
# Simply move the ODT result to the result # Simply move the ODT result to the result
os.rename(resultOdtName, self.result) os.rename(resultName, self.result)
else: else:
if resultType.startswith('.'): resultType = resultType[1:] if resultType not in FILE_TYPES:
if not resultType in FILE_TYPES.keys():
raise PodError(BAD_RESULT_TYPE % ( raise PodError(BAD_RESULT_TYPE % (
self.result, FILE_TYPES.keys())) self.result, FILE_TYPES.keys()))
# Call OpenOffice to perform the conversion or document update # Call LibreOffice to perform the conversion or document update.
output = self.callOpenOffice(resultOdtName, resultType) output = self.callLibreOffice(resultName, resultType)
# I (should) have the result. Move it to the correct name # I (should) have the result. Move it to the correct name.
resPrefix = os.path.splitext(resultOdtName)[0] + '.' resPrefix = os.path.splitext(resultName)[0]
if resultType == 'odt': if resultType in self.templateTypes:
# converter.py has (normally!) created a second file # converter.py has (normally!) created a second file
# suffixed .res.odt # suffixed .res.[resultType]
resultName = resPrefix + 'res.odt' finalResultName = '%s.res.%s' % (resPrefix, resultType)
if not os.path.exists(resultName): if not os.path.exists(finalResultName):
resultName = resultOdtName finalResultName = resultName
# In this case OO in server mode could not be called to # In this case OO in server mode could not be called to
# update indexes, sections, etc. # update indexes, sections, etc.
else: else:
resultName = resPrefix + resultType finalResultName = '%s.%s' % (resPrefix, resultType)
if not os.path.exists(resultName): if not os.path.exists(finalResultName):
raise PodError(CONVERT_ERROR % output) raise PodError(CONVERT_ERROR % output)
os.rename(resultName, self.result) os.rename(finalResultName, self.result)
finally: finally:
FolderDeleter.delete(self.tempFolder) FolderDeleter.delete(self.tempFolder)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -4,13 +4,16 @@ import os.path
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
appyPath = os.path.realpath(os.path.dirname(appy.__file__)) appyPath = os.path.realpath(os.path.dirname(appy.__file__))
mimeTypes = {'odt': 'application/vnd.oasis.opendocument.text', od = 'application/vnd.oasis.opendocument'
mimeTypes = {'odt': '%s.text' % od,
'ods': '%s.spreadsheet' % od,
'doc': 'application/msword', 'doc': 'application/msword',
'rtf': 'text/rtf', 'rtf': 'text/rtf',
'pdf': 'application/pdf' 'pdf': 'application/pdf'
} }
mimeTypesExts = { mimeTypesExts = {
'application/vnd.oasis.opendocument.text': 'odt', '%s.text' % od: 'odt',
'%s.spreadsheet' % od: 'ods',
'application/msword': 'doc', 'application/msword': 'doc',
'text/rtf': 'rtf', 'text/rtf': 'rtf',
'application/pdf': 'pdf', 'application/pdf': 'pdf',