From 12a0b8b750aca7827dc5135479480d35e1edf896 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 9 Feb 2015 20:49:24 +0000 Subject: [PATCH 1/7] Add default shortcut bindings for preview next/prev, and make the appear in the shortcut edit dialog. Fixes bug 1412570. Fixes: https://launchpad.net/bugs/1412570 --- openlp/core/common/settings.py | 4 ++-- openlp/core/common/uistrings.py | 1 + openlp/core/ui/slidecontroller.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index f30aeb0ee..8d5abb7bc 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -216,7 +216,7 @@ class Settings(QtCore.QSettings): 'shortcuts/moveDown': [QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextTrackItem': [], 'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], - 'shortcuts/nextItem_preview': [], + 'shortcuts/nextItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextService': [QtGui.QKeySequence(QtCore.Qt.Key_Right)], 'shortcuts/newService': [], 'shortcuts/offlineHelpItem': [], @@ -230,7 +230,7 @@ class Settings(QtCore.QSettings): 'shortcuts/playSlidesLoop': [], 'shortcuts/playSlidesOnce': [], 'shortcuts/previousService': [QtGui.QKeySequence(QtCore.Qt.Key_Left)], - 'shortcuts/previousItem_preview': [], + 'shortcuts/previousItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Up), QtGui.QKeySequence(QtCore.Qt.Key_PageUp)], 'shortcuts/printServiceItem': [QtGui.QKeySequence('Ctrl+P')], 'shortcuts/songExportItem': [], 'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)], diff --git a/openlp/core/common/uistrings.py b/openlp/core/common/uistrings.py index a279bf573..bebf4add0 100644 --- a/openlp/core/common/uistrings.py +++ b/openlp/core/common/uistrings.py @@ -115,6 +115,7 @@ class UiStrings(object): 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.PreviewToolbar = translate('OpenLP.Ui', 'Preview Toolbar') self.PrintService = translate('OpenLP.Ui', 'Print Service') self.Projector = translate('OpenLP.Ui', 'Projector', 'Singular') self.Projectors = translate('OpenLP.Ui', 'Projectors', 'Plural') diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 5696296e8..94ece4693 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -1418,7 +1418,7 @@ class PreviewController(RegistryMixin, OpenLPMixin, SlideController): super(PreviewController, self).__init__(parent) self.split = 0 self.type_prefix = 'preview' - self.category = None + self.category = 'Preview Toolbar' def bootstrap_post_set_up(self): """ From 5795e386d48d835438054f19a3aced06455f66bc Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 12 Feb 2015 21:09:25 +0000 Subject: [PATCH 2/7] Make csv-bible import work with python3. Fixes bug 1421136. Fixes: https://launchpad.net/bugs/1421136 --- openlp/plugins/bibles/lib/csvbible.py | 31 ++++++++++----------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index e193c6f95..ffe54efa5 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -73,7 +73,7 @@ class CSVBible(BibleDB): """ log.info(self.__class__.__name__) BibleDB.__init__(self, parent, **kwargs) - self.books_file = kwargs['books_file'] + self.books_file = kwargs['booksfile'] self.verses_file = kwargs['versefile'] def do_import(self, bible_name=None): @@ -93,23 +93,20 @@ class CSVBible(BibleDB): # Populate the Tables try: details = get_file_encoding(self.books_file) - books_file = open(self.books_file, 'r') - if not books_file.read(3) == '\xEF\xBB\xBF': - # no BOM was found - books_file.seek(0) + books_file = open(self.books_file, 'r', encoding=details['encoding']) books_reader = csv.reader(books_file, delimiter=',', quotechar='"') for line in books_reader: if self.stop_import_flag: break - self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') % - str(line[2], details['encoding'])) - book_ref_id = self.get_book_ref_id_by_name(str(line[2], details['encoding']), 67, language_id) + self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') + % line[2]) + book_ref_id = self.get_book_ref_id_by_name(line[2], 67, language_id) if not book_ref_id: log.error('Importing books from "%s" failed' % self.books_file) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) - self.create_book(str(line[2], details['encoding']), book_ref_id, book_details['testament_id']) - book_list[int(line[0])] = str(line[2], details['encoding']) + self.create_book(line[2], book_ref_id, book_details['testament_id']) + book_list[int(line[0])] = line[2] self.application.process_events() except (IOError, IndexError): log.exception('Loading books from file failed') @@ -125,10 +122,7 @@ class CSVBible(BibleDB): try: book_ptr = None details = get_file_encoding(self.verses_file) - verse_file = open(self.verses_file, 'rb') - if not verse_file.read(3) == '\xEF\xBB\xBF': - # no BOM was found - verse_file.seek(0) + verse_file = open(self.verses_file, 'r', encoding=details['encoding']) verse_reader = csv.reader(verse_file, delimiter=',', quotechar='"') for line in verse_reader: if self.stop_import_flag: @@ -136,7 +130,7 @@ class CSVBible(BibleDB): try: line_book = book_list[int(line[0])] except ValueError: - line_book = str(line[0], details['encoding']) + line_book = line[0] if book_ptr != line_book: book = self.get_book(line_book) book_ptr = book.name @@ -144,10 +138,7 @@ class CSVBible(BibleDB): translate('BiblesPlugin.CSVBible', 'Importing verses from %s...' % book.name, 'Importing verses from ...')) self.session.commit() - try: - verse_text = str(line[3], details['encoding']) - except UnicodeError: - verse_text = str(line[3], 'cp1252') + verse_text = line[3] self.create_verse(book.id, line[1], line[2], verse_text) self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing verses... done.')) self.application.process_events() @@ -170,7 +161,7 @@ def get_file_encoding(filename): """ detect_file = None try: - detect_file = open(filename, 'r') + detect_file = open(filename, 'rb') details = chardet.detect(detect_file.read(1024)) except IOError: log.exception('Error detecting file encoding') From 340a766bba485aeea1296fcc6ddab953910e518a Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 13 Feb 2015 20:10:53 +0000 Subject: [PATCH 3/7] Change ConnectionException to ConnectionError. Fixes bug 1421561 Fixes: https://launchpad.net/bugs/1421561 --- openlp/core/ui/firsttimeform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 9c3b7bf09..3f3403d19 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -436,7 +436,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) meta = site.info() return int(meta.get("Content-Length")) - except ConnectionException: + except ConnectionError: if retries > CONNECTION_RETRIES: raise else: From c3dc1e1a780a21ac5626bc5c080c140c679fa45a Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 13 Feb 2015 20:19:05 +0000 Subject: [PATCH 4/7] If no copyright info is given for bible, don't print it. Fixes bug 1420785. Fixes: https://launchpad.net/bugs/1420785 --- openlp/plugins/bibles/lib/versereferencelist.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/lib/versereferencelist.py b/openlp/plugins/bibles/lib/versereferencelist.py index f21a51f27..a04617877 100644 --- a/openlp/plugins/bibles/lib/versereferencelist.py +++ b/openlp/plugins/bibles/lib/versereferencelist.py @@ -82,9 +82,11 @@ class VerseReferenceList(object): if result[-1] not in [';', ',', '.']: result += ';' result += ' ' - result = '%s%s, %s' % (result, version['version'], version['copyright']) + result += version['version'] + if version['copyright'].strip(): + result += ', ' + version['copyright'] if version['permission'].strip(): - result = result + ', ' + version['permission'] + result += ', ' + version['permission'] result = result.rstrip() if result.endswith(','): return result[:len(result) - 1] From 81de433df4428146ede98b1d824bcc0f4cbf6ba4 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 13 Feb 2015 23:01:07 +0000 Subject: [PATCH 5/7] Added test for csvbible import --- openlp/core/common/settings.py | 6 +- openlp/plugins/bibles/lib/csvbible.py | 6 +- .../openlp_plugins/bibles/test_csvimport.py | 97 +++++++++++++++++++ tests/resources/bibles/dk1933-books.csv | 22 +++++ tests/resources/bibles/dk1933-verses.csv | 10 ++ 5 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 tests/functional/openlp_plugins/bibles/test_csvimport.py create mode 100644 tests/resources/bibles/dk1933-books.csv create mode 100644 tests/resources/bibles/dk1933-verses.csv diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 8d5abb7bc..cd121c2ef 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -216,7 +216,8 @@ class Settings(QtCore.QSettings): 'shortcuts/moveDown': [QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextTrackItem': [], 'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], - 'shortcuts/nextItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], + 'shortcuts/nextItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Down), + QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextService': [QtGui.QKeySequence(QtCore.Qt.Key_Right)], 'shortcuts/newService': [], 'shortcuts/offlineHelpItem': [], @@ -230,7 +231,8 @@ class Settings(QtCore.QSettings): 'shortcuts/playSlidesLoop': [], 'shortcuts/playSlidesOnce': [], 'shortcuts/previousService': [QtGui.QKeySequence(QtCore.Qt.Key_Left)], - 'shortcuts/previousItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Up), QtGui.QKeySequence(QtCore.Qt.Key_PageUp)], + 'shortcuts/previousItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Up), + QtGui.QKeySequence(QtCore.Qt.Key_PageUp)], 'shortcuts/printServiceItem': [QtGui.QKeySequence('Ctrl+P')], 'shortcuts/songExportItem': [], 'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)], diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index ffe54efa5..0836acaab 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -98,15 +98,15 @@ class CSVBible(BibleDB): for line in books_reader: if self.stop_import_flag: break - self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') - % line[2]) + self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') + % line[2]) book_ref_id = self.get_book_ref_id_by_name(line[2], 67, language_id) if not book_ref_id: log.error('Importing books from "%s" failed' % self.books_file) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) self.create_book(line[2], book_ref_id, book_details['testament_id']) - book_list[int(line[0])] = line[2] + book_list.update({int(line[0]): line[2]}) self.application.process_events() except (IOError, IndexError): log.exception('Loading books from file failed') diff --git a/tests/functional/openlp_plugins/bibles/test_csvimport.py b/tests/functional/openlp_plugins/bibles/test_csvimport.py new file mode 100644 index 000000000..9fb3de9c2 --- /dev/null +++ b/tests/functional/openlp_plugins/bibles/test_csvimport.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2015 OpenLP Developers # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +This module contains tests for the CSV Bible importer. +""" + +import os +import json +from unittest import TestCase + +from tests.functional import MagicMock, patch +from openlp.plugins.bibles.lib.csvbible import CSVBible +from openlp.plugins.bibles.lib.db import BibleDB + +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), + '..', '..', '..', 'resources', 'bibles')) + + +class TestCSVImport(TestCase): + """ + Test the functions in the :mod:`csvimport` module. + """ + + def setUp(self): + self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher.start() + self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') + self.manager_patcher.start() + + def tearDown(self): + self.registry_patcher.stop() + self.manager_patcher.stop() + + def create_importer_test(self): + """ + Test creating an instance of the CSV file importer + """ + # GIVEN: A mocked out "manager" + mocked_manager = MagicMock() + + # WHEN: An importer object is created + importer = CSVBible(mocked_manager, path='.', name='.', booksfile='.', versefile='.') + + # THEN: The importer should be an instance of BibleDB + self.assertIsInstance(importer, BibleDB) + + def file_import_test(self): + """ + Test the actual import of CSV Bible file + """ + # GIVEN: Test files with a mocked out "manager", "import_wizard", and mocked functions + # get_book_ref_id_by_name, create_verse, create_book, session and get_language. + result_file = open(os.path.join(TEST_PATH, 'dk1933.json'), 'rb') + test_data = json.loads(result_file.read().decode()) + books_file = os.path.join(TEST_PATH, 'dk1933-books.csv') + verses_file = os.path.join(TEST_PATH, 'dk1933-verses.csv') + with patch('openlp.plugins.bibles.lib.csvbible.CSVBible.application'): + mocked_manager = MagicMock() + mocked_import_wizard = MagicMock() + importer = CSVBible(mocked_manager, path='.', name='.', booksfile=books_file, versefile=verses_file) + importer.wizard = mocked_import_wizard + importer.get_book_ref_id_by_name = MagicMock() + importer.create_verse = MagicMock() + importer.create_book = MagicMock() + importer.session = MagicMock() + importer.get_language = MagicMock() + importer.get_language.return_value = 'Danish' + importer.get_book = MagicMock() + + # WHEN: Importing bible file + importer.do_import() + + # THEN: The create_verse() method should have been called with each verse in the file. + self.assertTrue(importer.create_verse.called) + for verse_tag, verse_text in test_data['verses']: + importer.create_verse.assert_any_call(importer.get_book().id, '1', verse_tag, verse_text) + importer.create_book.assert_any_call('1. Mosebog', importer.get_book_ref_id_by_name(), 1) + importer.create_book.assert_any_call('1. Krønikebog', importer.get_book_ref_id_by_name(), 1) diff --git a/tests/resources/bibles/dk1933-books.csv b/tests/resources/bibles/dk1933-books.csv new file mode 100644 index 000000000..43bd7e462 --- /dev/null +++ b/tests/resources/bibles/dk1933-books.csv @@ -0,0 +1,22 @@ +1,1,1. Mosebog,1Mos +2,1,2. Mosebog,2Mos +3,1,3. Mosebog,3Mos +4,1,4. Mosebog,4Mos +5,1,5. Mosebog,5Mos +6,1,Josvabogen,jos +7,1,Dommerbogen,dom +8,1,Ruths Bog,ruth +9,1,1. Samuelsbog,1Sam +10,1,2. Samuelsbog,2Sam +11,1,1. Kongebog,1kong +12,1,2. Kongebog,2kong +13,1,1. Krønikebog,1kron +14,1,2. Krønikebog,2kron +15,1,Ezras Bog,ezra +16,1,Nehemias' Bog,neh +17,1,Esters Bog,est +18,1,Jobs Bog,job +19,1,Salmernes Bog,sl +20,1,Ordsprogenes Bog,ordsp +21,1,Prædikerens Bog,prad +22,1,Højsangen,hojs diff --git a/tests/resources/bibles/dk1933-verses.csv b/tests/resources/bibles/dk1933-verses.csv new file mode 100644 index 000000000..bb065b177 --- /dev/null +++ b/tests/resources/bibles/dk1933-verses.csv @@ -0,0 +1,10 @@ +1,1,1,"I Begyndelsen skabte Gud Himmelen og Jorden." +1,1,2,"Og Jorden var øde og tom, og der var Mørke over Verdensdybet. Men Guds Ånd svævede over Vandene." +1,1,3,"Og Gud sagde: ""Der blive Lys!"" Og der blev Lys." +1,1,4,"Og Gud så, at Lyset var godt, og Gud satte Skel mellem Lyset og Mørket," +1,1,5,"og Gud kaldte Lyset Dag, og Mørket kaldte han Nat. Og det blev Aften, og det blev Morgen, første Dag." +1,1,6,"Derpå sagde Gud: ""Der blive en Hvælving midt i Vandene til at skille Vandene ad!""" +1,1,7,"Og således skete det: Gud gjorde Hvælvingen og skilte Vandet under Hvælvingen fra Vandet over Hvælvingen;" +1,1,8,"og Gud kaldte Hvælvingen Himmel. Og det blev Aften, og det blev Morgen, anden Dag." +1,1,9,"Derpå sagde Gud: ""Vandet under Himmelen samle sig på eet Sted, så det faste Land kommer til Syne!"" Og således skete det;" +1,1,10,"og Gud kaldte det faste Land Jord, og Stedet, hvor Vandet samlede sig, kaldte han Hav. Og Gud så, at det var godt." From 06355032a26b032e36a57d7cae637a157432e919 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 16 Feb 2015 21:59:55 +0000 Subject: [PATCH 6/7] Use the doubleclick-go-live setting in the preview controller. Fixes bug 1422197. Fixes: https://launchpad.net/bugs/1422197 --- openlp/core/ui/slidecontroller.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 94ece4693..b4d36e3e1 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -408,7 +408,7 @@ class SlideController(DisplayController, RegistryProperties): self.set_live_hot_keys(self) self.__add_actions_to_widget(self.controller) else: - self.preview_widget.doubleClicked.connect(self.on_preview_add_to_service) + self.preview_widget.doubleClicked.connect(self.on_preview_double_click) self.toolbar.set_widget_visible(['editSong'], False) self.controller.addActions([self.next_item, self.previous_item]) Registry().register_function('slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop) @@ -1309,18 +1309,21 @@ class SlideController(DisplayController, RegistryProperties): if self.service_item: self.service_manager.add_service_item(self.service_item) - def on_go_live_click(self, field=None): + def on_preview_double_click(self, field=None): """ - triggered by clicking the Preview slide items + Triggered when a preview slide item is doubleclicked """ - if Settings().value('advanced/double click live'): - # Live and Preview have issues if we have video or presentations - # playing in both at the same time. - if self.service_item.is_command(): - Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live]) - if self.service_item.is_media(): - self.on_media_close() - self.on_go_live() + if self.service_item: + if Settings().value('advanced/double click live'): + # Live and Preview have issues if we have video or presentations + # playing in both at the same time. + if self.service_item.is_command(): + Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live]) + if self.service_item.is_media(): + self.on_media_close() + self.on_go_live() + else: + self.on_preview_add_to_service() def on_go_live(self, field=None): """ From f01aa970a7860be383a9f1e6768afc8845031f7f Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 16 Feb 2015 22:03:59 +0000 Subject: [PATCH 7/7] Revert fix for bug 1421561, it is fixed elsewhere. --- openlp/core/ui/firsttimeform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index d92866bc4..8e5ab219f 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -449,7 +449,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties): site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT) meta = site.info() return int(meta.get("Content-Length")) - except ConnectionError: + except ConnectionException: if retries > CONNECTION_RETRIES: raise else: