recover v1.x theme file names from XML info

bzr-revno: 1846
This commit is contained in:
Meinert Jordan 2011-12-20 20:23:36 +00:00 committed by Tim Bentley
commit d94816d481
4 changed files with 86 additions and 83 deletions

View File

@ -41,7 +41,7 @@ class Ui_FileRenameDialog(object):
self.dialogLayout.addWidget(self.fileNameLabel, 0, 0) self.dialogLayout.addWidget(self.fileNameLabel, 0, 0)
self.fileNameEdit = QtGui.QLineEdit(fileRenameDialog) self.fileNameEdit = QtGui.QLineEdit(fileRenameDialog)
self.fileNameEdit.setValidator(QtGui.QRegExpValidator( self.fileNameEdit.setValidator(QtGui.QRegExpValidator(
QtCore.QRegExp(r'[^/\\?*|<>\[\]":<>+%]+'), self)) QtCore.QRegExp(r'[^/\\?*|<>\[\]":+%]+'), self))
self.fileNameEdit.setObjectName(u'fileNameEdit') self.fileNameEdit.setObjectName(u'fileNameEdit')
self.dialogLayout.addWidget(self.fileNameEdit, 0, 1) self.dialogLayout.addWidget(self.fileNameEdit, 0, 1)
self.buttonBox = create_accept_reject_button_box(fileRenameDialog, True) self.buttonBox = create_accept_reject_button_box(fileRenameDialog, True)

View File

@ -43,8 +43,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
context_menu_action, context_menu_separator, find_and_set_in_combo_box context_menu_action, context_menu_separator, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
from openlp.core.ui.printserviceform import PrintServiceForm from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ from openlp.core.utils import AppLocation, delete_file, split_filename
split_filename
from openlp.core.utils.actions import ActionList, CategoryOrder from openlp.core.utils.actions import ActionList, CategoryOrder
class ServiceManagerList(QtGui.QTreeWidget): class ServiceManagerList(QtGui.QTreeWidget):
@ -636,8 +635,11 @@ class ServiceManager(QtGui.QWidget):
try: try:
zip = zipfile.ZipFile(fileName) zip = zipfile.ZipFile(fileName)
for zipinfo in zip.infolist(): for zipinfo in zip.infolist():
ucsfile = file_is_unicode(zipinfo.filename) try:
if not ucsfile: ucsfile = zipinfo.filename.decode(u'utf-8')
except UnicodeDecodeError:
log.exception(u'Filename "%s" is not valid UTF-8' %
zipinfo.filename.decode(u'utf-8', u'replace'))
critical_error_message_box( critical_error_message_box(
message=translate('OpenLP.ServiceManager', message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n' 'File is not a valid service.\n'

View File

@ -30,6 +30,7 @@ import zipfile
import shutil import shutil
import logging import logging
import locale import locale
import re
from xml.etree.ElementTree import ElementTree, XML from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -43,8 +44,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
context_menu_action, context_menu_separator context_menu_action, context_menu_separator
from openlp.core.theme import Theme from openlp.core.theme import Theme
from openlp.core.ui import FileRenameForm, ThemeForm from openlp.core.ui import FileRenameForm, ThemeForm
from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
get_filesystem_encoding
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -147,6 +147,7 @@ class ThemeManager(QtGui.QWidget):
check_directory_exists(self.thumbPath) check_directory_exists(self.thumbPath)
self.themeForm.path = self.path self.themeForm.path = self.path
self.oldBackgroundImage = None self.oldBackgroundImage = None
self.bad_v1_name_chars = re.compile(r'[%+\[\]]')
# Last little bits of setting up # Last little bits of setting up
self.configUpdated() self.configUpdated()
@ -524,44 +525,50 @@ class ThemeManager(QtGui.QWidget):
filexml = None filexml = None
try: try:
zip = zipfile.ZipFile(filename) zip = zipfile.ZipFile(filename)
themename = None xmlfile = filter(lambda name:
for file in zip.namelist(): os.path.splitext(name)[1].lower() == u'.xml', zip.namelist())
# Handle UTF-8 files if len(xmlfile) != 1:
ucsfile = file_is_unicode(file) log.exception(u'Theme contains "%s" XML files' % len(xmlfile))
if not ucsfile: raise Exception(u'validation')
# Handle native Unicode files from Windows xml_tree = ElementTree(element=XML(zip.read(xmlfile[0]))).getroot()
ucsfile = file v1_background = xml_tree.find(u'BackgroundType')
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile)) if v1_background is not None:
theme_dir = None (themename, filexml, outfile) = self.unzipVersion122(dir, zip,
if osfile.endswith(os.path.sep): xmlfile[0], xml_tree, v1_background, outfile)
theme_dir = os.path.join(dir, osfile)
check_directory_exists(theme_dir)
else: else:
fullpath = os.path.join(dir, osfile) themename = xml_tree.find(u'name').text.strip()
names = osfile.split(os.path.sep) for name in zip.namelist():
if len(names) > 1: try:
# not preview file uname = unicode(name, u'utf-8')
if themename is None: except UnicodeDecodeError:
themename = names[0] log.exception(u'Theme file contains non utf-8 filename'
if theme_dir is None: u' "%s"' % name.decode(u'utf-8', u'replace'))
theme_dir = os.path.join(dir, names[0]) raise Exception(u'validation')
check_directory_exists(theme_dir) uname = unicode(QtCore.QDir.toNativeSeparators(uname))
if os.path.splitext(ucsfile)[1].lower() in [u'.xml']: splitname = uname.split(os.path.sep)
xml_data = zip.read(file) if splitname[-1] == u'' or len(splitname) == 1:
xml_data = file_is_unicode(xml_data) # is directory or preview file
if not xml_data: continue
break fullname = os.path.join(dir, uname)
filexml = self._checkVersionAndConvert(xml_data) check_directory_exists(os.path.dirname(fullname))
outfile = open(fullpath, u'w') if os.path.splitext(uname)[1].lower() == u'.xml':
filexml = unicode(zip.read(name), u'utf-8')
outfile = open(fullname, u'w')
outfile.write(filexml.encode(u'utf-8')) outfile.write(filexml.encode(u'utf-8'))
else: else:
outfile = open(fullpath, u'wb') outfile = open(fullname, u'wb')
outfile.write(zip.read(file)) outfile.write(zip.read(name))
except (IOError, NameError, zipfile.BadZipfile): outfile.close()
critical_error_message_box( except (IOError, zipfile.BadZipfile):
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename) log.exception(u'Importing theme from zip failed %s' % filename)
raise Exception(u'validation')
except Exception as info:
if unicode(info) == u'validation':
critical_error_message_box(translate('OpenLP.ThemeManager',
'Validation Error'), translate('OpenLP.ThemeManager',
'File is not a valid theme.'))
else:
raise
finally: finally:
# Close the files, to be able to continue creating the theme. # Close the files, to be able to continue creating the theme.
if zip: if zip:
@ -582,6 +589,36 @@ class ThemeManager(QtGui.QWidget):
log.exception(u'Theme file does not contain XML data %s' % log.exception(u'Theme file does not contain XML data %s' %
filename) filename)
def unzipVersion122(self, dir, zip, xmlfile, xml_tree, background, outfile):
"""
Unzip openlp.org 1.2x theme file and upgrade the theme xml. When calling
this method, please keep in mind, that some parameters are redundant.
"""
themename = xml_tree.find(u'Name').text.strip()
themename = self.bad_v1_name_chars.sub(u'', themename)
themedir = os.path.join(dir, themename)
check_directory_exists(themedir)
filexml = unicode(zip.read(xmlfile), u'utf-8')
filexml = self._migrateVersion122(filexml)
outfile = open(os.path.join(themedir, themename + u'.xml'), u'w')
outfile.write(filexml.encode(u'utf-8'))
outfile.close()
if background.text.strip() == u'2':
imagename = xml_tree.find(u'BackgroundParameter1').text.strip()
# image file has same extension and is in subfolder
imagefile = filter(lambda name: os.path.splitext(name)[1].lower()
== os.path.splitext(imagename)[1].lower() and name.find(r'/'),
zip.namelist())
if len(imagefile) >= 1:
outfile = open(os.path.join(themedir, imagename), u'wb')
outfile.write(zip.read(imagefile[0]))
outfile.close()
else:
log.exception(u'Theme file does not contain image file "%s"' %
imagename.decode(u'utf-8', u'replace'))
raise Exception(u'validation')
return (themename, filexml, outfile)
def checkIfThemeExists(self, themeName): def checkIfThemeExists(self, themeName):
""" """
Check if theme already exists and displays error message Check if theme already exists and displays error message
@ -692,22 +729,6 @@ class ThemeManager(QtGui.QWidget):
image = os.path.join(self.path, theme + u'.png') image = os.path.join(self.path, theme + u'.png')
return image return image
def _checkVersionAndConvert(self, xml_data):
"""
Check if a theme is from OpenLP version 1
``xml_data``
Theme XML to check the version of
"""
log.debug(u'checkVersion1 ')
theme = xml_data.encode(u'ascii', u'xmlcharrefreplace')
tree = ElementTree(element=XML(theme)).getroot()
# look for old version 1 tags
if tree.find(u'BackgroundType') is None:
return xml_data
else:
return self._migrateVersion122(xml_data)
def _createThemeFromXml(self, themeXml, path): def _createThemeFromXml(self, themeXml, path):
""" """
Return a theme object using information parsed from XML Return a theme object using information parsed from XML
@ -772,7 +793,7 @@ class ThemeManager(QtGui.QWidget):
""" """
theme = Theme(xml_data) theme = Theme(xml_data)
newtheme = ThemeXML() newtheme = ThemeXML()
newtheme.theme_name = theme.Name newtheme.theme_name = self.bad_v1_name_chars.sub(u'', theme.Name)
if theme.BackgroundType == 0: if theme.BackgroundType == 0:
newtheme.background_type = \ newtheme.background_type = \
BackgroundType.to_string(BackgroundType.Solid) BackgroundType.to_string(BackgroundType.Solid)

View File

@ -455,26 +455,6 @@ def get_web_page(url, header=None, update_openlp=False):
log.debug(page) log.debug(page)
return page return page
def file_is_unicode(filename):
"""
Checks if a file is valid unicode and returns the unicode decoded file or
None.
``filename``
File to check is valid unicode.
"""
if not filename:
return None
ucsfile = None
try:
ucsfile = filename.decode(u'utf-8')
except UnicodeDecodeError:
log.exception(u'Filename "%s" is not valid UTF-8' %
filename.decode(u'utf-8', u'replace'))
if not ucsfile:
return None
return ucsfile
def get_uno_command(): def get_uno_command():
""" """
Returns the UNO command to launch an openoffice.org instance. Returns the UNO command to launch an openoffice.org instance.
@ -507,5 +487,5 @@ from actions import ActionList
__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version', __all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', u'LanguageManager', u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
u'ActionList', u'get_web_page', u'file_is_unicode', u'get_uno_command', u'ActionList', u'get_web_page', u'get_uno_command', u'get_uno_instance',
u'get_uno_instance', u'delete_file', u'clean_filename'] u'delete_file', u'clean_filename']