diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 307ee84df..14de141fc 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -113,6 +113,14 @@ class ImageManager(QtCore.QObject): time.sleep(0.1) return self._cache[name].image_bytes + def del_image(self, name): + """ + Delete the Image from the Cache + """ + log.debug(u'del_image %s' % name) + if name in self._cache: + del self._cache[name] + def add_image(self, name, path): """ Add image to cache if it is not already there @@ -125,6 +133,8 @@ class ImageManager(QtCore.QObject): image.image = resize_image(path, self.width, self.height) self._cache[name] = image + else: + log.debug(u'Image in cache %s:%s' % (name, path)) self._cache_dirty = True # only one thread please if not self._thread_running: diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index 81cde12a0..fc7ba38b8 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -213,6 +213,8 @@ class RenderManager(object): # make big page for theme edit dialog to get line count if self.force_page: verse = verse + verse + verse + else: + self.image_manager.del_image(self.theme_data.theme_name) footer = [] footer.append(u'Arky Arky (Unknown)' ) footer.append(u'Public Domain') diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b9394030a..9b4a035a5 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -44,6 +44,7 @@ class ServiceItemType(object): Image = 2 Command = 3 + class ItemCapabilities(object): """ Provides an enumeration of a serviceitem's capabilities diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 7ccf3fc4c..cc66f21d7 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -138,6 +138,6 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): if re.search(r'[/\\]openlp[/\\]', line): source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line) if u':' in line: - exception = line.split(u'\n')[-1].split(u':')[0] + exception = line.split(u'\n')[-1].split(u':')[0] subject = u'Bug report: %s in %s' % (exception, source) mailto(address=u'bugs@openlp.org', subject=subject, body=body % content) diff --git a/openlp/core/ui/filerenamedialog.py b/openlp/core/ui/filerenamedialog.py index 02eefe7ed..600027940 100644 --- a/openlp/core/ui/filerenamedialog.py +++ b/openlp/core/ui/filerenamedialog.py @@ -30,24 +30,24 @@ from openlp.core.lib import translate class Ui_FileRenameDialog(object): def setupUi(self, FileRenameDialog): - FileRenameDialog.setObjectName("FileRenameDialog") + FileRenameDialog.setObjectName(u'FileRenameDialog') FileRenameDialog.resize(400, 87) self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog) self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25)) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) - self.buttonBox.setObjectName("buttonBox") + self.buttonBox.setObjectName(u'buttonBox') self.widget = QtGui.QWidget(FileRenameDialog) self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35)) - self.widget.setObjectName("widget") + self.widget.setObjectName(u'widget') self.horizontalLayout = QtGui.QHBoxLayout(self.widget) - self.horizontalLayout.setObjectName("horizontalLayout") - self.FileRenameLabel = QtGui.QLabel(self.widget) - self.FileRenameLabel.setObjectName("FileRenameLabel") - self.horizontalLayout.addWidget(self.FileRenameLabel) - self.FileNameEdit = QtGui.QLineEdit(self.widget) - self.FileNameEdit.setObjectName("FileNameEdit") - self.horizontalLayout.addWidget(self.FileNameEdit) + self.horizontalLayout.setObjectName(u'horizontalLayout') + self.fileRenameLabel = QtGui.QLabel(self.widget) + self.fileRenameLabel.setObjectName(u'fileRenameLabel') + self.horizontalLayout.addWidget(self.fileRenameLabel) + self.fileNameEdit = QtGui.QLineEdit(self.widget) + self.fileNameEdit.setObjectName(u'fileNameEdit') + self.horizontalLayout.addWidget(self.fileNameEdit) self.retranslateUi(FileRenameDialog) QtCore.QMetaObject.connectSlotsByName(FileRenameDialog) @@ -55,6 +55,5 @@ class Ui_FileRenameDialog(object): def retranslateUi(self, FileRenameDialog): FileRenameDialog.setWindowTitle(translate('OpenLP.FileRenameForm', 'File Rename')) - self.FileRenameLabel.setText(translate('OpenLP.FileRenameForm', + self.fileRenameLabel.setText(translate('OpenLP.FileRenameForm', 'New File Name:')) - diff --git a/openlp/core/ui/serviceitemeditform.py b/openlp/core/ui/serviceitemeditform.py index f385754f5..e57474315 100644 --- a/openlp/core/ui/serviceitemeditform.py +++ b/openlp/core/ui/serviceitemeditform.py @@ -64,8 +64,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): self.item._raw_frames = [] if self.item.is_image(): for item in self.itemList: - self.item.add_from_image(item[u'path'], item[u'title'], - item[u'image']) + self.item.add_from_image(item[u'path'], item[u'title']) self.item.render() return self.item diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 6c7fb8538..4f75a3ce0 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -466,7 +466,7 @@ class SlideController(QtGui.QWidget): self.Toolbar.actions[u'Stop Loop'].setVisible(False) if item.is_text(): if QtCore.QSettings().value( - self.parent.songsSettingsSection + u'/show songbar', + self.parent.songsSettingsSection + u'/display songbar', QtCore.QVariant(True)).toBool() and len(self.slideList) > 0: self.Toolbar.makeWidgetsVisible([u'Song Menu']) if item.is_capable(ItemCapabilities.AllowsLoop) and \ @@ -560,7 +560,7 @@ class SlideController(QtGui.QWidget): [serviceItem, self.isLive, blanked, slideno]) self.slideList = {} width = self.parent.ControlSplitter.sizes()[self.split] - # Set pointing cursor when we have somthing to point at + # Set pointing cursor when we have something to point at self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor) self.serviceItem = serviceItem self.PreviewListWidget.clear() diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index b091427bf..7ed58e943 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -289,6 +289,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): """ Run the wizard. """ + log.debug(u'Editing theme %s' % self.theme.theme_name) self.updateThemeAllowed = False self.setDefaults() self.updateThemeAllowed = True @@ -444,7 +445,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): def setPreviewTabValues(self): self.setField(u'name', QtCore.QVariant(self.theme.theme_name)) - if len(self.theme.theme_name) > 1: + if len(self.theme.theme_name) > 0: self.themeNameEdit.setEnabled(False) else: self.themeNameEdit.setEnabled(True) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index b6e8c3d7a..0b0d8281d 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -225,10 +225,10 @@ class ThemeManager(QtGui.QWidget): """ item = self.themeListWidget.currentItem() oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString()) - self.fileRenameForm.FileNameEdit.setText(oldThemeName) + self.fileRenameForm.fileNameEdit.setText(oldThemeName) self.saveThemeName = u'' if self.fileRenameForm.exec_(): - newThemeName = unicode(self.fileRenameForm.FileNameEdit.text()) + newThemeName = unicode(self.fileRenameForm.fileNameEdit.text()) oldThemeData = self.getThemeData(oldThemeName) self.deleteTheme(oldThemeName) self.cloneThemeData(oldThemeData, newThemeName) @@ -239,10 +239,10 @@ class ThemeManager(QtGui.QWidget): """ item = self.themeListWidget.currentItem() oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString()) - self.fileRenameForm.FileNameEdit.setText(oldThemeName) + self.fileRenameForm.fileNameEdit.setText(oldThemeName) self.saveThemeName = u'' if self.fileRenameForm.exec_(): - newThemeName = unicode(self.fileRenameForm.FileNameEdit.text()) + newThemeName = unicode(self.fileRenameForm.fileNameEdit.text()) themeData = self.getThemeData(oldThemeName) self.cloneThemeData(themeData, newThemeName) self.loadThemes() diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 087fd7ca5..53e659064 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -43,10 +43,12 @@ class WebDownload(object): Unknown = -1 Crosswalk = 0 BibleGateway = 1 + Bibleserver = 2 Names = { 0: u'Crosswalk', - 1: u'BibleGateway' + 1: u'BibleGateway', + 2: u'Bibleserver' } @classmethod @@ -232,8 +234,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): The index of the combo box. """ self.bibleComboBox.clear() - bibles = [unicode(translate('BiblesPlugin.ImportWizardForm', bible)) for - bible in self.web_bible_list[index].keys()] + bibles = self.web_bible_list[index].keys() bibles.sort() for bible in bibles: self.bibleComboBox.addItem(bible) @@ -338,31 +339,27 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): """ Load the list of Crosswalk and BibleGateway bibles. """ - # Load and store Crosswalk Bibles. + # Load Crosswalk Bibles. filepath = AppLocation.get_directory(AppLocation.PluginsDir) filepath = os.path.join(filepath, u'bibles', u'resources') books_file = None try: self.web_bible_list[WebDownload.Crosswalk] = {} books_file = open( - os.path.join(filepath, u'crosswalkbooks.csv'), 'r') + os.path.join(filepath, u'crosswalkbooks.csv'), 'rb') dialect = csv.Sniffer().sniff(books_file.read(1024)) books_file.seek(0) books_reader = csv.reader(books_file, dialect) for line in books_reader: - ver = line[0] - name = line[1] - if not isinstance(ver, unicode): - ver = unicode(ver, u'utf8') - if not isinstance(name, unicode): - name = unicode(name, u'utf8') + ver = unicode(line[0], u'utf-8') + name = unicode(line[1], u'utf-8') self.web_bible_list[WebDownload.Crosswalk][ver] = name.strip() except IOError: log.exception(u'Crosswalk resources missing') finally: if books_file: books_file.close() - # Load and store BibleGateway Bibles. + # Load BibleGateway Bibles. books_file = None try: self.web_bible_list[WebDownload.BibleGateway] = {} @@ -384,6 +381,26 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): finally: if books_file: books_file.close() + # Load and Bibleserver Bibles. + filepath = AppLocation.get_directory(AppLocation.PluginsDir) + filepath = os.path.join(filepath, u'bibles', u'resources') + books_file = None + try: + self.web_bible_list[WebDownload.Bibleserver] = {} + books_file = open( + os.path.join(filepath, u'bibleserver.csv'), 'rb') + dialect = csv.Sniffer().sniff(books_file.read(1024)) + books_file.seek(0) + books_reader = csv.reader(books_file, dialect) + for line in books_reader: + ver = unicode(line[0], u'utf-8') + name = unicode(line[1], u'utf-8') + self.web_bible_list[WebDownload.Bibleserver][ver] = name.strip() + except IOError, UnicodeError: + log.exception(u'Bibleserver resources missing') + finally: + if books_file: + books_file.close() def getFileName(self, title, editbox): filename = QtGui.QFileDialog.getOpenFileName(self, title, @@ -457,6 +474,9 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): elif download_location == WebDownload.BibleGateway: bible = \ self.web_bible_list[WebDownload.BibleGateway][bible_version] + elif download_location == WebDownload.Bibleserver: + bible = \ + self.web_bible_list[WebDownload.Bibleserver][bible_version] importer = self.manager.import_bible( BibleFormat.WebDownload, name=license_version, diff --git a/openlp/plugins/bibles/forms/bibleimportwizard.py b/openlp/plugins/bibles/forms/bibleimportwizard.py index a0e90f975..a0b2b99b9 100644 --- a/openlp/plugins/bibles/forms/bibleimportwizard.py +++ b/openlp/plugins/bibles/forms/bibleimportwizard.py @@ -208,6 +208,7 @@ class Ui_BibleImportWizard(object): self.locationComboBox.setObjectName(u'LocationComboBox') self.locationComboBox.addItem(u'') self.locationComboBox.addItem(u'') + self.locationComboBox.addItem(u'') self.downloadOptionsLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.locationComboBox) self.bibleLabel = QtGui.QLabel(self.downloadOptionsTab) @@ -388,6 +389,8 @@ class Ui_BibleImportWizard(object): translate('BiblesPlugin.ImportWizardForm', 'Crosswalk')) self.locationComboBox.setItemText(1, translate('BiblesPlugin.ImportWizardForm', 'BibleGateway')) + self.locationComboBox.setItemText(2, + translate('BiblesPlugin.ImportWizardForm', 'Bibleserver')) self.bibleLabel.setText( translate('BiblesPlugin.ImportWizardForm', 'Bible:')) self.webDownloadTabWidget.setTabText( diff --git a/openlp/plugins/bibles/lib/__init__.py b/openlp/plugins/bibles/lib/__init__.py index a6fc03045..7975bfed7 100644 --- a/openlp/plugins/bibles/lib/__init__.py +++ b/openlp/plugins/bibles/lib/__init__.py @@ -32,134 +32,164 @@ import re log = logging.getLogger(__name__) -BIBLE_REFERENCE = re.compile( - r'^([\w ]+?) *([0-9]+)' # Initial book and chapter - r'(?: *[:|v|V] *([0-9]+))?' # Verse for first chapter - r'(?: *- *([0-9]+|end$))?' # Range for verses or chapters - r'(?:(?:,([0-9]+))?' # Second chapter - r' *[,|:|v|V] *([0-9]+|end$)' # More range for verses or chapters - r'(?: *- *([0-9]+|end$))?)?$', # End of second verse range - re.UNICODE) +def get_reference_match(match_type): + local_separator = unicode(u':;;\s*[:vV]\s*;;-;;\s*-\s*;;,;;\s*,\s*;;end' + ).split(u';;') # English + # local_separator = unicode(u',;;\s*,\s*;;-;;\s*-\s*;;.;;\.;;[Ee]nde' + # ).split(u';;') # German + separators = { + u'sep_v_display': local_separator[0], u'sep_v': local_separator[1], + u'sep_r_display': local_separator[2], u'sep_r': local_separator[3], + u'sep_l_display': local_separator[4], u'sep_l': local_separator[5], + u'sep_e': local_separator[6]} -def check_end(match_group): - """ - Check if a regular expression match group contains the text u'end' or - should be converted to an int. - - ``match_group`` - The match group to check. - """ - if match_group == u'end': - return -1 + # verse range match: (:)?(-((:)?|end)?)? + range_string = str(r'(?:(?P[0-9]+)%(sep_v)s)?(?P' + r'[0-9]+)(?P%(sep_r)s(?:(?:(?P[0-9]+)%(sep_v)s)?' + r'(?P[0-9]+)|%(sep_e)s)?)?') % separators + if match_type == u'range': + return re.compile(r'^\s*' + range_string + r'\s*$', re.UNICODE) + elif match_type == u'range_separator': + return re.compile(separators[u'sep_l']) + elif match_type == u'full': + # full reference match: ((,|(?=$)))+ + return re.compile(str(r'^\s*(?!\s)(?P[\d]*[^\d]+)(?(?:' + range_string + r'(?:%(sep_l)s|(?=\s*$)))+)\s*$') + % separators, re.UNICODE) else: - return int(match_group) + return separators[match_type] def parse_reference(reference): """ - This is the über-awesome function that takes a person's typed in string - and converts it to a reference list, a list of references to be queried - from the Bible database files. + This is the next generation über-awesome function that takes a person's + typed in string and converts it to a reference list, a list of references to + be queried from the Bible database files. - The ``BIBLE_REFERENCE`` constant regular expression produces the following - match groups: + This is a user manual like description, how the references are working. - 0. (match string) - This is a special group consisting of the whole string that matched. - 1. ``[\w ]+`` - The book the reference is from. - 2. ``[0-9]+`` - The first (or only) chapter in the reference. - 3. ``None`` or ``[0-9]+`` - ``None``, or the only verse, or the first verse in a verse range or, - the start verse in a chapter range. - 4. ``None`` or ``[0-9]+`` or ``end`` - ``None``, or the end verse of the first verse range, or the end chapter - of a chapter range. - 5. ``None`` or ``[0-9]+`` - ``None``, or the second chapter in multiple (non-ranged) chapters. - 6. ``None`` or ``[0-9]+`` or ``end`` - ``None``, the start of the second verse range. or the end of a chapter - range. - 7. ``None`` or ``[0-9]+`` or ``end`` - ``None``, or the end of the second verse range. + - Each reference starts with the book name. A chapter name is manditory. + ``John 3`` refers to Gospel of John chapter 3 + - A reference range can be given after a range separator. + ``John 3-5`` refers to John chapters 3 to 5 + - Single verses can be addressed after a verse separator + ``John 3:16`` refers to John chapter 3 verse 16 + ``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3 + - After a verse reference all further single values are treat as verse in + the last selected chapter. + ``John 3:16-18`` refers to John chapter 3 verses 16 to 18 + - After a list separator it is possible to refer to additional verses. They + are build analog to the first ones. This way it is possible to define each + number of verse references. It is not possible to refer to verses in + additional books. + ``John 3:16,18`` refers to John chapter 3 verses 16 and 18 + ``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20 + ``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and + chapter 3 verse 1 + - If there is a range separator without further verse declaration the last + refered chapter is addressed until the end. + + ``range_string`` is a regular expression which matches for verse range + declarations: + + 1. ``(?:(?P[0-9]+)%(sep_v)s)?' + It starts with a optional chapter reference ``from_chapter`` followed by + a verse separator. + 2. ``(?P[0-9]+)`` + The verse reference ``from_verse`` is manditory + 3. ``(?P%(sep_r)s(?:`` ... ``|%(sep_e)s)?)?`` + A ``range_to`` declaration is optional. It starts with a range separator + and contains optional a chapter and verse declaration or a end + separator. + 4. ``(?:(?P[0-9]+)%(sep_v)s)?`` + The ``to_chapter`` reference with separator is equivalent to group 1. + 5. ``(?P[0-9]+)`` + The ``to_verse`` reference is equivalent to group 2. + + The full reference is matched against get_reference_match(u'full'). This + regular expression looks like this: + + 1. ``^\s*(?!\s)(?P[\d]*[^\d]+)(?(?:`` + range_string + ``(?:%(sep_l)s|(?=\s*$)))+)\s*$`` + The second group contains all ``ranges``. This can be multiple + declarations of a range_string separated by a list separator. The reference list is a list of tuples, with each tuple structured like this:: - (book, chapter, start_verse, end_verse) + (book, chapter, from_verse, to_verse) ``reference`` The bible reference to parse. Returns None or a reference list. """ - reference = reference.strip() log.debug('parse_reference("%s")', reference) - unified_ref_list = [] - match = BIBLE_REFERENCE.match(reference) + match = get_reference_match(u'full').match(reference) if match: log.debug(u'Matched reference %s' % reference) - book = match.group(1) - chapter = int(match.group(2)) - if match.group(7): - # Two verse ranges - vr1_start = int(match.group(3)) - vr1_end = int(match.group(4)) - unified_ref_list.append((book, chapter, vr1_start, vr1_end)) - vr2_start = int(match.group(6)) - vr2_end = check_end(match.group(7)) - if match.group(5): - # One verse range per chapter - chapter2 = int(match.group(5)) - unified_ref_list.append((book, chapter2, vr2_start, vr2_end)) + book = match.group(u'book') + ranges = match.group(u'ranges') + range_list = get_reference_match(u'range_separator').split(ranges) + ref_list = [] + chapter = None + for this_range in range_list: + range_match = get_reference_match(u'range').match(this_range) + from_chapter = range_match.group(u'from_chapter') + from_verse = range_match.group(u'from_verse') + has_range = range_match.group(u'range_to') + to_chapter = range_match.group(u'to_chapter') + to_verse = range_match.group(u'to_verse') + if from_chapter: + from_chapter = int(from_chapter) + if from_verse: + from_verse = int(from_verse) + if to_chapter: + to_chapter = int(to_chapter) + if to_verse: + to_verse = int(to_verse) + # Fill chapter fields with reasonable values. + if from_chapter: + chapter = from_chapter + elif chapter: + from_chapter = chapter else: - unified_ref_list.append((book, chapter, vr2_start, vr2_end)) - elif match.group(6): - # Chapter range with verses - if match.group(3): - vr1_start = int(match.group(3)) - else: - vr1_start = 1 - if match.group(2) == match.group(4): - vr1_end = int(match.group(6)) - unified_ref_list.append((book, chapter, vr1_start, vr1_end)) - else: - vr1_end = -1 - unified_ref_list.append((book, chapter, vr1_start, vr1_end)) - vr2_end = check_end(match.group(6)) - if int(match.group(4)) > chapter: - for i in range(chapter + 1, int(match.group(4)) + 1): - if i == int(match.group(4)): - unified_ref_list.append((book, i, 1, vr2_end)) - else: - unified_ref_list.append((book, i, 1, -1)) - elif match.group(4): - # Chapter range or chapter and verse range - if match.group(3): - vr1_start = int(match.group(3)) - vr1_end = check_end(match.group(4)) - if vr1_end == -1 or vr1_end > vr1_start: - unified_ref_list.append((book, chapter, vr1_start, vr1_end)) + from_chapter = from_verse + from_verse = None + if to_chapter: + if to_chapter < from_chapter: + continue else: - log.debug(u'Ambiguous reference: %s' % reference) - return None - elif match.group(4) != u'end': - for i in range(chapter, int(match.group(4)) + 1): - unified_ref_list.append((book, i, 1, -1)) + chapter = to_chapter + elif to_verse: + if chapter: + to_chapter = chapter + else: + to_chapter = to_verse + to_verse = None + # Append references to the list + if has_range: + if not from_verse: + from_verse = 1 + if not to_verse: + to_verse = -1 + if to_chapter > from_chapter: + ref_list.append((book, from_chapter, from_verse, -1)) + for i in range(from_chapter + 1, to_chapter - 1): + ref_list.append((book, i, 1, -1)) + ref_list.append((book, to_chapter, 1, to_verse)) + elif to_verse >= from_verse or to_verse == -1: + ref_list.append((book, from_chapter, from_verse, to_verse)) + elif from_verse: + ref_list.append((book, from_chapter, from_verse, from_verse)) else: - log.debug(u'Unsupported reference: %s' % reference) - return None - elif match.group(3): - # Single chapter and verse - verse = int(match.group(3)) - unified_ref_list.append((book, chapter, verse, verse)) - else: - # Single chapter - unified_ref_list.append((book, chapter, -1, -1)) + ref_list.append((book, from_chapter, 1, -1)) + return ref_list else: log.debug(u'Invalid reference: %s' % reference) return None - return unified_ref_list class SearchResults(object): diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index dade3ad44..218f7212e 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -240,6 +240,66 @@ class BGExtract(object): return SearchResults(bookname, chapter, verse_list) +class BSExtract(object): + """ + Extract verses from Bibleserver.com + """ + def __init__(self,proxyurl=None): + log.debug(u'init %s', proxyurl) + self.proxyurl = proxyurl + + def get_bible_chapter(self, version, bookname, chapter): + """ + Access and decode bibles via Bibleserver mobile website + + ``version`` + The version of the bible like NIV for New International Version + + ``bookname`` + Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung + + ``chapter`` + Chapter number + """ + log.debug(u'get_bible_chapter %s,%s,%s', version, bookname, chapter) + chapter_url = u'http://m.bibleserver.com/text/%s/%s%s' % \ + (version, bookname, chapter) + + log.debug(u'URL: %s', chapter_url) + page = None + try: + page = urllib2.urlopen(chapter_url) + Receiver.send_message(u'openlp_process_events') + except urllib2.URLError: + log.exception(u'The web bible page could not be downloaded.') + finally: + if not page: + return None + soup = None + try: + soup = BeautifulSoup(page) + except HTMLParseError: + log.exception(u'BeautifulSoup could not parse the bible page.') + finally: + if not soup: + return None + Receiver.send_message(u'openlp_process_events') + try: + content = soup.find(u'div', u'content').find(u'div').findAll(u'div') + except: + log.exception(u'No verses found.') + finally: + if not content: + return None + verse_number = re.compile(r'v(\d{2})(\d{3})(\d{3}) verse') + verses = {} + for verse in content: + Receiver.send_message(u'openlp_process_events') + versenumber = int(verse_number.sub(r'\3', verse[u'class'])) + verses[versenumber] = verse.contents[1].rstrip(u'\n') + return SearchResults(bookname, chapter, verses) + + class CWExtract(object): """ Extract verses from CrossWalk/BibleStudyTools @@ -350,7 +410,7 @@ class HTTPBible(BibleDB): Run the import. This method overrides the parent class method. Returns ``True`` on success, ``False`` on failure. """ - self.wizard.ImportProgressBar.setMaximum(2) + self.wizard.importProgressBar.setMaximum(2) self.wizard.incrementProgressBar('Registering bible...') self.create_meta(u'download source', self.download_source) self.create_meta(u'download name', self.download_name) @@ -426,8 +486,10 @@ class HTTPBible(BibleDB): log.debug(u'source = %s', self.download_source) if self.download_source.lower() == u'crosswalk': ev = CWExtract(self.proxy_server) - else: + elif self.download_source.lower() == u'biblegateway': ev = BGExtract(self.proxy_server) + elif self.download_source.lower() == u'bibleserver': + ev = BSExtract(self.proxy_server) return ev.get_bible_chapter(self.download_name, book, chapter) def get_books(self): diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index a220b160d..93f301713 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -112,6 +112,7 @@ class BibleFormat(object): def get_availability(format): return BibleFormat._format_availability.get(format, True) + class BibleManager(object): """ The Bible manager which holds and manages all the Bibles. @@ -311,7 +312,7 @@ class BibleManager(object): 'Scripture Reference Error'), translate('BiblesPlugin.BibleManager', 'You did not enter a ' 'search keyword.\nYou can separate different keywords by a ' - 'space to search for all of your keywords and you can seperate ' + 'space to search for all of your keywords and you can separate ' 'them by a comma to search for one of them.')) return None @@ -356,3 +357,4 @@ class BibleManager(object): BibleFormat.set_availability(BibleFormat.OpenLP1, has_openlp1) __all__ = [u'BibleFormat'] + diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 339dac41f..8fafd0f97 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \ ItemCapabilities, translate from openlp.plugins.bibles.forms import BibleImportForm +from openlp.plugins.bibles.lib import get_reference_match log = logging.getLogger(__name__) @@ -553,12 +554,15 @@ class BibleMediaItem(MediaManagerItem): bible = unicode(self.AdvancedVersionComboBox.currentText()) second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText()) book = unicode(self.AdvancedBookComboBox.currentText()) - chapter_from = int(self.AdvancedFromChapter.currentText()) - chapter_to = int(self.AdvancedToChapter.currentText()) - verse_from = int(self.AdvancedFromVerse.currentText()) - verse_to = int(self.AdvancedToVerse.currentText()) - versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from, - chapter_to, verse_to) + chapter_from = self.AdvancedFromChapter.currentText() + chapter_to = self.AdvancedToChapter.currentText() + verse_from = self.AdvancedFromVerse.currentText() + verse_to = self.AdvancedToVerse.currentText() + verse_separator = get_reference_match(u'sep_v_display') + range_separator = get_reference_match(u'sep_r_display') + verse_range = chapter_from + verse_separator + verse_from + \ + range_separator + chapter_to + verse_separator + verse_to + versetext = u'%s %s' % (book, verse_range) self.search_results = self.parent.manager.get_verses(bible, versetext) if second_bible: self.second_search_results = self.parent.manager.get_verses( @@ -709,7 +713,7 @@ class BibleMediaItem(MediaManagerItem): obj = reference[QtCore.QString(key)] if isinstance(obj, QtCore.QVariant): obj = obj.toPyObject() - return unicode(obj) + return unicode(obj).strip() def generateSlideData(self, service_item, item=None, xmlVersion=False): """ @@ -739,7 +743,8 @@ class BibleMediaItem(MediaManagerItem): second_bible = self._decodeQtObject(bitem, 'second_bible') second_version = self._decodeQtObject(bitem, 'second_version') second_copyright = self._decodeQtObject(bitem, 'second_copyright') - second_permissions = self._decodeQtObject(bitem, 'second_permissions') + second_permissions = \ + self._decodeQtObject(bitem, 'second_permissions') second_text = self._decodeQtObject(bitem, 'second_text') verse_text = self.formatVerse(old_chapter, chapter, verse) footer = u'%s (%s %s %s)' % (book, version, copyright, permissions) @@ -750,21 +755,21 @@ class BibleMediaItem(MediaManagerItem): second_copyright, second_permissions) if footer not in raw_footer: raw_footer.append(footer) - bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text, - second_text) + bible_text = u'%s\u00a0%s\n\n%s\u00a0%s' % (verse_text, text, + verse_text, second_text) raw_slides.append(bible_text) bible_text = u'' # If we are 'Verse Per Slide' then create a new slide. elif self.parent.settings_tab.layout_style == 0: - bible_text = u'%s %s' % (verse_text, text) + bible_text = u'%s\u00a0%s' % (verse_text, text) raw_slides.append(bible_text) bible_text = u'' # If we are 'Verse Per Line' then force a new line. elif self.parent.settings_tab.layout_style == 1: - bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) + bible_text = u'%s %s\u00a0%s\n' % (bible_text, verse_text, text) # We have to be 'Continuous'. else: - bible_text = u'%s %s %s\n' % (bible_text, verse_text, text) + bible_text = u'%s %s\u00a0%s\n' % (bible_text, verse_text, text) if first_item: start_item = item first_item = False @@ -816,36 +821,31 @@ class BibleMediaItem(MediaManagerItem): ``old_item`` The last item of a range. """ + verse_separator = get_reference_match(u'sep_v_display') + range_separator = get_reference_match(u'sep_r_display') old_bitem = self.listView.item(old_item.row()) - old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) - old_verse = int(self._decodeQtObject(old_bitem, 'verse')) + old_chapter = self._decodeQtObject(old_bitem, 'chapter') + old_verse = self._decodeQtObject(old_bitem, 'verse') start_bitem = self.listView.item(start_item.row()) start_book = self._decodeQtObject(start_bitem, 'book') - start_chapter = int(self._decodeQtObject(start_bitem, 'chapter')) - start_verse = int(self._decodeQtObject(start_bitem, 'verse')) + start_chapter = self._decodeQtObject(start_bitem, 'chapter') + start_verse = self._decodeQtObject(start_bitem, 'verse') start_bible = self._decodeQtObject(start_bitem, 'bible') start_second_bible = self._decodeQtObject(start_bitem, 'second_bible') if start_second_bible: - if start_verse == old_verse and start_chapter == old_chapter: - title = u'%s %s:%s (%s, %s)' % (start_book, start_chapter, - start_verse, start_bible, start_second_bible) - elif start_chapter == old_chapter: - title = u'%s %s:%s-%s (%s, %s)' % (start_book, start_chapter, - start_verse, old_verse, start_bible, start_second_bible) - else: - title = u'%s %s:%s-%s:%s (%s, %s)' % (start_book, start_chapter, - start_verse, old_chapter, old_verse, start_bible, - start_second_bible) + bibles = u'%s, %s' % (start_bible, start_second_bible) else: - if start_verse == old_verse and start_chapter == old_chapter: - title = u'%s %s:%s (%s)' % (start_book, start_chapter, - start_verse, start_bible) - elif start_chapter == old_chapter: - title = u'%s %s:%s-%s (%s)' % (start_book, start_chapter, - start_verse, old_verse, start_bible) + bibles = start_bible + if start_chapter == old_chapter: + if start_verse == old_verse: + verse_range = start_chapter + verse_separator + start_verse else: - title = u'%s %s:%s-%s:%s (%s)' % (start_book, start_chapter, - start_verse, old_chapter, old_verse, start_bible) + verse_range = start_chapter + verse_separator + start_verse + \ + range_separator + old_verse + else: + verse_range = start_chapter + verse_separator + start_verse + \ + range_separator + old_chapter + verse_separator + old_verse + title = u'%s %s (%s)' % (start_book, verse_range, bibles) return title def checkTitle(self, item, old_item): @@ -907,9 +907,10 @@ class BibleMediaItem(MediaManagerItem): ``verse`` The verse number (int). """ + verse_separator = get_reference_match(u'sep_v_display') if not self.parent.settings_tab.show_new_chapters or \ old_chapter != chapter: - verse_text = u'%s:%s' % (chapter, verse) + verse_text = unicode(chapter) + verse_separator + unicode(verse) else: verse_text = u'%s' % verse if self.parent.settings_tab.display_style == 1: diff --git a/openlp/plugins/bibles/lib/openlp1.py b/openlp/plugins/bibles/lib/openlp1.py old mode 100755 new mode 100644 diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index 53a6f152c..f39a4ab0f 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -134,9 +134,9 @@ class OSISBible(BibleDB): testament) if last_chapter == 0: if book == u'Gen': - self.wizard.ImportProgressBar.setMaximum(1188) + self.wizard.importProgressBar.setMaximum(1188) else: - self.wizard.ImportProgressBar.setMaximum(260) + self.wizard.importProgressBar.setMaximum(260) if last_chapter != chapter: if last_chapter != 0: self.session.commit() diff --git a/openlp/plugins/bibles/resources/biblegateway.csv b/openlp/plugins/bibles/resources/biblegateway.csv index deca46d7c..ad8052704 100644 --- a/openlp/plugins/bibles/resources/biblegateway.csv +++ b/openlp/plugins/bibles/resources/biblegateway.csv @@ -1,80 +1,81 @@ +João Ferreira de Almeida Atualizada,AA +التفسير التطبيقى للكتاب المقدس,ALAB +Shqip,ALB +Amplified Bible,AMP Amuzgo de Guerrero,AMU -Arabic Life Application Bible,ALAB -Bulgarian Bible,BULG -1940 Bulgarian Bible,BG1940 -Chinanteco de Comaltepec,CCO -Cakchiquel Occidental,CKW -Haitian Creole Version,HCV -Slovo na cestu,SNC -Dette er Biblen pÃ¥ dansk,DN1933 -Hoffnung für Alle,HOF -Luther Bibel 1545,LUTH1545 -New International Version,NIV -New American Standard Bible,NASB -The Message,MSG -Amplified Bible,AMP -New Living Translation,NLT -King James Version,KJV -English Standard Version,ESV -Contemporary English Version,CEV -New King James Version,NKJV -New Century Version,NCV -21st Century King James Version,KJ21 -American Standard Version,ASV -Young's Literal Translation,YLT -Darby Translation,DARBY -Holman Christian Standard Bible,HCSB -New International Reader's Version,NIRV -Wycliffe New Testament,WYC -Worldwide English (New Testament),WE -New International Version - UK,NIVUK -Today's New International Version,TNIV +American Standard Version,ASV +La Bible du Semeur,BDS +Български 1940,BG1940 +Български,BULG +Chinanteco de Comaltepec,CCO +Contemporary English Version,CEV +Cakchiquel Occidental,CKW +Hrvatski,CRO +Castilian,CST +聖經和合本 (简体中文),CUVS +聖經和合本 (繁体中文),CUV +Darby Translation,DARBY +Dette er Biblen på dansk,DN1933 +Det Norsk Bibelselskap 1930,DNB1930 +English Standard Version,ESV +GOD’S WORD Translation,GW +Holman Christian Standard Bible,HCSB +Kreyòl ayisyen bib,HCV +Hiligaynon Bible,HLGN +Hoffnung für Alle,HOF +Het Boek,HTB +Icelandic Bible,ICELAND +Jacalteco – Oriental,JAC +Károlyi-biblia,KAR +Kekchi,KEK +21st Century King James Version,KJ21 +King James Version,KJV +La Biblia de las Américas,LBLA +Levande Bibeln,LB +La Parola è Vita,LM +La Nuova Diodati,LND +Louis Segond,LSG +Luther Bibel 1545,LUTH1545 +Māori Bible,MAORI +Македонски Новиот Завет,MNT +The Message,MSG +Mam de Comitancillo Central,MVC +Mam de Todos Santos Cuchumatán,MVJ +New American Standard Bible,NASB +New Century Version,NCV +Náhuatl de Guerrero,NGU +New International Reader's Version,NIRV +New International Version 1984,NIV1984 +New International Version 2010,NIV +New International Version - UK,NIVUK +New King James Version,NKJV +New Living Translation,NLT +Nádej pre kazdého,NPK +Nueva Versión Internacional,NVI +O Livro,OL +Quiché – Centro Occidental,QUT +Reimer 2001,REIMER +Română Cornilescu,RMNN +Новый перевод на русский язык,RUSV +Reina-Valera Antigua,RVA Reina-Valera 1960,RVR1960 -Nueva Versión Internacional,NVI -Reina-Valera 1995,RVR1995 -Castilian,CST -Reina-Valera Antigua,RVA -Biblia en Lenguaje Sencillo,BLS -La Biblia de las Américas,LBLA -Louis Segond,LSG -La Bible du Semeur,BDS -1881 Westcott-Hort New Testament,WHNU -1550 Stephanus New Testament,TR1550 -1894 Scrivener New Testament,TR1894 -The Westminster Leningrad Codex,WLC -Hiligaynon Bible,HLGN -Croatian Bible,CRO -Hungarian Károli,KAR -Icelandic Bible,ICELAND -La Nuova Diodati,LND -La Parola è Vita,LM -Jacalteco, Oriental,JAC -Kekchi,KEK -Korean Bible,KOREAN -Maori Bible,MAORI -Macedonian New Testament,MNT -Mam, Central,MVC -Mam de Todos Santos Chuchumatán,MVJ -Reimer 2001,REIMER -Náhuatl de Guerrero,NGU -Het Boek,HTB -Det Norsk Bibelselskap 1930,DNB1930 -Levande Bibeln,LB -O Livro,OL -João Ferreira de Almeida Atualizada,AA -Quiché, Centro Occidental,QUT -Romanian,RMNN -Romanian,TLCR -Russian Synodal Version,RUSV -Slovo Zhizny,SZ -Nádej pre kazdého,NPK -Albanian Bible,ALB -Levande Bibeln,SVL -Svenska 1917,SV1917 -Swahili New Testament,SNT -Ang Salita ng Diyos,SND -Ukrainian Bible,UKR -Uspanteco,USP -1934 Vietnamese Bible,VIET -Chinese Union Version (Simplified),CUVS -Chinese Union Version (Traditional),CUV \ No newline at end of file +Reina-Valera 1995,RVR1995 +Slovo na cestu,SNC +Ang Salita ng Diyos,SND +Swahili New Testament,SNT +Svenska 1917,SV1917 +Levande Bibeln,SVL +Создать страницу,SZ +Traducción en lenguaje actual,TLA +New Romanian Translation,TLCR +Today’s New International Version 2005,TNIV +Textus Receptus Stephanus 1550,TR1550 +Textus Receptus Scrivener 1894,TR1894 +Українська Біблія. Переклад Івана Огієнка,UKR +Uspanteco,USP +Kinh Thánh tiếng Việt 1934,VIET +Worldwide English (New Testament),WE +Codex Vaticanus Westcott-Hort 1881,WHNU +Westminster Leningrad Codex,WLC +Wycliffe New Testament,WYC +Young's Literal Translation,YLT diff --git a/openlp/plugins/bibles/resources/bibleserver.csv b/openlp/plugins/bibles/resources/bibleserver.csv new file mode 100644 index 000000000..c0d109f97 --- /dev/null +++ b/openlp/plugins/bibles/resources/bibleserver.csv @@ -0,0 +1,39 @@ +عربي, ARA +Bible – překlad 21. století, B21 +Bible du Semeur, BDS +Българската Библия, BLG +Český ekumenický překlad, CEP +Hrvatski, CRO +Священное Писание, CRS +Version La Biblia al Dia, CST +中文和合本(简体), CUVS +Bibelen på hverdagsdansk, DK +Revidierte Elberfelder, ELB +Einheitsübersetzung, EU +Gute Nachricht Bibel, GNB +Hoffnung für alle, HFA +Hungarian, HUN +Het Boek, HTB +La Parola è Vita, ITA +IBS-fordítás (Új Károli), KAR +King James Version, KJV +Luther 1984, LUT +Septuaginta, LXX +Neue Genfer Übersetzung, NGÜ +New International Readers Version, NIRV +New International Version, NIV +Neues Leben, NL +En Levende Bok (NOR), NOR +Nádej pre kazdého, NPK +Noua traducere în limba românã, NTR +Nueva Versión Internacional, NVI +הברית הישנה, OT +Słowo Życia, POL +O Livro, PRT +Новый перевод на русский язык, RUS +Slovo na cestu, SNC +Schlachter 2000, SLT +En Levande Bok (SWE), SVL +Today's New International Version, TNIV +Türkçe, TR +Biblia Vulgata, VUL diff --git a/openlp/plugins/bibles/resources/crosswalkbooks.csv b/openlp/plugins/bibles/resources/crosswalkbooks.csv index 0b6de47de..7957bfdc8 100644 --- a/openlp/plugins/bibles/resources/crosswalkbooks.csv +++ b/openlp/plugins/bibles/resources/crosswalkbooks.csv @@ -24,4 +24,4 @@ New International Reader's Version,nrv The Darby Translation,dby The Webster Bible,wbt The Latin Vulgate,vul -Weymouth New Testament,wnt \ No newline at end of file +Weymouth New Testament,wnt diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index c5281574b..359cc9eae 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -224,27 +224,24 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): ``edit_all`` Indicates if all slides or only one slide has been edited. """ - if len(slides) == 1: - self.slideListView.currentItem().setText(slides[0]) + if edit_all: + self.slideListView.clear() + for slide in slides: + self.slideListView.addItem(slide) else: - if edit_all: - self.slideListView.clear() - for slide in slides: - self.slideListView.addItem(slide) - else: - old_slides = [] - old_row = self.slideListView.currentRow() - # Create a list with all (old/unedited) slides. - old_slides = [self.slideListView.item(row).text() for row in \ - range(0, self.slideListView.count())] - self.slideListView.clear() - old_slides.pop(old_row) - # Insert all slides to make the old_slides list complete. - for slide in slides: - old_slides.insert(old_row, slide) - for slide in old_slides: - self.slideListView.addItem(slide) - self.slideListView.repaint() + old_slides = [] + old_row = self.slideListView.currentRow() + # Create a list with all (old/unedited) slides. + old_slides = [self.slideListView.item(row).text() for row in \ + range(0, self.slideListView.count())] + self.slideListView.clear() + old_slides.pop(old_row) + # Insert all slides to make the old_slides list complete. + for slide in slides: + old_slides.insert(old_row, slide) + for slide in old_slides: + self.slideListView.addItem(slide) + self.slideListView.repaint() def onDeleteButtonPressed(self): self.slideListView.takeItem(self.slideListView.currentRow()) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 4f1e9378e..0774787f5 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \ context_menu_action, ItemCapabilities, SettingsManager, translate, \ - check_item_selected + check_item_selected, Receiver from openlp.core.utils import AppLocation, get_images_filter log = logging.getLogger(__name__) @@ -139,6 +139,8 @@ class ImageMediaItem(MediaManagerItem): self.settingsSection, self.getFileList()) def loadList(self, list): + self.listView.setCursor(QtCore.Qt.BusyCursor) + Receiver.send_message(u'openlp_process_events') for file in list: filename = os.path.split(unicode(file))[1] thumb = os.path.join(self.servicePath, filename) @@ -153,6 +155,8 @@ class ImageMediaItem(MediaManagerItem): item_name.setIcon(icon) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) self.listView.addItem(item_name) + self.listView.setCursor(QtCore.Qt.ArrowCursor) + Receiver.send_message(u'openlp_process_events') def generateSlideData(self, service_item, item=None, xmlVersion=False): items = self.listView.selectedIndexes() diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index b7f4a3f0b..21958d403 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -108,6 +108,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.TopicsListView.setSortingEnabled(False) self.TopicsListView.setAlternatingRowColors(True) self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE) + self.whitespace = re.compile(r'\W+', re.UNICODE) def initialise(self): self.VerseEditButton.setEnabled(False) @@ -546,14 +547,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): if self.AuthorsListView.count() == 0: self.SongTabWidget.setCurrentIndex(1) self.AuthorsListView.setFocus() - answer = QtGui.QMessageBox.warning(self, + QtGui.QMessageBox.critical(self, translate('SongsPlugin.EditSongForm', 'Warning'), translate('SongsPlugin.EditSongForm', - 'You have not added any authors for this song. Do you ' - 'want to add an author now?'), - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - if answer == QtGui.QMessageBox.Yes: - return False + 'You need to have an author for this song.')) + return False if self.song.verse_order: order = [] order_names = self.song.verse_order.split() @@ -738,7 +736,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): verseId = unicode(item.data(QtCore.Qt.UserRole).toString()) bits = verseId.split(u':') sxml.add_verse_to_lyrics(bits[0], bits[1], unicode(item.text())) - text = text + re.sub(r'\W+', u' ', + text = text + whitespace.sub(u' ', unicode(self.VerseListWidget.item(i, 0).text())) + u' ' if (bits[1] > u'1') and (bits[0][0] not in multiple): multiple.append(bits[0][0]) diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index d954bfb1f..8f5f04194 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -29,7 +29,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import VerseType, translate from editversedialog import Ui_EditVerseDialog @@ -131,6 +131,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): def setVerse(self, text, single=False, tag=u'%s:1' % VerseType.to_string(VerseType.Verse)): + self.hasSingleVerse = single if single: verse_type, verse_number = tag.split(u':') verse_type_index = VerseType.from_string(verse_type) @@ -159,3 +160,16 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): text = u'---[%s:1]---\n%s' % (VerseType.to_string(VerseType.Verse), text) return text + + def accept(self): + if self.hasSingleVerse: + value = unicode(self.getVerse()[0]) + else: + value = self.getVerse()[0].split(u'\n')[1] + if len(value) == 0: + QtGui.QMessageBox.critical(self, + translate('SongsPlugin.EditSongForm', 'Error'), + translate('SongsPlugin.EditSongForm', + 'You need to type some text in to the verse.')) + return False + QtGui.QDialog.accept(self) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index dc8310e9d..e42cb7fa3 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -44,6 +44,7 @@ class SongListView(BaseListWithDnD): self.PluginName = u'Songs' BaseListWithDnD.__init__(self, parent) + class SongMediaItem(MediaManagerItem): """ This is the custom media manager item for Songs. @@ -392,7 +393,7 @@ class SongMediaItem(MediaManagerItem): author_audit.append(unicode(author.display_name)) raw_footer.append(song.title) raw_footer.append(author_list) - raw_footer.append(song.copyright ) + raw_footer.append(song.copyright) raw_footer.append(unicode( translate('SongsPlugin.MediaItem', 'CCLI License: ') + QtCore.QSettings().value(u'general/ccli number', @@ -417,27 +418,37 @@ class SongMediaItem(MediaManagerItem): item.data_string[u'title'].split(u'@')[0].lower() , Song.search_title.asc()) author_list = item.data_string[u'authors'].split(u', ') + # The service item always has an author (at least it has u'' as + # author). However, songs saved in the database do not have to have + # an author. + if u'' in author_list: + author_list.remove(u'') editId = 0 uuid = item._uuid + add_song = True if search_results: for song in search_results: - count = 0 - for author in song.authors: - if author.display_name in author_list: - count += 1 - # All Authors the same - if count == len(author_list): - editId = song.id + same_authors = True + # If the author counts are different, we do not have to do + # any further checking. This is also important when a song + # does not have any author (because we can not loop over an + # empty list). + if len(song.authors) == len(author_list): + for author in song.authors: + if author.display_name not in author_list: + same_authors = False else: - # Authors different - if self.addSongFromService: - editId = self.openLyrics. \ - xml_to_song(item.xml_version) - else: - # Title does not match + same_authors = False + # All authors are the same, so we can stop here and the song + # does not have to be saved. + if same_authors: + add_song = False + editId = song.id + break + if add_song: if self.addSongFromService: editId = self.openLyrics.xml_to_song(item.xml_version) - # Update service with correct song id + # Update service with correct song id. if editId != 0: Receiver.send_message(u'service_item_update', u'%s:%s' %(editId, uuid)) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index ea36d55b5..f305b90c7 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -247,7 +247,7 @@ class SongImport(QtCore.QObject): """ Extracts alphanumeric words for searchable fields """ - return re.sub(r'\W+', u' ', text) + return re.sub(r'\W+', u' ', text, re.UNICODE) def finish(self): """ diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index d26919d79..9d98737dc 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -297,6 +297,8 @@ class OpenLyricsParser(object): song_xml = objectify.fromstring(xml) properties = song_xml.properties song.copyright = unicode(properties.copyright.text) + if song.copyright == u'None': + song.copyright = u'' song.verse_order = unicode(properties.verseOrder.text) if song.verse_order == u'None': song.verse_order = u'' @@ -357,7 +359,7 @@ class OpenLyricsParser(object): def _add_text_to_element(self, tag, parent, text=None, label=None): if label: - element = etree.Element(tag, name = unicode(label)) + element = etree.Element(tag, name=unicode(label)) else: element = etree.Element(tag) if text: diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 32336c507..b55b05988 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager -from openlp.plugins.songs.lib import SongMediaItem, SongsTab +from openlp.plugins.songs.lib import SongMediaItem, SongsTab, SongXMLParser from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.importer import SongFormat @@ -150,9 +150,13 @@ class SongsPlugin(Plugin): song.title = u'' if song.alternate_title is None: song.alternate_title = u'' - song.search_title = self.whitespace.sub(u' ', \ - song.title.lower()) + u' ' + \ - self.whitespace.sub(u' ', song.alternate_title.lower()) + song.search_title = self.whitespace.sub(u' ', song.title.lower() + \ + u' ' + song.alternate_title.lower()) + lyrics = u'' + verses = SongXMLParser(song.lyrics).get_verses() + for verse in verses: + lyrics = lyrics + self.whitespace.sub(u' ', verse[1]) + u' ' + song.search_lyrics = lyrics.lower() progressDialog.setValue(counter) self.manager.save_objects(songs) counter += 1