From 2939151ff1e78841b361fe1090617ea07b13f6d5 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 21 Jun 2011 07:40:53 +0200 Subject: [PATCH 01/25] EasyWorship importer: added conversion of Tags - basically working, but some issues remain --- openlp/plugins/songs/lib/ewimport.py | 728 ++++++++++++++------------- 1 file changed, 380 insertions(+), 348 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 09f84fbe2..2431743d6 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -1,348 +1,380 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2011 Raoul Snyman # -# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # -# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # -# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # -# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # -# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`ewimport` module provides the functionality for importing -EasyWorship song databases into the current installation database. -""" - -import os -import struct - -from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib import retrieve_windows_encoding -from songimport import SongImport - -def strip_rtf(blob, encoding): - depth = 0 - control = False - clear_text = [] - control_word = [] - for c in blob: - if control: - # for delimiters, set control to False - if c == '{': - if len(control_word) > 0: - depth += 1 - control = False - elif c == '}': - if len(control_word) > 0: - depth -= 1 - control = False - elif c == '\\': - new_control = (len(control_word) > 0) - control = False - elif c.isspace(): - control = False - else: - control_word.append(c) - if len(control_word) == 3 and control_word[0] == '\'': - control = False - if not control: - if len(control_word) == 0: - if c == '{' or c == '}' or c == '\\': - clear_text.append(c) - else: - control_str = ''.join(control_word) - if control_str == 'par' or control_str == 'line': - clear_text.append(u'\n') - elif control_str == 'tab': - clear_text.append(u'\t') - # Prefer the encoding specified by the RTF data to that - # specified by the Paradox table header - # West European encoding - elif control_str == 'fcharset0': - encoding = u'cp1252' - # Greek encoding - elif control_str == 'fcharset161': - encoding = u'cp1253' - # Turkish encoding - elif control_str == 'fcharset162': - encoding = u'cp1254' - # Vietnamese encoding - elif control_str == 'fcharset163': - encoding = u'cp1258' - # Hebrew encoding - elif control_str == 'fcharset177': - encoding = u'cp1255' - # Arabic encoding - elif control_str == 'fcharset178': - encoding = u'cp1256' - # Baltic encoding - elif control_str == 'fcharset186': - encoding = u'cp1257' - # Cyrillic encoding - elif control_str == 'fcharset204': - encoding = u'cp1251' - # Thai encoding - elif control_str == 'fcharset222': - encoding = u'cp874' - # Central+East European encoding - elif control_str == 'fcharset238': - encoding = u'cp1250' - elif control_str[0] == '\'': - s = chr(int(control_str[1:3], 16)) - clear_text.append(s.decode(encoding)) - del control_word[:] - if c == '\\' and new_control: - control = True - elif c == '{': - depth += 1 - elif c == '}': - depth -= 1 - elif depth > 2: - continue - elif c == '\n' or c == '\r': - continue - elif c == '\\': - control = True - else: - clear_text.append(c) - return u''.join(clear_text) - -class FieldDescEntry: - def __init__(self, name, type, size): - self.name = name - self.type = type - self.size = size - - -class EasyWorshipSongImport(SongImport): - """ - The :class:`EasyWorshipSongImport` class provides OpenLP with the - ability to import EasyWorship song files. - """ - def __init__(self, manager, **kwargs): - SongImport.__init__(self, manager, **kwargs) - - def do_import(self): - # Open the DB and MB files if they exist - import_source_mb = self.import_source.replace('.DB', '.MB') - if not os.path.isfile(self.import_source): - return - if not os.path.isfile(import_source_mb): - return - db_size = os.path.getsize(self.import_source) - if db_size < 0x800: - return - db_file = open(self.import_source, 'rb') - self.memo_file = open(import_source_mb, 'rb') - # Don't accept files that are clearly not paradox files - record_size, header_size, block_size, first_block, num_fields \ - = struct.unpack(' 4: - db_file.close() - self.memo_file.close() - return - # Take a stab at how text is encoded - self.encoding = u'cp1252' - db_file.seek(106) - code_page, = struct.unpack(''] - for field_desc in field_descs: - if field_desc.type == 1: - # string - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 3: - # 16-bit int - fsl.append('H') - elif field_desc.type == 4: - # 32-bit int - fsl.append('I') - elif field_desc.type == 9: - # Logical - fsl.append('B') - elif field_desc.type == 0x0c: - # Memo - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x0d: - # Blob - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x15: - # Timestamp - fsl.append('Q') - else: - fsl.append('%ds' % field_desc.size) - self.record_struct = struct.Struct(''.join(fsl)) - self.field_descs = field_descs - - def get_field(self, field_desc_index): - field = self.fields[field_desc_index] - field_desc = self.field_descs[field_desc_index] - # Return None in case of 'blank' entries - if isinstance(field, str): - if len(field.rstrip('\0')) == 0: - return None - elif field == 0: - return None - # Format the field depending on the field type - if field_desc.type == 1: - # string - return field.rstrip('\0').decode(self.encoding) - elif field_desc.type == 3: - # 16-bit int - return field ^ 0x8000 - elif field_desc.type == 4: - # 32-bit int - return field ^ 0x80000000 - elif field_desc.type == 9: - # Logical - return (field ^ 0x80 == 1) - elif field_desc.type == 0x0c or field_desc.type == 0x0d: - # Memo or Blob - block_start, blob_size = \ - struct.unpack_from(' 63: - return u'' - self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) - sub_block_start, = struct.unpack('B', self.memo_file.read(1)) - self.memo_file.seek(block_start + (sub_block_start * 16)) - else: - return u'' - return self.memo_file.read(blob_size) - else: - return 0 +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`ewimport` module provides the functionality for importing +EasyWorship song databases into the current installation database. +""" + +import os +import struct +import re + +from openlp.core.lib import translate +from openlp.core.ui.wizard import WizardStrings +from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import retrieve_windows_encoding +from songimport import SongImport + +def strip_rtf(blob, encoding): + depth = 0 + control = False + clear_text = [] + control_word = [] + for c in blob: + if control: + # for delimiters, set control to False + if c == '{': + if len(control_word) > 0: + depth += 1 + control = False + elif c == '}': + if len(control_word) > 0: + depth -= 1 + control = False + elif c == '\\': + new_control = (len(control_word) > 0) + control = False + elif c.isspace(): + control = False + else: + control_word.append(c) + if len(control_word) == 3 and control_word[0] == '\'': + control = False + if not control: + if len(control_word) == 0: + if c == '{' or c == '}' or c == '\\': + clear_text.append(c) + else: + control_str = ''.join(control_word) + if control_str == 'par' or control_str == 'line': + clear_text.append(u'\n') + elif control_str == 'tab': + clear_text.append(u'\t') + # Prefer the encoding specified by the RTF data to that + # specified by the Paradox table header + # West European encoding + elif control_str == 'fcharset0': + encoding = u'cp1252' + # Greek encoding + elif control_str == 'fcharset161': + encoding = u'cp1253' + # Turkish encoding + elif control_str == 'fcharset162': + encoding = u'cp1254' + # Vietnamese encoding + elif control_str == 'fcharset163': + encoding = u'cp1258' + # Hebrew encoding + elif control_str == 'fcharset177': + encoding = u'cp1255' + # Arabic encoding + elif control_str == 'fcharset178': + encoding = u'cp1256' + # Baltic encoding + elif control_str == 'fcharset186': + encoding = u'cp1257' + # Cyrillic encoding + elif control_str == 'fcharset204': + encoding = u'cp1251' + # Thai encoding + elif control_str == 'fcharset222': + encoding = u'cp874' + # Central+East European encoding + elif control_str == 'fcharset238': + encoding = u'cp1250' + elif control_str[0] == '\'': + s = chr(int(control_str[1:3], 16)) + clear_text.append(s.decode(encoding)) + del control_word[:] + if c == '\\' and new_control: + control = True + elif c == '{': + depth += 1 + elif c == '}': + depth -= 1 + elif depth > 2: + continue + elif c == '\n' or c == '\r': + continue + elif c == '\\': + control = True + else: + clear_text.append(c) + return u''.join(clear_text) + +class FieldDescEntry: + def __init__(self, name, type, size): + self.name = name + self.type = type + self.size = size + + +class EasyWorshipSongImport(SongImport): + """ + The :class:`EasyWorshipSongImport` class provides OpenLP with the + ability to import EasyWorship song files. + """ + def __init__(self, manager, **kwargs): + SongImport.__init__(self, manager, **kwargs) + + def do_import(self): + # Open the DB and MB files if they exist + import_source_mb = self.import_source.replace('.DB', '.MB') + if not os.path.isfile(self.import_source): + return + if not os.path.isfile(import_source_mb): + return + db_size = os.path.getsize(self.import_source) + if db_size < 0x800: + return + db_file = open(self.import_source, 'rb') + self.memo_file = open(import_source_mb, 'rb') + # Don't accept files that are clearly not paradox files + record_size, header_size, block_size, first_block, num_fields \ + = struct.unpack(' 4: + db_file.close() + self.memo_file.close() + return + # Take a stab at how text is encoded + self.encoding = u'cp1252' + db_file.seek(106) + code_page, = struct.unpack(' len(type): # tag is followed by number and/or note + p = re.compile(r'[0-9]+') + m = re.search(p, ew_tag) + if m: + number = m.group() + verse_type +=number + + p = re.compile(r'\(.*\)') + m = re.search(p, ew_tag) + if m: + self.comments += ew_tag+'\n' + break + + self.add_verse( + verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 + verse_type) + if len(self.comments) > 5: + self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from EasyWorship]')) + if self.stop_import_flag: + break + if not self.finish(): + self.log_error(self.import_source) + db_file.close() + self.memo_file.close() + + def find_field(self, field_name): + return [i for i, x in enumerate(self.field_descs) + if x.name == field_name][0] + + def set_record_struct(self, field_descs): + # Begin with empty field struct list + fsl = ['>'] + for field_desc in field_descs: + if field_desc.type == 1: + # string + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 3: + # 16-bit int + fsl.append('H') + elif field_desc.type == 4: + # 32-bit int + fsl.append('I') + elif field_desc.type == 9: + # Logical + fsl.append('B') + elif field_desc.type == 0x0c: + # Memo + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x0d: + # Blob + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x15: + # Timestamp + fsl.append('Q') + else: + fsl.append('%ds' % field_desc.size) + self.record_struct = struct.Struct(''.join(fsl)) + self.field_descs = field_descs + + def get_field(self, field_desc_index): + field = self.fields[field_desc_index] + field_desc = self.field_descs[field_desc_index] + # Return None in case of 'blank' entries + if isinstance(field, str): + if len(field.rstrip('\0')) == 0: + return None + elif field == 0: + return None + # Format the field depending on the field type + if field_desc.type == 1: + # string + return field.rstrip('\0').decode(self.encoding) + elif field_desc.type == 3: + # 16-bit int + return field ^ 0x8000 + elif field_desc.type == 4: + # 32-bit int + return field ^ 0x80000000 + elif field_desc.type == 9: + # Logical + return (field ^ 0x80 == 1) + elif field_desc.type == 0x0c or field_desc.type == 0x0d: + # Memo or Blob + block_start, blob_size = \ + struct.unpack_from(' 63: + return u'' + self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) + sub_block_start, = struct.unpack('B', self.memo_file.read(1)) + self.memo_file.seek(block_start + (sub_block_start * 16)) + else: + return u'' + return self.memo_file.read(blob_size) + else: + return 0 From 31dd4945bae57b2aeaa2f0310290d40824413b6d Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 21 Jun 2011 07:55:11 +0200 Subject: [PATCH 02/25] fixed line endings --- openlp/plugins/songs/lib/ewimport.py | 759 +++++++++++++-------------- 1 file changed, 379 insertions(+), 380 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 2431743d6..fb82ab347 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -1,380 +1,379 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2011 Raoul Snyman # -# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # -# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # -# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # -# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # -# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`ewimport` module provides the functionality for importing -EasyWorship song databases into the current installation database. -""" - -import os -import struct -import re - -from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib import retrieve_windows_encoding -from songimport import SongImport - -def strip_rtf(blob, encoding): - depth = 0 - control = False - clear_text = [] - control_word = [] - for c in blob: - if control: - # for delimiters, set control to False - if c == '{': - if len(control_word) > 0: - depth += 1 - control = False - elif c == '}': - if len(control_word) > 0: - depth -= 1 - control = False - elif c == '\\': - new_control = (len(control_word) > 0) - control = False - elif c.isspace(): - control = False - else: - control_word.append(c) - if len(control_word) == 3 and control_word[0] == '\'': - control = False - if not control: - if len(control_word) == 0: - if c == '{' or c == '}' or c == '\\': - clear_text.append(c) - else: - control_str = ''.join(control_word) - if control_str == 'par' or control_str == 'line': - clear_text.append(u'\n') - elif control_str == 'tab': - clear_text.append(u'\t') - # Prefer the encoding specified by the RTF data to that - # specified by the Paradox table header - # West European encoding - elif control_str == 'fcharset0': - encoding = u'cp1252' - # Greek encoding - elif control_str == 'fcharset161': - encoding = u'cp1253' - # Turkish encoding - elif control_str == 'fcharset162': - encoding = u'cp1254' - # Vietnamese encoding - elif control_str == 'fcharset163': - encoding = u'cp1258' - # Hebrew encoding - elif control_str == 'fcharset177': - encoding = u'cp1255' - # Arabic encoding - elif control_str == 'fcharset178': - encoding = u'cp1256' - # Baltic encoding - elif control_str == 'fcharset186': - encoding = u'cp1257' - # Cyrillic encoding - elif control_str == 'fcharset204': - encoding = u'cp1251' - # Thai encoding - elif control_str == 'fcharset222': - encoding = u'cp874' - # Central+East European encoding - elif control_str == 'fcharset238': - encoding = u'cp1250' - elif control_str[0] == '\'': - s = chr(int(control_str[1:3], 16)) - clear_text.append(s.decode(encoding)) - del control_word[:] - if c == '\\' and new_control: - control = True - elif c == '{': - depth += 1 - elif c == '}': - depth -= 1 - elif depth > 2: - continue - elif c == '\n' or c == '\r': - continue - elif c == '\\': - control = True - else: - clear_text.append(c) - return u''.join(clear_text) - -class FieldDescEntry: - def __init__(self, name, type, size): - self.name = name - self.type = type - self.size = size - - -class EasyWorshipSongImport(SongImport): - """ - The :class:`EasyWorshipSongImport` class provides OpenLP with the - ability to import EasyWorship song files. - """ - def __init__(self, manager, **kwargs): - SongImport.__init__(self, manager, **kwargs) - - def do_import(self): - # Open the DB and MB files if they exist - import_source_mb = self.import_source.replace('.DB', '.MB') - if not os.path.isfile(self.import_source): - return - if not os.path.isfile(import_source_mb): - return - db_size = os.path.getsize(self.import_source) - if db_size < 0x800: - return - db_file = open(self.import_source, 'rb') - self.memo_file = open(import_source_mb, 'rb') - # Don't accept files that are clearly not paradox files - record_size, header_size, block_size, first_block, num_fields \ - = struct.unpack(' 4: - db_file.close() - self.memo_file.close() - return - # Take a stab at how text is encoded - self.encoding = u'cp1252' - db_file.seek(106) - code_page, = struct.unpack(' len(type): # tag is followed by number and/or note - p = re.compile(r'[0-9]+') - m = re.search(p, ew_tag) - if m: - number = m.group() - verse_type +=number - - p = re.compile(r'\(.*\)') - m = re.search(p, ew_tag) - if m: - self.comments += ew_tag+'\n' - break - - self.add_verse( - verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 - verse_type) - if len(self.comments) > 5: - self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', - '\n[above are Song Tags with notes imported from EasyWorship]')) - if self.stop_import_flag: - break - if not self.finish(): - self.log_error(self.import_source) - db_file.close() - self.memo_file.close() - - def find_field(self, field_name): - return [i for i, x in enumerate(self.field_descs) - if x.name == field_name][0] - - def set_record_struct(self, field_descs): - # Begin with empty field struct list - fsl = ['>'] - for field_desc in field_descs: - if field_desc.type == 1: - # string - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 3: - # 16-bit int - fsl.append('H') - elif field_desc.type == 4: - # 32-bit int - fsl.append('I') - elif field_desc.type == 9: - # Logical - fsl.append('B') - elif field_desc.type == 0x0c: - # Memo - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x0d: - # Blob - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x15: - # Timestamp - fsl.append('Q') - else: - fsl.append('%ds' % field_desc.size) - self.record_struct = struct.Struct(''.join(fsl)) - self.field_descs = field_descs - - def get_field(self, field_desc_index): - field = self.fields[field_desc_index] - field_desc = self.field_descs[field_desc_index] - # Return None in case of 'blank' entries - if isinstance(field, str): - if len(field.rstrip('\0')) == 0: - return None - elif field == 0: - return None - # Format the field depending on the field type - if field_desc.type == 1: - # string - return field.rstrip('\0').decode(self.encoding) - elif field_desc.type == 3: - # 16-bit int - return field ^ 0x8000 - elif field_desc.type == 4: - # 32-bit int - return field ^ 0x80000000 - elif field_desc.type == 9: - # Logical - return (field ^ 0x80 == 1) - elif field_desc.type == 0x0c or field_desc.type == 0x0d: - # Memo or Blob - block_start, blob_size = \ - struct.unpack_from(' 63: - return u'' - self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) - sub_block_start, = struct.unpack('B', self.memo_file.read(1)) - self.memo_file.seek(block_start + (sub_block_start * 16)) - else: - return u'' - return self.memo_file.read(blob_size) - else: - return 0 +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`ewimport` module provides the functionality for importing +EasyWorship song databases into the current installation database. +""" + +import os +import struct +import re + +from openlp.core.lib import translate +from openlp.core.ui.wizard import WizardStrings +from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import retrieve_windows_encoding +from songimport import SongImport + +def strip_rtf(blob, encoding): + depth = 0 + control = False + clear_text = [] + control_word = [] + for c in blob: + if control: + # for delimiters, set control to False + if c == '{': + if len(control_word) > 0: + depth += 1 + control = False + elif c == '}': + if len(control_word) > 0: + depth -= 1 + control = False + elif c == '\\': + new_control = (len(control_word) > 0) + control = False + elif c.isspace(): + control = False + else: + control_word.append(c) + if len(control_word) == 3 and control_word[0] == '\'': + control = False + if not control: + if len(control_word) == 0: + if c == '{' or c == '}' or c == '\\': + clear_text.append(c) + else: + control_str = ''.join(control_word) + if control_str == 'par' or control_str == 'line': + clear_text.append(u'\n') + elif control_str == 'tab': + clear_text.append(u'\t') + # Prefer the encoding specified by the RTF data to that + # specified by the Paradox table header + # West European encoding + elif control_str == 'fcharset0': + encoding = u'cp1252' + # Greek encoding + elif control_str == 'fcharset161': + encoding = u'cp1253' + # Turkish encoding + elif control_str == 'fcharset162': + encoding = u'cp1254' + # Vietnamese encoding + elif control_str == 'fcharset163': + encoding = u'cp1258' + # Hebrew encoding + elif control_str == 'fcharset177': + encoding = u'cp1255' + # Arabic encoding + elif control_str == 'fcharset178': + encoding = u'cp1256' + # Baltic encoding + elif control_str == 'fcharset186': + encoding = u'cp1257' + # Cyrillic encoding + elif control_str == 'fcharset204': + encoding = u'cp1251' + # Thai encoding + elif control_str == 'fcharset222': + encoding = u'cp874' + # Central+East European encoding + elif control_str == 'fcharset238': + encoding = u'cp1250' + elif control_str[0] == '\'': + s = chr(int(control_str[1:3], 16)) + clear_text.append(s.decode(encoding)) + del control_word[:] + if c == '\\' and new_control: + control = True + elif c == '{': + depth += 1 + elif c == '}': + depth -= 1 + elif depth > 2: + continue + elif c == '\n' or c == '\r': + continue + elif c == '\\': + control = True + else: + clear_text.append(c) + return u''.join(clear_text) + +class FieldDescEntry: + def __init__(self, name, type, size): + self.name = name + self.type = type + self.size = size + + +class EasyWorshipSongImport(SongImport): + """ + The :class:`EasyWorshipSongImport` class provides OpenLP with the + ability to import EasyWorship song files. + """ + def __init__(self, manager, **kwargs): + SongImport.__init__(self, manager, **kwargs) + + def do_import(self): + # Open the DB and MB files if they exist + import_source_mb = self.import_source.replace('.DB', '.MB') + if not os.path.isfile(self.import_source): + return + if not os.path.isfile(import_source_mb): + return + db_size = os.path.getsize(self.import_source) + if db_size < 0x800: + return + db_file = open(self.import_source, 'rb') + self.memo_file = open(import_source_mb, 'rb') + # Don't accept files that are clearly not paradox files + record_size, header_size, block_size, first_block, num_fields \ + = struct.unpack(' 4: + db_file.close() + self.memo_file.close() + return + # Take a stab at how text is encoded + self.encoding = u'cp1252' + db_file.seek(106) + code_page, = struct.unpack(' len(type): # tag is followed by number and/or note + p = re.compile(r'[0-9]+') + m = re.search(p, ew_tag) + if m: + number = m.group() + verse_type +=number + + p = re.compile(r'\(.*\)') + m = re.search(p, ew_tag) + if m: + self.comments += ew_tag+'\n' + break + self.add_verse( + verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 + verse_type) + if len(self.comments) > 5: + self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from EasyWorship]')) + if self.stop_import_flag: + break + if not self.finish(): + self.log_error(self.import_source) + db_file.close() + self.memo_file.close() + + def find_field(self, field_name): + return [i for i, x in enumerate(self.field_descs) + if x.name == field_name][0] + + def set_record_struct(self, field_descs): + # Begin with empty field struct list + fsl = ['>'] + for field_desc in field_descs: + if field_desc.type == 1: + # string + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 3: + # 16-bit int + fsl.append('H') + elif field_desc.type == 4: + # 32-bit int + fsl.append('I') + elif field_desc.type == 9: + # Logical + fsl.append('B') + elif field_desc.type == 0x0c: + # Memo + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x0d: + # Blob + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x15: + # Timestamp + fsl.append('Q') + else: + fsl.append('%ds' % field_desc.size) + self.record_struct = struct.Struct(''.join(fsl)) + self.field_descs = field_descs + + def get_field(self, field_desc_index): + field = self.fields[field_desc_index] + field_desc = self.field_descs[field_desc_index] + # Return None in case of 'blank' entries + if isinstance(field, str): + if len(field.rstrip('\0')) == 0: + return None + elif field == 0: + return None + # Format the field depending on the field type + if field_desc.type == 1: + # string + return field.rstrip('\0').decode(self.encoding) + elif field_desc.type == 3: + # 16-bit int + return field ^ 0x8000 + elif field_desc.type == 4: + # 32-bit int + return field ^ 0x80000000 + elif field_desc.type == 9: + # Logical + return (field ^ 0x80 == 1) + elif field_desc.type == 0x0c or field_desc.type == 0x0d: + # Memo or Blob + block_start, blob_size = \ + struct.unpack_from(' 63: + return u'' + self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) + sub_block_start, = struct.unpack('B', self.memo_file.read(1)) + self.memo_file.seek(block_start + (sub_block_start * 16)) + else: + return u'' + return self.memo_file.read(blob_size) + else: + return 0 From bddf91ddcb748d6c6929e95cbad80d414cab9da0 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 1 Jul 2011 17:55:07 +0100 Subject: [PATCH 03/25] Add ability to clone songs Amend framework for plugins to add non toolbar context items Fixes: https://launchpad.net/bugs/763583 --- openlp/core/lib/mediamanageritem.py | 8 ++++++++ openlp/plugins/songs/lib/mediaitem.py | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index a79355c88..17862326e 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -288,6 +288,7 @@ class MediaManagerItem(QtGui.QWidget): self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick) + self.addCutomContextActions() # Create the context menu and add all actions from the listView. self.menu = QtGui.QMenu() self.menu.addActions(self.listView.actions()) @@ -301,6 +302,13 @@ class MediaManagerItem(QtGui.QWidget): QtCore.SIGNAL('customContextMenuRequested(QPoint)'), self.contextMenu) + def addCutomContextActions(self): + """ + Implement this method in your descendent media manager item to + add any context menu items. This method is called automatically. + """ + pass + def initialise(self): """ Implement this method in your descendent media manager item to diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index e2efbe3df..9082d8a1f 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -35,7 +35,8 @@ from sqlalchemy.sql import or_ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate, check_item_selected, PluginStatus from openlp.core.lib.searchedit import SearchEdit -from openlp.core.lib.ui import UiStrings +from openlp.core.lib.ui import UiStrings, context_menu_action, \ + context_menu_separator from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ SongImportForm, SongExportForm from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \ @@ -128,6 +129,13 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'searchTypeChanged(int)'), self.onSearchTextButtonClick) + def addCutomContextActions(self): + context_menu_separator(self.listView) + context_menu_action( + self.listView, u':/general/general_add.png', + translate('OpenLP.MediaManagerItem', + '&Clone.'), self.onCloneClick) + def onFocus(self): self.searchTextEdit.setFocus() @@ -366,6 +374,23 @@ class SongMediaItem(MediaManagerItem): self.plugin.manager.delete_object(Song, item_id) self.onSearchTextButtonClick() + def onCloneClick(self): + """ + Clone a Song + """ + log.debug(u'onCloneClick') + if check_item_selected(self.listView, UiStrings().SelectEdit): + self.editItem = self.listView.currentItem() + item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0] + old_song = self.plugin.manager.get_object(Song, item_id) + song_xml = self.openLyrics.song_to_xml(old_song) + new_song_id = self.openLyrics.xml_to_song(song_xml) + new_song = self.plugin.manager.get_object(Song, new_song_id) + new_song.title = u'%s <%s>' % (new_song.title, + translate('SongsPlugin.MediaItem', 'copy')) + self.plugin.manager.save_object(new_song) + self.onSongListLoad() + def generateSlideData(self, service_item, item=None, xmlVersion=False): log.debug(u'generateSlideData (%s:%s)' % (service_item, item)) item_id = self._getIdOfItemToGenerate(item, self.remoteSong) From 219218161b11f86ec6fbe709fd77b27d5bff8608 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 1 Jul 2011 17:59:56 +0100 Subject: [PATCH 04/25] 6am spelling fix --- openlp/core/lib/mediamanageritem.py | 4 ++-- openlp/plugins/songs/lib/mediaitem.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 17862326e..0cc25717c 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -288,7 +288,7 @@ class MediaManagerItem(QtGui.QWidget): self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick) - self.addCutomContextActions() + self.addCustomContextActions() # Create the context menu and add all actions from the listView. self.menu = QtGui.QMenu() self.menu.addActions(self.listView.actions()) @@ -302,7 +302,7 @@ class MediaManagerItem(QtGui.QWidget): QtCore.SIGNAL('customContextMenuRequested(QPoint)'), self.contextMenu) - def addCutomContextActions(self): + def addCustomContextActions(self): """ Implement this method in your descendent media manager item to add any context menu items. This method is called automatically. diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 9082d8a1f..743013934 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -129,7 +129,7 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'searchTypeChanged(int)'), self.onSearchTextButtonClick) - def addCutomContextActions(self): + def addCustomContextActions(self): context_menu_separator(self.listView) context_menu_action( self.listView, u':/general/general_add.png', From bc808ade93762cf5d3a1a4501e0f3378a1cee4c3 Mon Sep 17 00:00:00 2001 From: Benny Date: Sat, 2 Jul 2011 00:45:27 +0200 Subject: [PATCH 05/25] EasyWorshipSongImport: use tag from previous slide for slides without tag, fix regex for notes --- openlp/plugins/songs/lib/ewimport.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index c207a07d2..95533ba94 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -261,6 +261,7 @@ class EasyWorshipSongImport(SongImport): # Format the lyrics words = strip_rtf(words, self.encoding) # TODO: convert rtf instead of stripping? p = re.compile(r'\n *?\n[\n ]*') # at least two newlines, with zero or more space characters between them + verse_type = VerseType.Tags[VerseType.Verse] # TODO!!!: use previous verse type.... for verse in p.split(words): #for verse in words.split(u'\n\n'): # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide @@ -268,13 +269,11 @@ class EasyWorshipSongImport(SongImport): if len(verse) == 0: continue verse_split = verse.split(u'\n', 1) - verse_type = VerseType.Tags[VerseType.Verse] first_line_is_tag = False for type in VerseType.Names+['tag', 'slide']: # doesnt cover tag, slide type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): - #print ew_tag verse_type = type[0] if type == 'tag' or type == 'slide': verse_type = VerseType.Tags[VerseType.Other] @@ -286,7 +285,7 @@ class EasyWorshipSongImport(SongImport): number = m.group() verse_type +=number - p = re.compile(r'\(.*\)') + p = re.compile(r'\(.*?\)') m = re.search(p, ew_tag) if m: self.comments += ew_tag+'\n' From 6a259e0489470ebfa1f9e4c46a8ea2e80238e266 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 2 Jul 2011 06:51:03 +0100 Subject: [PATCH 06/25] Correct build icon --- openlp/plugins/bibles/lib/mediaitem.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index cb8273327..5ad8af73d 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -34,7 +34,8 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings, add_widget_completer, \ - media_item_combo_box, critical_error_message_box, find_and_set_in_combo_box + media_item_combo_box, critical_error_message_box, \ + find_and_set_in_combo_box, build_icon from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \ VerseReferenceList, get_reference_match @@ -57,8 +58,8 @@ class BibleMediaItem(MediaManagerItem): def __init__(self, parent, plugin, icon): self.IconPath = u'songs/song' - self.lockIcon = QtGui.QIcon(u':/bibles/bibles_search_lock.png') - self.unlockIcon = QtGui.QIcon(u':/bibles/bibles_search_unlock.png') + self.lockIcon = build_icon(u':/bibles/bibles_search_lock.png') + self.unlockIcon = build_icon(u':/bibles/bibles_search_unlock.png') MediaManagerItem.__init__(self, parent, plugin, icon) # Place to store the search results for both bibles. self.settings = self.plugin.settings_tab From 091cdbbc24ee25684116b1b0ec7002edbf2ef8f6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 2 Jul 2011 07:48:17 +0100 Subject: [PATCH 07/25] Slow down slidecontroller events to allow buffers to clear. Line wrap incorrect and fix object name Fixes: https://launchpad.net/bugs/752374 --- openlp/core/ui/servicemanager.py | 8 ++++---- openlp/core/ui/slidecontroller.py | 3 +++ openlp/plugins/bibles/lib/mediaitem.py | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 6424dfb2c..cccbed399 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -48,18 +48,18 @@ class ServiceManagerList(QtGui.QTreeWidget): """ Set up key bindings and mouse behaviour for the service list """ - def __init__(self, mainwindow, parent=None, name=None): + def __init__(self, serviceManager, parent=None, name=None): QtGui.QTreeWidget.__init__(self, parent) - self.mainwindow = mainwindow + self.serviceManager = serviceManager def keyPressEvent(self, event): if isinstance(event, QtGui.QKeyEvent): # here accept the event and do something if event.key() == QtCore.Qt.Key_Up: - self.mainwindow.onMoveSelectionUp() + self.serviceManager.onMoveSelectionUp() event.accept() elif event.key() == QtCore.Qt.Key_Down: - self.mainwindow.onMoveSelectionDown() + self.serviceManager.onMoveSelectionDown() event.accept() event.ignore() else: diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8e2c199a1..e86e2e760 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -27,6 +27,7 @@ import logging import os +import time from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon @@ -412,9 +413,11 @@ class SlideController(QtGui.QWidget): self.display.videoStop() def servicePrevious(self): + time.sleep(0.1) Receiver.send_message('servicemanager_previous_item') def serviceNext(self): + time.sleep(0.1) Receiver.send_message('servicemanager_next_item') def screenSizeChanged(self): diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 5ad8af73d..0734df818 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -984,7 +984,8 @@ class BibleMediaItem(MediaManagerItem): Search for some Bible verses (by reference). """ bible = unicode(self.quickVersionComboBox.currentText()) - search_results = self.plugin.manager.get_verses(bible, string, False, False) + search_results = self.plugin.manager.get_verses(bible, string, False, + False) if search_results: versetext = u' '.join([verse.text for verse in search_results]) return [[string, versetext]] From 2a73f1b1889d0a7c24a17f607f7945d69a1516a6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 09:13:48 +0100 Subject: [PATCH 08/25] Prevent Images and Media backgrounds being added when No service Item is present in the live controller. Fixes: https://launchpad.net/bugs/795980 --- openlp/core/ui/maindisplay.py | 7 ++++++- openlp/plugins/images/lib/mediaitem.py | 9 +++++++-- openlp/plugins/media/lib/mediaitem.py | 8 ++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index b661b1e49..72a998efe 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -233,10 +233,12 @@ class MainDisplay(QtGui.QGraphicsView): API for replacement backgrounds so Images are added directly to cache """ self.image_manager.add_image(name, path) - self.image(name) if hasattr(self, u'serviceItem'): self.override[u'image'] = name self.override[u'theme'] = self.serviceItem.themedata.theme_name + self.image(name) + return True + return False def image(self, name): """ @@ -349,6 +351,9 @@ class MainDisplay(QtGui.QGraphicsView): """ Loads and starts a video to run with the option of sound """ + # We request a background video but have no service Item + if isBackground and not hasattr(self, u'serviceItem'): + return None if not self.mediaObject: self.createMediaObject() log.debug(u'video') diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 481b55c09..3c4489bbc 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -208,8 +208,13 @@ class ImageMediaItem(MediaManagerItem): filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): (path, name) = os.path.split(filename) - self.plugin.liveController.display.directImage(name, filename) - self.resetAction.setVisible(True) + if self.plugin.liveController.display.directImage(name, + filename): + self.resetAction.setVisible(True) + else: + critical_error_message_box(UiStrings().LiveBGError, + translate('ImagePlugin.MediaItem', + 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, unicode(translate('ImagePlugin.MediaItem', diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 1e39a0426..77f91a529 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -114,8 +114,12 @@ class MediaMediaItem(MediaManagerItem): filename = unicode(item.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): (path, name) = os.path.split(filename) - self.plugin.liveController.display.video(filename, 0, True) - self.resetAction.setVisible(True) + if self.plugin.liveController.display.video(filename, 0, True): + self.resetAction.setVisible(True) + else: + critical_error_message_box(UiStrings().LiveBGError, + translate('MediaPlugin.MediaItem', + 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, unicode(translate('MediaPlugin.MediaItem', From 1c454b606fc76f598d6ea9371b17a613322032aa Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 13:43:31 +0100 Subject: [PATCH 09/25] Fix fullstop and add icon --- openlp/plugins/songs/lib/mediaitem.py | 4 ++-- resources/images/general_clone.png | Bin 0 -> 527 bytes resources/images/openlp-2.qrc | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 resources/images/general_clone.png diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 743013934..e9335a684 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -132,9 +132,9 @@ class SongMediaItem(MediaManagerItem): def addCustomContextActions(self): context_menu_separator(self.listView) context_menu_action( - self.listView, u':/general/general_add.png', + self.listView, u':/general/general_clone.png', translate('OpenLP.MediaManagerItem', - '&Clone.'), self.onCloneClick) + '&Clone'), self.onCloneClick) def onFocus(self): self.searchTextEdit.setFocus() diff --git a/resources/images/general_clone.png b/resources/images/general_clone.png new file mode 100644 index 0000000000000000000000000000000000000000..db1d9fbafc2f08e1beef834d7128ada961f53ea5 GIT binary patch literal 527 zcmV+q0`UEbP)pya@#$h3+(` zJq0}ybtIrch?)+XKnZ~=3M-;iiImO76nn{Jmx7V3(Rjz7|M|TF`~mj(-RipgYnX_D zz0V}+xPzIZB8Vy?k_CVWs>;^pW(%kR$nOAYGv0@d1FGY_B~9f0PSEdWW-J={wZHRw>t ztrk}SD+S@(0tJ-`)b6eQNZ~4H{{zI`Nz;^Rn)>t0b3Xzc5m!|SC5D~C;(otRqp`vN z^Yi=btLsaE9pC^s1P=G(_+m1d_;fn;G);XzpZj95@a1ypgeneral_save.png general_email.png general_revert.png + general_clone.png slide_close.png From 4bf45ad2defe7018062c65abdc1b586e7d241c2e Mon Sep 17 00:00:00 2001 From: Benny Date: Mon, 4 Jul 2011 22:51:43 +0200 Subject: [PATCH 10/25] ewimport: workaround for RTF stripping bug --- openlp/plugins/songs/lib/ewimport.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 95533ba94..a50c97f47 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -44,6 +44,14 @@ def strip_rtf(blob, encoding): control = False clear_text = [] control_word = [] + + # workaround for \tx bug: remove one pair of curly braces if \tx is encountered + p = re.compile(r'\{\\tx[^}]*\}') + m = p.search(blob) + if m: + # start and end indices of match are curly braces - filter them out + blob = ''.join([blob[i] for i in xrange(len(blob)) if i != m.start() and i !=m.end()]) + for c in blob: if control: # for delimiters, set control to False From 3c0c9c5b781d80899f1b73543a085c779bfc9ac8 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 00:55:57 +0200 Subject: [PATCH 11/25] EasyWorship importer: some work to create more reasonable verse numbers if EW tags are missing or without numbers --- openlp/plugins/songs/lib/ewimport.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index a50c97f47..18b87f9c0 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -267,18 +267,18 @@ class EasyWorshipSongImport(SongImport): self.add_author(author_name.strip()) if words: # Format the lyrics - words = strip_rtf(words, self.encoding) # TODO: convert rtf instead of stripping? - p = re.compile(r'\n *?\n[\n ]*') # at least two newlines, with zero or more space characters between them - verse_type = VerseType.Tags[VerseType.Verse] # TODO!!!: use previous verse type.... + words = strip_rtf(words, self.encoding) # TODO: convert rtf to display tags? + # regex: at least two newlines, with zero or more space characters between them + p = re.compile(r'\n *?\n[\n ]*') + verse_type = VerseType.Tags[VerseType.Verse] for verse in p.split(words): - #for verse in words.split(u'\n\n'): - # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide verse = verse.strip() if len(verse) == 0: continue verse_split = verse.split(u'\n', 1) first_line_is_tag = False - for type in VerseType.Names+['tag', 'slide']: # doesnt cover tag, slide + # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide + for type in VerseType.Names+['tag', 'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): @@ -286,20 +286,24 @@ class EasyWorshipSongImport(SongImport): if type == 'tag' or type == 'slide': verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True + number_found = False if len(ew_tag) > len(type): # tag is followed by number and/or note p = re.compile(r'[0-9]+') m = re.search(p, ew_tag) if m: number = m.group() verse_type +=number + number_found = True p = re.compile(r'\(.*?\)') m = re.search(p, ew_tag) if m: self.comments += ew_tag+'\n' + if not number_found: + verse_type += '1' break self.add_verse( - verse_split[-1].strip() if first_line_is_tag else verse, # TODO: hacky: -1 + verse_split[-1].strip() if first_line_is_tag else verse, verse_type) if len(self.comments) > 5: self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', From 6436b05240635a5b5c3fd4675e32fad3bf46c7d4 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 12:50:55 +0200 Subject: [PATCH 12/25] changes from review (cosmetic & regex performance) --- openlp/plugins/songs/lib/ewimport.py | 54 +++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 18b87f9c0..732c6e4f0 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -39,18 +39,25 @@ from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import retrieve_windows_encoding from songimport import SongImport +RTF_STRIPPING_REGEX = re.compile(r'\{\\tx[^}]*\}') +# regex: at least two newlines, can have spaces between them +SLIDE_BREAK_REGEX = re.compile(r'\n *?\n[\n ]*') +NUMBER_REGEX = re.compile(r'[0-9]+') +NOTE_REGEX = re.compile(r'\(.*?\)') + def strip_rtf(blob, encoding): depth = 0 control = False clear_text = [] control_word = [] - # workaround for \tx bug: remove one pair of curly braces if \tx is encountered - p = re.compile(r'\{\\tx[^}]*\}') - m = p.search(blob) - if m: + # workaround for \tx bug: remove one pair of curly braces + # if \tx is encountered + match = RTF_STRIPPING_REGEX.search(blob) + if match: # start and end indices of match are curly braces - filter them out - blob = ''.join([blob[i] for i in xrange(len(blob)) if i != m.start() and i !=m.end()]) + blob = ''.join([blob[i] for i in xrange(len(blob)) + if i != match.start() and i !=match.end()]) for c in blob: if control: @@ -267,17 +274,16 @@ class EasyWorshipSongImport(SongImport): self.add_author(author_name.strip()) if words: # Format the lyrics - words = strip_rtf(words, self.encoding) # TODO: convert rtf to display tags? - # regex: at least two newlines, with zero or more space characters between them - p = re.compile(r'\n *?\n[\n ]*') + words = strip_rtf(words, self.encoding) verse_type = VerseType.Tags[VerseType.Verse] - for verse in p.split(words): + for verse in SLIDE_BREAK_REGEX.split(words): verse = verse.strip() if len(verse) == 0: continue - verse_split = verse.split(u'\n', 1) + verse_split = verse.split(u'\n', 1) first_line_is_tag = False - # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide + # EW tags: verse, chorus, pre-chorus, bridge, tag, + # intro, ending, slide for type in VerseType.Names+['tag', 'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() @@ -287,27 +293,27 @@ class EasyWorshipSongImport(SongImport): verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True number_found = False - if len(ew_tag) > len(type): # tag is followed by number and/or note - p = re.compile(r'[0-9]+') - m = re.search(p, ew_tag) - if m: - number = m.group() + # check if tag is followed by number and/or note + if len(ew_tag) > len(type): + match = NUMBER_REGEX.search(ew_tag) + if match: + number = match.group() verse_type +=number number_found = True - - p = re.compile(r'\(.*?\)') - m = re.search(p, ew_tag) - if m: - self.comments += ew_tag+'\n' + match = NOTE_REGEX.search(ew_tag) + if match: + self.comments += ew_tag + u'\n' if not number_found: - verse_type += '1' + verse_type += u'1' break self.add_verse( verse_split[-1].strip() if first_line_is_tag else verse, verse_type) if len(self.comments) > 5: - self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', - '\n[above are Song Tags with notes imported from EasyWorship]')) + self.comments += unicode( + translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from \ + EasyWorship]')) if self.stop_import_flag: break if not self.finish(): From 1876d520ae4a23899210c6ca5efe3ee474a588ac Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 14:00:34 +0200 Subject: [PATCH 13/25] review fixes --- openlp/plugins/songs/lib/ewimport.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 732c6e4f0..448d629d5 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -278,18 +278,18 @@ class EasyWorshipSongImport(SongImport): verse_type = VerseType.Tags[VerseType.Verse] for verse in SLIDE_BREAK_REGEX.split(words): verse = verse.strip() - if len(verse) == 0: + if not verse: continue verse_split = verse.split(u'\n', 1) first_line_is_tag = False # EW tags: verse, chorus, pre-chorus, bridge, tag, # intro, ending, slide - for type in VerseType.Names+['tag', 'slide']: + for type in VerseType.Names+[u'tag', u'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): verse_type = type[0] - if type == 'tag' or type == 'slide': + if type == u'tag' or type == u'slide': verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True number_found = False @@ -298,7 +298,7 @@ class EasyWorshipSongImport(SongImport): match = NUMBER_REGEX.search(ew_tag) if match: number = match.group() - verse_type +=number + verse_type += number number_found = True match = NOTE_REGEX.search(ew_tag) if match: From 439b5592698bcda0cb195a1ee5e8576b2bd674c3 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 5 Jul 2011 22:17:17 +0200 Subject: [PATCH 14/25] Add main script path, make paths more readable. --- scripts/windows-builder.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index d6f4d42e3..f1d53e600 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -96,7 +96,7 @@ psvince.dll the install will fail. The dll can be obtained from here: http://www.vincenzo.net/isxkb/index.php?title=PSVince) -Mako +Mako Mako Templates for Python. This package is required for building the remote plugin. It can be installed by going to your python_directory\scripts\.. and running "easy_install Mako". If you do not @@ -319,17 +319,19 @@ def main(): import sys for arg in sys.argv: if arg == u'-v' or arg == u'--verbose': - print "Script path:", script_path - print "Branch path:", branch_path - print "Source path:", source_path - print "\"dist\" path:", dist_path - print "PyInstaller:", pyi_build + print "OpenLP main script: ......", openlp_main_script + print "Script path: .............", script_path + print "Branch path: .............", branch_path + print "Source path: .............", source_path + print "\"dist\" path: .............", dist_path + print "PyInstaller: .............", pyi_build print "Documentation branch path:", doc_branch_path - print "Help file build path;", helpfile_path - print "Inno Setup path:", innosetup_exe - print "Windows resources:", winres_path - print "VCBuild path:", vcbuild_exe - print "PPTVIEWLIB path:", pptviewlib_path + print "Help file build path: ....", helpfile_path + print "Inno Setup path: .........", innosetup_exe + print "Windows resources: .......", winres_path + print "VCBuild path: ............", vcbuild_exe + print "PPTVIEWLIB path: .........", pptviewlib_path + print "" elif arg == u'--skip-update': skip_update = True elif arg == u'/?' or arg == u'-h' or arg == u'--help': From 447016c1892247fc7a32619546bc110c82614269 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 6 Jul 2011 20:36:33 +0200 Subject: [PATCH 15/25] Updated Windows build script to work with new PyInstaller and PyQt4 locations. --- scripts/windows-builder.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index f1d53e600..be1a5fd3e 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -133,7 +133,10 @@ site_packages = os.path.join(os.path.split(python_exe)[0], u'Lib', pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..', u'pyinstaller', u'pyinstaller.py')) openlp_main_script = os.path.abspath(os.path.join(branch_path, 'openlp.pyw')) -lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') +if os.path.exists(os.path.join(site_packages, u'PyQt4', u'bin')): + lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') +else: + lrelease_exe = os.path.join(site_packages, u'PyQt4', u'lrelease.exe') i18n_utils = os.path.join(script_path, u'translation_utils.py') win32_icon = os.path.join(branch_path, u'resources', u'images', 'OpenLP.ico') @@ -145,7 +148,7 @@ helpfile_path = os.path.join(manual_build_path, u'htmlhelp') i18n_path = os.path.join(branch_path, u'resources', u'i18n') winres_path = os.path.join(branch_path, u'resources', u'windows') build_path = os.path.join(branch_path, u'build') -dist_path = os.path.join(build_path, u'dist', u'OpenLP') +dist_path = os.path.join(branch_path, u'dist', u'OpenLP') pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', u'lib', u'pptviewlib') @@ -172,7 +175,7 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', - u'-o', build_path, + u'-o', branch_path, #build_path, u'-i', win32_icon, u'-p', branch_path, u'-n', 'OpenLP', From 3e8c91cbd593c47d655c086f85331837e7c7e5e4 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 16:53:05 +0200 Subject: [PATCH 16/25] refactor some code --- openlp/core/lib/imagemanager.py | 45 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 5970efd4f..61be16b91 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -112,17 +112,29 @@ class PriorityQueue(Queue.PriorityQueue): """ Customised ``Queue.PriorityQueue``. """ - def remove(self, item): + def modify_priority(self, image, new_priority): """ - Removes the given ``item`` from the queue. + Modifies the priority of the given ``image``. - ``item`` - The item to remove. This should be a tuple:: + ``image`` + The image to remove. This should be an ``Image`` instance. - ``(Priority, Image)`` + ``new_priority`` + The new priority for the image. """ - if item in self.queue: - self.queue.remove(item) + self.remove(image) + image.priority = new_priority + self.put((image.priority, image)) + + def remove(self, image): + """ + Removes the given ``image`` from the queue. + + ``image`` + The image to remove. This should be an ``Image`` instance. + """ + if (image.priority, image) in self.queue: + self.queue.remove((image.priority, image)) class ImageManager(QtCore.QObject): @@ -168,9 +180,7 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image %s' % name) image = self._cache[name] if image.image is None: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.High - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.High) while image.image is None: log.debug(u'get_image - waiting') time.sleep(0.1) @@ -184,9 +194,7 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image_bytes %s' % name) image = self._cache[name] if image.image_bytes is None: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Urgent - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Urgent) while image.image_bytes is None: log.debug(u'get_image_bytes - waiting') time.sleep(0.1) @@ -198,8 +206,7 @@ class ImageManager(QtCore.QObject): """ log.debug(u'del_image %s' % name) if name in self._cache: - self._conversion_queue.remove( - (self._cache[name].priority, self._cache[name])) + self._conversion_queue.remove(self._cache[name]) del self._cache[name] def add_image(self, name, path): @@ -238,18 +245,14 @@ class ImageManager(QtCore.QObject): # Set the priority to Lowest and stop here as we need to process # more important images first. if image.priority == Priority.Normal: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Lowest - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Lowest) return # For image with high priority we set the priority to Low, as the # byte stream might be needed earlier the byte stream of image with # Normal priority. We stop here as we need to process more important # images first. elif image.priority == Priority.High: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Low - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Low) return # Generate the byte stream for the image. if image.image_bytes is None: From 2b419d8a4eb279ca5a4af5f3f73561539f540c62 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 17:15:48 +0200 Subject: [PATCH 17/25] implementation fix: set priority to low instead of lowerest when the image was requested --- openlp/core/lib/imagemanager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 61be16b91..bde464586 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -184,6 +184,12 @@ class ImageManager(QtCore.QObject): while image.image is None: log.debug(u'get_image - waiting') time.sleep(0.1) + elif image.image_bytes is None: + # Set the priority to Low, because the image was requested but the + # byte stream was not generated yet. However, we only need to do + # this, when the image was generated before it was requested + # (otherwise this is already taken care of). + self._conversion_queue.modify_priority(image, Priority.Low) return image.image def get_image_bytes(self, name): From 1ffd5713b03b67ee35ac4d8e4678b4772b6c5147 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 7 Jul 2011 11:23:55 -0400 Subject: [PATCH 18/25] Modified slide controller to change loop button icons when selecting slide loops --- openlp/core/lib/ui.py | 4 ++++ openlp/core/ui/slidecontroller.py | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index 973c76660..1d7f8ae3f 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -103,6 +103,8 @@ class UiStrings(object): self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. ' 'Do you wish to continue?') self.OpenService = translate('OpenLP.Ui', 'Open service.') + self.PlaySlidesInLoop = translate('OpenLP.Ui','Play Slides in Loop') + self.PlaySlidesToEnd = translate('OpenLP.Ui','Play Slides to End') self.Preview = translate('OpenLP.Ui', 'Preview') self.PrintService = translate('OpenLP.Ui', 'Print Service') self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background') @@ -124,6 +126,8 @@ class UiStrings(object): self.SplitToolTip = translate('OpenLP.Ui', 'Split a slide into two ' 'only if it does not fit on the screen as one slide.') self.StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s')) + self.StopPlaySlidesInLoop = translate('OpenLP.Ui','Stop Play Slides in Loop') + self.StopPlaySlidesToEnd = translate('OpenLP.Ui','Stop Play Slides to End') self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular') self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural') self.Tools = translate('OpenLP.Ui', 'Tools') diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8e2c199a1..57e14179a 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -193,13 +193,11 @@ class SlideController(QtGui.QWidget): self.playSlidesLoop = shortcut_action(self.playSlidesMenu, u'playSlidesLoop', [], self.onPlaySlidesLoop, u':/media/media_time.png', False, UiStrings().LiveToolbar) - self.playSlidesLoop.setText( - translate('OpenLP.SlideController', 'Play Slides in Loop')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesOnce = shortcut_action(self.playSlidesMenu, u'playSlidesOnce', [], self.onPlaySlidesOnce, u':/media/media_time.png', False, UiStrings().LiveToolbar) - self.playSlidesOnce.setText( - translate('OpenLP.SlideController', 'Play Slides to End')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) if QtCore.QSettings().value(self.parent().generalSettingsSection + u'/enable slide loop', QtCore.QVariant(True)).toBool(): self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) @@ -1056,6 +1054,14 @@ class SlideController(QtGui.QWidget): else: self.playSlidesLoop.setChecked(checked) log.debug(u'onPlaySlidesLoop %s' % checked) + if checked: + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop) + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) + else: + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) self.playSlidesOnce.setChecked(False) self.onToggleLoop() @@ -1069,6 +1075,14 @@ class SlideController(QtGui.QWidget): else: self.playSlidesOnce.setChecked(checked) log.debug(u'onPlaySlidesOnce %s' % checked) + if checked: + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd) + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) + else: + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesMenu.setDefaultAction(self.playSlidesOnce) self.playSlidesLoop.setChecked(False) self.onToggleLoop() From f7ab82518bad72f66cc96540b28137412e2988f0 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 17:37:43 +0200 Subject: [PATCH 19/25] doc --- openlp/core/lib/imagemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index bde464586..37d1de79c 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -120,7 +120,7 @@ class PriorityQueue(Queue.PriorityQueue): The image to remove. This should be an ``Image`` instance. ``new_priority`` - The new priority for the image. + The image's new priority. """ self.remove(image) image.priority = new_priority From 37fdcc62a4cafab83919aeabfebe30a92568d911 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 7 Jul 2011 18:03:38 +0100 Subject: [PATCH 20/25] Fix comment --- openlp/plugins/songs/lib/mediaitem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index e9335a684..a2814a1df 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -387,7 +387,8 @@ class SongMediaItem(MediaManagerItem): new_song_id = self.openLyrics.xml_to_song(song_xml) new_song = self.plugin.manager.get_object(Song, new_song_id) new_song.title = u'%s <%s>' % (new_song.title, - translate('SongsPlugin.MediaItem', 'copy')) + translate('SongsPlugin.MediaItem', 'copy', + 'For song cloning')) self.plugin.manager.save_object(new_song) self.onSongListLoad() From 856d44270f1e98d322102d5a738c46263579b548 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 7 Jul 2011 13:38:13 -0400 Subject: [PATCH 21/25] Changed use of Qicon to build_icon in slidecontroller --- openlp/core/ui/slidecontroller.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 57e14179a..0068a7d75 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -32,7 +32,7 @@ from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ - ItemCapabilities, translate + ItemCapabilities, translate, build_icon from openlp.core.lib.ui import UiStrings, shortcut_action from openlp.core.ui import HideMode, MainDisplay, ScreenList from openlp.core.utils.actions import ActionList, CategoryOrder @@ -1055,12 +1055,12 @@ class SlideController(QtGui.QWidget): self.playSlidesLoop.setChecked(checked) log.debug(u'onPlaySlidesLoop %s' % checked) if checked: - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_stop.png')) self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop) - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) else: - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) self.playSlidesOnce.setChecked(False) @@ -1076,12 +1076,12 @@ class SlideController(QtGui.QWidget): self.playSlidesOnce.setChecked(checked) log.debug(u'onPlaySlidesOnce %s' % checked) if checked: - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_stop.png')) self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd) - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) else: - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_time')) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesMenu.setDefaultAction(self.playSlidesOnce) self.playSlidesLoop.setChecked(False) From e6cf76b7b98f6ed966ee880a99cc3a4c6a8e4229 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 7 Jul 2011 20:18:35 +0200 Subject: [PATCH 22/25] Added comments for explanation of some code. Fixed the build directory due to the new way PyInstaller works. --- scripts/windows-builder.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index be1a5fd3e..9c96fe251 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -134,8 +134,12 @@ pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..', u'pyinstaller', u'pyinstaller.py')) openlp_main_script = os.path.abspath(os.path.join(branch_path, 'openlp.pyw')) if os.path.exists(os.path.join(site_packages, u'PyQt4', u'bin')): + # Older versions of the PyQt4 Windows installer put their binaries in the + # "bin" directory lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') else: + # Newer versions of the PyQt4 Windows installer put their binaries in the + # base directory of the installation lrelease_exe = os.path.join(site_packages, u'PyQt4', u'lrelease.exe') i18n_utils = os.path.join(script_path, u'translation_utils.py') win32_icon = os.path.join(branch_path, u'resources', u'images', 'OpenLP.ico') @@ -175,7 +179,7 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', - u'-o', branch_path, #build_path, + u'-o', branch_path, u'-i', win32_icon, u'-p', branch_path, u'-n', 'OpenLP', From ce1abaf3322ffd09a03461b7365a950f0ab6445b Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 07:57:39 +0200 Subject: [PATCH 23/25] Fixed bug #803031: If UTF-8 decoding fails, try the standard Windows codepage. --- openlp/plugins/bibles/lib/http.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 03b094e82..28ceaad68 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -147,7 +147,10 @@ class BGExtract(object): send_error_message(u'download') return None page_source = page.read() - page_source = unicode(page_source, 'utf8') + try: + page_source = unicode(page_source, u'utf8') + except UnicodeDecodeError: + page_source = unicode(page_source, u'cp1251') page_source_temp = re.search(u'.*?'\ u'
', page_source, re.DOTALL) if page_source_temp: From 897f7a7dbbda3b379b8b33ca7f9aa725e63a06ee Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 08:31:34 +0200 Subject: [PATCH 24/25] Fixed bug #794971: Typecast the buffer object to a unicode object. --- openlp/plugins/songs/lib/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 308ff6aa1..409564553 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -267,6 +267,10 @@ def clean_song(manager, song): ``song`` The song object. """ + if not isinstance(song.title, basestring): + song.title = unicode(song.title) + if not isinstance(song.lyrics, basestring): + song.lyrics = unicode(song.lyrics) song.title = song.title.rstrip() if song.title else u'' if song.alternate_title is None: song.alternate_title = u'' From 5581a74034097a98abd8d5c055daba4a1afc123d Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 08:40:50 +0200 Subject: [PATCH 25/25] Changed typecast to rather check for buffer. --- openlp/plugins/songs/lib/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 409564553..e2996ff8f 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -267,9 +267,11 @@ def clean_song(manager, song): ``song`` The song object. """ - if not isinstance(song.title, basestring): + if isinstance(song.title, buffer): song.title = unicode(song.title) - if not isinstance(song.lyrics, basestring): + if isinstance(song.alternate_title, buffer): + song.alternate_title = unicode(song.alternate_title) + if isinstance(song.lyrics, buffer): song.lyrics = unicode(song.lyrics) song.title = song.title.rstrip() if song.title else u'' if song.alternate_title is None: