From f32c7823dffa20d75eccd17d8a95a7bc8baa9918 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Dec 2015 14:04:01 +0100 Subject: [PATCH 01/11] First stab at a pysword based SWORD-importer. --- openlp/core/ui/wizard.py | 1 + .../plugins/bibles/forms/bibleimportform.py | 166 +++++++++++++++++- openlp/plugins/bibles/lib/manager.py | 5 + 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/wizard.py b/openlp/core/ui/wizard.py index 5724e618f..db87545fa 100644 --- a/openlp/core/ui/wizard.py +++ b/openlp/core/ui/wizard.py @@ -45,6 +45,7 @@ class WizardStrings(object): OS = 'OpenSong' OSIS = 'OSIS' ZEF = 'Zefania' + SWORD = 'Sword' # These strings should need a good reason to be retranslated elsewhere. FinishedImport = translate('OpenLP.Ui', 'Finished import.') FormatLabel = translate('OpenLP.Ui', 'Format:') diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index b563ab3bf..4670a6599 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -27,6 +27,11 @@ import os import urllib.error from PyQt4 import QtGui +try: + from pysword import modules + PYSWORD_AVAILABLE = True +except: + PYSWORD_AVAILABLE = False from openlp.core.common import AppLocation, Settings, UiStrings, translate from openlp.core.lib.db import delete_database @@ -94,6 +99,14 @@ class BibleImportForm(OpenLPWizard): self.manager.set_process_dialog(self) self.restart() self.select_stack.setCurrentIndex(0) + if PYSWORD_AVAILABLE: + self.pysword_folder_modules = modules.SwordModules() + self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules() + bible_keys = self.pysword_folder_modules_json.keys() + for key in bible_keys: + self.sword_bible_combo_box.addItem(self.pysword_folder_modules_json[key]['description'], key) + else: + self.sword_tab_widget.setDisabled(True) def custom_signals(self): """ @@ -106,6 +119,8 @@ class BibleImportForm(OpenLPWizard): self.open_song_browse_button.clicked.connect(self.on_open_song_browse_button_clicked) self.zefania_browse_button.clicked.connect(self.on_zefania_browse_button_clicked) self.web_update_button.clicked.connect(self.on_web_update_button_clicked) + self.sword_browse_button.clicked.connect(self.on_sword_browse_button_clicked) + self.sword_zipbrowse_button.clicked.connect(self.on_sword_zipbrowse_button_clicked) def add_custom_pages(self): """ @@ -121,7 +136,7 @@ class BibleImportForm(OpenLPWizard): self.format_label = QtGui.QLabel(self.select_page) self.format_label.setObjectName('FormatLabel') self.format_combo_box = QtGui.QComboBox(self.select_page) - self.format_combo_box.addItems(['', '', '', '', '']) + self.format_combo_box.addItems(['', '', '', '', '', '']) self.format_combo_box.setObjectName('FormatComboBox') self.format_layout.addRow(self.format_label, self.format_combo_box) self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) @@ -275,6 +290,64 @@ class BibleImportForm(OpenLPWizard): self.zefania_layout.addRow(self.zefania_file_label, self.zefania_file_layout) self.zefania_layout.setItem(5, QtGui.QFormLayout.LabelRole, self.spacer) self.select_stack.addWidget(self.zefania_widget) + self.sword_widget = QtGui.QWidget(self.select_page) + self.sword_widget.setObjectName('SwordWidget') + self.sword_layout = QtGui.QVBoxLayout(self.sword_widget) + self.sword_layout.setObjectName('SwordLayout') + self.sword_tab_widget = QtGui.QTabWidget(self.sword_widget) + self.sword_tab_widget.setObjectName('SwordTabWidget') + self.sword_folder_tab = QtGui.QWidget(self.sword_tab_widget) + self.sword_folder_tab.setObjectName('SwordFolderTab') + self.sword_folder_tab_layout = QtGui.QGridLayout(self.sword_folder_tab) + self.sword_folder_tab_layout.setObjectName('SwordTabFolderLayout') + self.sword_folder_label = QtGui.QLabel(self.sword_folder_tab) + self.sword_folder_label.setObjectName('SwordSourceLabel') + self.sword_folder_tab_layout.addWidget(self.sword_folder_label, 0, 0) + self.sword_folder_label.setObjectName('SwordFolderLabel') + self.sword_folder_edit = QtGui.QLineEdit(self.sword_folder_tab) + self.sword_folder_edit.setObjectName('SwordFolderEdit') + self.sword_browse_button = QtGui.QToolButton(self.sword_folder_tab) + self.sword_browse_button.setIcon(self.open_icon) + self.sword_browse_button.setObjectName('SwordBrowseButton') + self.sword_folder_tab_layout.addWidget(self.sword_folder_edit, 0, 1) + self.sword_folder_tab_layout.addWidget(self.sword_browse_button, 0, 2) + self.sword_bible_label = QtGui.QLabel(self.sword_folder_tab) + self.sword_bible_label.setObjectName('SwordBibleLabel') + self.sword_folder_tab_layout.addWidget(self.sword_bible_label, 1, 0) + self.sword_bible_combo_box = QtGui.QComboBox(self.sword_folder_tab) + self.sword_bible_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) + self.sword_bible_combo_box.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + self.sword_bible_combo_box.setObjectName('SwordBibleComboBox') + self.sword_folder_tab_layout.addWidget(self.sword_bible_combo_box, 1, 1) + self.sword_tab_widget.addTab(self.sword_folder_tab, '') + self.sword_zip_tab = QtGui.QWidget(self.sword_tab_widget) + self.sword_zip_tab.setObjectName('SwordZipTab') + self.sword_zip_layout = QtGui.QGridLayout(self.sword_zip_tab) + self.sword_zip_layout.setObjectName('SwordZipLayout') + self.sword_zipfile_label = QtGui.QLabel(self.sword_zip_tab) + self.sword_zipfile_label.setObjectName('SwordZipFileLabel') + self.sword_zipfile_edit = QtGui.QLineEdit(self.sword_zip_tab) + self.sword_zipfile_edit.setObjectName('SwordZipFileEdit') + self.sword_zipbrowse_button = QtGui.QToolButton(self.sword_zip_tab) + self.sword_zipbrowse_button.setIcon(self.open_icon) + self.sword_zipbrowse_button.setObjectName('SwordZipBrowseButton') + self.sword_zipbible_label = QtGui.QLabel(self.sword_folder_tab) + self.sword_zipbible_label.setObjectName('SwordZipBibleLabel') + self.sword_zipbible_combo_box = QtGui.QComboBox(self.sword_zip_tab) + self.sword_zipbible_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) + self.sword_zipbible_combo_box.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) + self.sword_zipbible_combo_box.setObjectName('SwordZipBibleComboBox') + self.sword_zip_layout.addWidget(self.sword_zipfile_label, 0, 0) + self.sword_zip_layout.addWidget(self.sword_zipfile_edit, 0, 1) + self.sword_zip_layout.addWidget(self.sword_zipbrowse_button, 0, 2) + self.sword_zip_layout.addWidget(self.sword_zipbible_label, 1, 0) + self.sword_zip_layout.addWidget(self.sword_zipbible_combo_box, 1, 1) + self.sword_tab_widget.addTab(self.sword_zip_tab, '') + self.sword_layout.addWidget(self.sword_tab_widget) + self.sword_disabled_label = QtGui.QLabel(self.sword_widget) + self.sword_disabled_label.setObjectName('SwordDisabledLabel') + self.sword_layout.addWidget(self.sword_disabled_label) + self.select_stack.addWidget(self.sword_widget) self.select_page_layout.addLayout(self.select_stack) self.addPage(self.select_page) # License Page @@ -323,6 +396,7 @@ class BibleImportForm(OpenLPWizard): self.format_combo_box.setItemText(BibleFormat.WebDownload, translate('BiblesPlugin.ImportWizardForm', 'Web Download')) self.format_combo_box.setItemText(BibleFormat.Zefania, WizardStrings.ZEF) + self.format_combo_box.setItemText(BibleFormat.SWORD, WizardStrings.SWORD) self.osis_file_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bible file:')) self.csv_books_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Books file:')) self.csv_verses_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Verses file:')) @@ -346,6 +420,22 @@ class BibleImportForm(OpenLPWizard): self.web_tab_widget.setTabText( self.web_tab_widget.indexOf(self.web_proxy_tab), translate('BiblesPlugin.ImportWizardForm', 'Proxy Server (Optional)')) + self.sword_bible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:')) + self.sword_folder_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD data folder:')) + self.sword_zipfile_label.setText(translate('BiblesPlugin.ImportWizardForm', 'SWORD zip-file:')) + self.sword_folder_edit.setPlaceholderText(translate('BiblesPlugin.ImportWizardForm', + 'Defaults to the standard SWORD data folder')) + self.sword_zipbible_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Bibles:')) + self.sword_tab_widget.setTabText(self.sword_tab_widget.indexOf(self.sword_folder_tab), + translate('BiblesPlugin.ImportWizardForm', 'Import from folder')) + self.sword_tab_widget.setTabText(self.sword_tab_widget.indexOf(self.sword_zip_tab), + translate('BiblesPlugin.ImportWizardForm', 'Import from Zip-file')) + if PYSWORD_AVAILABLE: + self.sword_disabled_label.setText('') + else: + self.sword_disabled_label.setText(translate('BiblesPlugin.ImportWizardForm', + 'To import SWORD bibles the pysword python module must be ' + 'installed. Please read the manual for instructions.')) self.license_details_page.setTitle( translate('BiblesPlugin.ImportWizardForm', 'License Details')) self.license_details_page.setSubTitle(translate('BiblesPlugin.ImportWizardForm', @@ -410,6 +500,28 @@ class BibleImportForm(OpenLPWizard): return False else: self.version_name_edit.setText(self.web_translation_combo_box.currentText()) + elif self.field('source_format') == BibleFormat.SWORD: + # Test the SWORD tab that is currently active + if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab): + if not self.field('sword_folder_path') and self.sword_bible_combo_box.count() == 0: + critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFolder % WizardStrings.SWORD) + self.sword_folder_edit.setFocus() + return False + key = self.sword_bible_combo_box.itemData(self.sword_bible_combo_box.currentIndex()) + if 'description' in self.pysword_folder_modules_json[key]: + self.version_name_edit.setText(self.pysword_folder_modules_json[key]['description']) + if 'distributionlicense' in self.pysword_folder_modules_json[key]: + self.permissions_edit.setText(self.pysword_folder_modules_json[key]['distributionlicense']) + elif self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_zip_tab): + if not self.field('sword_zip_path'): + critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.SWORD) + self.sword_zipfile_edit.setFocus() + return False + key = self.sword_zipbible_combo_box.itemData(self.sword_zipbible_combo_box.currentIndex()) + if 'description' in self.pysword_zip_modules_json[key]: + self.version_name_edit.setText(self.pysword_zip_modules_json[key]['description']) + if 'distributionlicense' in self.pysword_zip_modules_json[key]: + self.permissions_edit.setText(self.pysword_zip_modules_json[key]['distributionlicense']) return True elif self.currentPage() == self.license_details_page: license_version = self.field('license_version') @@ -531,6 +643,40 @@ class BibleImportForm(OpenLPWizard): self.web_update_button.setEnabled(True) self.web_progress_bar.setVisible(False) + def on_sword_browse_button_clicked(self): + """ + Show the file open dialog for the SWORD folder. + """ + self.get_folder(WizardStrings.OpenTypeFolder % WizardStrings.SWORD, self.sword_folder_edit, + 'last directory import') + if self.sword_folder_edit.text(): + try: + self.pysword_folder_modules = modules.SwordModules(self.sword_folder_edit.text()) + self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules() + bible_keys = self.pysword_folder_modules_json.keys() + self.sword_bible_combo_box.clear() + for key in bible_keys: + self.sword_bible_combo_box.addItem(self.pysword_folder_modules_json[key]['description'], key) + except: + self.sword_bible_combo_box.clear() + + def on_sword_zipbrowse_button_clicked(self): + """ + Show the file open dialog for a SWORD zip-file. + """ + self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.SWORD, self.sword_zipfile_edit, + 'last directory import') + if self.sword_zipfile_edit.text(): + try: + self.pysword_zip_modules = modules.SwordModules(self.sword_zipfile_edit.text()) + self.pysword_zip_modules_json = self.pysword_zip_modules.parse_modules() + bible_keys = self.pysword_zip_modules_json.keys() + self.sword_zipbible_combo_box.clear() + for key in bible_keys: + self.sword_zipbible_combo_box.addItem(self.pysword_zip_modules_json[key]['description'], key) + except: + self.sword_zipbible_combo_box.clear() + def register_fields(self): """ Register the bible import wizard fields. @@ -543,6 +689,8 @@ class BibleImportForm(OpenLPWizard): self.select_page.registerField('zefania_file', self.zefania_file_edit) self.select_page.registerField('web_location', self.web_source_combo_box) self.select_page.registerField('web_biblename', self.web_translation_combo_box) + self.select_page.registerField('sword_folder_path', self.sword_folder_edit) + self.select_page.registerField('sword_zip_path', self.sword_zipfile_edit) self.select_page.registerField('proxy_server', self.web_server_edit) self.select_page.registerField('proxy_username', self.web_user_edit) self.select_page.registerField('proxy_password', self.web_password_edit) @@ -565,6 +713,8 @@ class BibleImportForm(OpenLPWizard): self.setField('csv_versefile', '') self.setField('opensong_file', '') self.setField('zefania_file', '') + self.setField('sword_folder_path', '') + self.setField('sword_zip_path', '') self.setField('web_location', WebDownload.Crosswalk) self.setField('web_biblename', self.web_translation_combo_box.currentIndex()) self.setField('proxy_server', settings.value('proxy address')) @@ -626,9 +776,21 @@ class BibleImportForm(OpenLPWizard): language_id=language_id ) elif bible_type == BibleFormat.Zefania: - # Import an Zefania bible. + # Import a Zefania bible. importer = self.manager.import_bible(BibleFormat.Zefania, name=license_version, filename=self.field('zefania_file')) + elif bible_type == BibleFormat.SWORD: + # Import a SWORD bible. + if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab): + importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version, + sword_path=self.field('sword_folder_path'), + sword_key=self.sword_bible_combo_box.itemData( + self.sword_bible_combo_box.currentIndex())) + else: + importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version, + sword_path=self.field('sword_zip_path'), + sword_key=self.sword_zipbible_combo_box.itemData( + self.sword_zipbible_combo_box.currentIndex())) if importer.do_import(license_version): self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions) self.manager.reload_bibles() diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 8b7cfa18e..68e6c2d57 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -32,6 +32,7 @@ from .http import HTTPBible from .opensong import OpenSongBible from .osis import OSISBible from .zefania import ZefaniaBible +from .sword import SwordBible log = logging.getLogger(__name__) @@ -47,6 +48,7 @@ class BibleFormat(object): OpenSong = 2 WebDownload = 3 Zefania = 4 + SWORD = 5 @staticmethod def get_class(bible_format): @@ -65,6 +67,8 @@ class BibleFormat(object): return HTTPBible elif bible_format == BibleFormat.Zefania: return ZefaniaBible + elif bible_format == BibleFormat.SWORD: + return SwordBible else: return None @@ -79,6 +83,7 @@ class BibleFormat(object): BibleFormat.OpenSong, BibleFormat.WebDownload, BibleFormat.Zefania, + BibleFormat.SWORD ] From 66de29c0f91373e4dd6aa439ea229a87c52473ef Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Dec 2015 14:04:32 +0100 Subject: [PATCH 02/11] Forgot to add the actual importer... --- openlp/plugins/bibles/lib/sword.py | 102 +++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 openlp/plugins/bibles/lib/sword.py diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py new file mode 100644 index 000000000..b5f639329 --- /dev/null +++ b/openlp/plugins/bibles/lib/sword.py @@ -0,0 +1,102 @@ +# -*- 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 # +############################################################################### + +import logging +from lxml import etree, objectify +from pysword import modules, bible + +from openlp.core.common import translate +from openlp.core.lib.ui import critical_error_message_box +from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB + + +log = logging.getLogger(__name__) + + +class SwordBible(BibleDB): + """ + SWORD Bible format importer class. + """ + def __init__(self, parent, **kwargs): + """ + Constructor to create and set up an instance of the SwordBible class. This class is used to import Bibles + from SWORD bible modules. + """ + log.debug(self.__class__.__name__) + BibleDB.__init__(self, parent, **kwargs) + self.sword_key = kwargs['sword_key'] + self.sword_path = kwargs['sword_path'] + if self.sword_path == '': + self.sword_path = None + + def do_import(self, bible_name=None): + """ + Loads a Bible from SWORD module. + """ + log.debug('Starting SWORD import from "%s"' % self.sword_key) + success = True + try: + pysword_modules = modules.SwordModules(self.sword_path) + pysword_module_json = pysword_modules.parse_modules()[self.sword_key] + bible = pysword_modules.get_bible_from_module(self.sword_key) + language = pysword_module_json['lang'] + language = language[language.find('.') + 1:] + language_id = BiblesResourcesDB.get_language(language)['id'] + self.save_meta('language_id', language_id) + books = bible.get_structure().get_books() + # Count number of books + num_books = 0 + if 'ot' in books: + num_books += len(books['ot']) + if 'nt' in books: + num_books += len(books['nt']) + # Import the bible + for testament in ['ot', 'nt']: + if testament in books: + for book in books['ot']: + book_ref_id = self.get_book_ref_id_by_name(book.name, num_books, language_id) + book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) + db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) + for chapter_number in range(1, book.num_chapters + 1): + if self.stop_import_flag: + break + verses = bible.get_iter(book.name, chapter_number) + verse_number = 0 + for verse in verses: + verse_number += 1 + self.create_verse(db_book.id, chapter_number, verse_number, verse) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.Sword', 'Importing %(bookname)s %(chapter)s...') % + {'bookname': db_book.name, 'chapter': chapter_number}) + self.session.commit() + self.application.process_events() + except Exception as e: + critical_error_message_box( + message=translate('BiblesPlugin.SwordImport','An unexpected error happened while importing the SWORD ' + 'bible, please report this to the OpenLP developers.\n' + '%s' % e.msg)) + log.exception(str(e)) + success = False + if self.stop_import_flag: + return False + else: + return success From 3507b96d7da7677976c165af79a4c4a554b5dc57 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Dec 2015 15:21:38 +0100 Subject: [PATCH 03/11] Added pysword to the check_dependencies script. --- scripts/check_dependencies.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index f4c54f856..3f52ec0b9 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -96,6 +96,7 @@ OPTIONAL_MODULES = [ ('nose', '(testing framework)', True), ('mock', '(testing module)', sys.version_info[1] < 3), ('jenkins', '(access jenkins api - package name: jenkins-webapi)', True), + ('pysword', '(import SWORD bibles)', True), ] w = sys.stdout.write From 2c8e0b4dfa60b6ae007534f8527b089099f74b29 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 22 Mar 2016 15:13:59 +0100 Subject: [PATCH 04/11] update year --- openlp/plugins/bibles/lib/sword.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index b5f639329..0095b61d7 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -4,7 +4,7 @@ ############################################################################### # OpenLP - Open Source Lyrics Projection # # --------------------------------------------------------------------------- # -# Copyright (c) 2008-2015 OpenLP Developers # +# Copyright (c) 2008-2016 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 # From a86ef7e4d510c32b358366f69e7b058cd7ac1fa3 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 25 Mar 2016 20:28:33 +0100 Subject: [PATCH 05/11] import both OT and NT... --- openlp/plugins/bibles/lib/sword.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index 0095b61d7..07bd4dd56 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -69,10 +69,11 @@ class SwordBible(BibleDB): num_books += len(books['ot']) if 'nt' in books: num_books += len(books['nt']) + self.wizard.progress_bar.setMaximum(num_books) # Import the bible for testament in ['ot', 'nt']: if testament in books: - for book in books['ot']: + for book in books[testament]: book_ref_id = self.get_book_ref_id_by_name(book.name, num_books, language_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) @@ -84,9 +85,8 @@ class SwordBible(BibleDB): for verse in verses: verse_number += 1 self.create_verse(db_book.id, chapter_number, verse_number, verse) - self.wizard.increment_progress_bar( - translate('BiblesPlugin.Sword', 'Importing %(bookname)s %(chapter)s...') % - {'bookname': db_book.name, 'chapter': chapter_number}) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name) self.session.commit() self.application.process_events() except Exception as e: From 6b75148e34e4c301653dca671816fff86622d13f Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 25 Mar 2016 20:58:43 +0100 Subject: [PATCH 06/11] Disable importer if pysword is missing. Pep8 fixes. --- openlp/plugins/bibles/forms/bibleimportform.py | 9 +++++---- openlp/plugins/bibles/lib/manager.py | 6 ++++-- openlp/plugins/bibles/lib/sword.py | 6 +++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 8f7193db2..04d76139c 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -39,7 +39,7 @@ from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.utils import get_locale_key from openlp.plugins.bibles.lib.manager import BibleFormat -from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename +from openlp.plugins.bibles.lib.db import clean_filename from openlp.plugins.bibles.lib.http import CWExtract, BGExtract, BSExtract log = logging.getLogger(__name__) @@ -504,7 +504,8 @@ class BibleImportForm(OpenLPWizard): # Test the SWORD tab that is currently active if self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_folder_tab): if not self.field('sword_folder_path') and self.sword_bible_combo_box.count() == 0: - critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFolder % WizardStrings.SWORD) + critical_error_message_box(UiStrings().NFSs, + WizardStrings.YouSpecifyFolder % WizardStrings.SWORD) self.sword_folder_edit.setFocus() return False key = self.sword_bible_combo_box.itemData(self.sword_bible_combo_box.currentIndex()) @@ -785,12 +786,12 @@ class BibleImportForm(OpenLPWizard): importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version, sword_path=self.field('sword_folder_path'), sword_key=self.sword_bible_combo_box.itemData( - self.sword_bible_combo_box.currentIndex())) + self.sword_bible_combo_box.currentIndex())) else: importer = self.manager.import_bible(BibleFormat.SWORD, name=license_version, sword_path=self.field('sword_zip_path'), sword_key=self.sword_zipbible_combo_box.itemData( - self.sword_zipbible_combo_box.currentIndex())) + self.sword_zipbible_combo_box.currentIndex())) if importer.do_import(license_version): self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions) self.manager.reload_bibles() diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 3d1c5b2bf..7a2efbf32 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -32,8 +32,10 @@ from .http import HTTPBible from .opensong import OpenSongBible from .osis import OSISBible from .zefania import ZefaniaBible -from .sword import SwordBible - +try: + from .sword import SwordBible +except: + pass log = logging.getLogger(__name__) diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index 07bd4dd56..2bc4cccef 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -91,9 +91,9 @@ class SwordBible(BibleDB): self.application.process_events() except Exception as e: critical_error_message_box( - message=translate('BiblesPlugin.SwordImport','An unexpected error happened while importing the SWORD ' - 'bible, please report this to the OpenLP developers.\n' - '%s' % e.msg)) + message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD ' + 'bible, please report this to the OpenLP developers.\n' + '%s' % e.msg)) log.exception(str(e)) success = False if self.stop_import_flag: From d3a57ae46b2acd2257cb1b20d97e08b79a702c6d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 12 Apr 2016 21:55:32 +0200 Subject: [PATCH 07/11] various fixes and improvements to the sword import. --- .../plugins/bibles/forms/bibleimportform.py | 12 ++++++- openlp/plugins/bibles/lib/sword.py | 31 +++++++++---------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 04d76139c..1f827b213 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -101,7 +101,12 @@ class BibleImportForm(OpenLPWizard): self.select_stack.setCurrentIndex(0) if PYSWORD_AVAILABLE: self.pysword_folder_modules = modules.SwordModules() - self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules() + try: + self.pysword_folder_modules_json = self.pysword_folder_modules.parse_modules() + except FileNotFoundError: + log.debug('No installed SWORD modules found in the default location') + self.sword_bible_combo_box.clear() + return bible_keys = self.pysword_folder_modules_json.keys() for key in bible_keys: self.sword_bible_combo_box.addItem(self.pysword_folder_modules_json[key]['description'], key) @@ -464,6 +469,9 @@ class BibleImportForm(OpenLPWizard): if self.currentPage() == self.welcome_page: return True elif self.currentPage() == self.select_page: + self.version_name_edit.clear() + self.permissions_edit.clear() + self.copyright_edit.clear() if self.field('source_format') == BibleFormat.OSIS: if not self.field('osis_location'): critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.OSIS) @@ -513,6 +521,8 @@ class BibleImportForm(OpenLPWizard): self.version_name_edit.setText(self.pysword_folder_modules_json[key]['description']) if 'distributionlicense' in self.pysword_folder_modules_json[key]: self.permissions_edit.setText(self.pysword_folder_modules_json[key]['distributionlicense']) + if 'copyright' in self.pysword_folder_modules_json[key]: + self.copyright_edit.setText(self.pysword_folder_modules_json[key]['copyright']) elif self.sword_tab_widget.currentIndex() == self.sword_tab_widget.indexOf(self.sword_zip_tab): if not self.field('sword_zip_path'): critical_error_message_box(UiStrings().NFSs, WizardStrings.YouSpecifyFile % WizardStrings.SWORD) diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index 2bc4cccef..0db314b64 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -71,22 +71,21 @@ class SwordBible(BibleDB): num_books += len(books['nt']) self.wizard.progress_bar.setMaximum(num_books) # Import the bible - for testament in ['ot', 'nt']: - if testament in books: - for book in books[testament]: - book_ref_id = self.get_book_ref_id_by_name(book.name, num_books, language_id) - book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) - db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) - for chapter_number in range(1, book.num_chapters + 1): - if self.stop_import_flag: - break - verses = bible.get_iter(book.name, chapter_number) - verse_number = 0 - for verse in verses: - verse_number += 1 - self.create_verse(db_book.id, chapter_number, verse_number, verse) - self.wizard.increment_progress_bar( - translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name) + for testament in books.keys(): + for book in books[testament]: + book_ref_id = self.get_book_ref_id_by_name(book.name, num_books, language_id) + book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) + db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) + for chapter_number in range(1, book.num_chapters + 1): + if self.stop_import_flag: + break + verses = bible.get_iter(book.name, chapter_number) + verse_number = 0 + for verse in verses: + verse_number += 1 + self.create_verse(db_book.id, chapter_number, verse_number, verse) + self.wizard.increment_progress_bar( + translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name) self.session.commit() self.application.process_events() except Exception as e: From 6f975654ccdb92822d019e71c6060855ef9f2ff1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 15 Apr 2016 22:34:20 +0200 Subject: [PATCH 08/11] Added tests. --- openlp/plugins/bibles/lib/sword.py | 7 +- .../openlp_plugins/bibles/test_swordimport.py | 106 ++++++++++++++++++ .../bibles/forms/test_bibleimportform.py | 18 ++- 3 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 tests/functional/openlp_plugins/bibles/test_swordimport.py diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index 0db314b64..ddadc0515 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -21,8 +21,7 @@ ############################################################################### import logging -from lxml import etree, objectify -from pysword import modules, bible +from pysword import modules from openlp.core.common import translate from openlp.core.lib.ui import critical_error_message_box @@ -48,7 +47,7 @@ class SwordBible(BibleDB): if self.sword_path == '': self.sword_path = None - def do_import(self, bible_name=None): + def do_import(self): """ Loads a Bible from SWORD module. """ @@ -92,7 +91,7 @@ class SwordBible(BibleDB): critical_error_message_box( message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD ' 'bible, please report this to the OpenLP developers.\n' - '%s' % e.msg)) + '%s' % e)) log.exception(str(e)) success = False if self.stop_import_flag: diff --git a/tests/functional/openlp_plugins/bibles/test_swordimport.py b/tests/functional/openlp_plugins/bibles/test_swordimport.py new file mode 100644 index 000000000..6399c5404 --- /dev/null +++ b/tests/functional/openlp_plugins/bibles/test_swordimport.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 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 SWORD Bible importer. +""" + +import os +import json +from unittest import TestCase + +from tests.functional import MagicMock, patch +from openlp.plugins.bibles.lib.sword import SwordBible +from openlp.plugins.bibles.lib.db import BibleDB + +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), + '..', '..', '..', 'resources', 'bibles')) + + +class TestSwordImport(TestCase): + """ + Test the functions in the :mod:`swordimport` 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 Sword file importer + """ + # GIVEN: A mocked out "manager" + mocked_manager = MagicMock() + + # WHEN: An importer object is created + importer = SwordBible(mocked_manager, path='.', name='.', filename='', sword_key='', sword_path='') + + # THEN: The importer should be an instance of BibleDB + self.assertIsInstance(importer, BibleDB) + + @patch('openlp.plugins.bibles.lib.sword.SwordBible.application') + @patch('openlp.plugins.bibles.lib.sword.modules') + @patch('openlp.plugins.bibles.lib.db.BiblesResourcesDB') + def simple_import_test(self, mocked_bible_res_db, mocked_pysword_modules, mocked_application): + """ + Test that a simple SWORD import works + """ + # 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. + # Also mocked pysword structures + mocked_manager = MagicMock() + mocked_import_wizard = MagicMock() + importer = SwordBible(mocked_manager, path='.', name='.', filename='', sword_key='', sword_path='') + result_file = open(os.path.join(TEST_PATH, 'dk1933.json'), 'rb') + test_data = json.loads(result_file.read().decode()) + importer.wizard = mocked_import_wizard + importer.get_book_ref_id_by_name = MagicMock() + importer.create_verse = MagicMock() + importer.create_book = MagicMock() + importer.session = MagicMock() + mocked_bible_res_db.get_language.return_value = 'Danish' + mocked_bible = MagicMock() + mocked_genesis = MagicMock() + mocked_genesis.name = 'Genesis' + mocked_genesis.num_chapters = 1 + books = {'ot': [mocked_genesis]} + mocked_structure = MagicMock() + mocked_structure.get_books.return_value = books + mocked_bible.get_structure.return_value = mocked_structure + mocked_bible.get_iter.return_value = [verse[1] for verse in test_data['verses']] + mocked_module = MagicMock() + mocked_module.get_bible_from_module.return_value = mocked_bible + mocked_pysword_modules.SwordModules.return_value = mocked_module + + # 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.create_book().id, 1, int(verse_tag), verse_text) diff --git a/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py b/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py index 76d0195f5..25dcb9d45 100644 --- a/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py +++ b/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py @@ -27,7 +27,7 @@ from unittest import TestCase from PyQt5 import QtWidgets from openlp.core.common import Registry -from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm, WebDownload +import openlp.plugins.bibles.forms.bibleimportform as bibleimportform from tests.helpers.testmixin import TestMixin from tests.functional import MagicMock, patch @@ -46,7 +46,8 @@ class TestBibleImportForm(TestCase, TestMixin): self.setup_application() self.main_window = QtWidgets.QMainWindow() Registry().register('main_window', self.main_window) - self.form = BibleImportForm(self.main_window, MagicMock(), MagicMock()) + bibleimportform.PYSWORD_AVAILABLE = False + self.form = bibleimportform.BibleImportForm(self.main_window, MagicMock(), MagicMock()) def tearDown(self): """ @@ -76,3 +77,16 @@ class TestBibleImportForm(TestCase, TestMixin): # THEN: The webbible list should still be empty self.assertEqual(self.form.web_bible_list, {}, 'The webbible list should be empty') + + def custom_init_test(self): + """ + Test that custom_init works as expected if pysword is unavailable + """ + # GIVEN: A mocked sword_tab_widget + self.form.sword_tab_widget = MagicMock() + + # WHEN: Running custom_init + self.form.custom_init() + + # THEN: sword_tab_widget.setDisabled(True) should have been called + self.form.sword_tab_widget.setDisabled.assert_called_with(True) From 89ce4131e7db74a7bb133d7155dd0914b7718166 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 20 Apr 2016 21:29:04 +0200 Subject: [PATCH 09/11] Skip pysword tests is pysword isn't installed. --- tests/functional/openlp_plugins/bibles/test_swordimport.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/functional/openlp_plugins/bibles/test_swordimport.py b/tests/functional/openlp_plugins/bibles/test_swordimport.py index 6399c5404..ae4d9cdf9 100644 --- a/tests/functional/openlp_plugins/bibles/test_swordimport.py +++ b/tests/functional/openlp_plugins/bibles/test_swordimport.py @@ -25,10 +25,13 @@ This module contains tests for the SWORD Bible importer. import os import json -from unittest import TestCase +from unittest import TestCase, SkipTest from tests.functional import MagicMock, patch -from openlp.plugins.bibles.lib.sword import SwordBible +try: + from openlp.plugins.bibles.lib.sword import SwordBible +except ImportError: + raise SkipTest('PySword is not installed, skipping SWORD test.') from openlp.plugins.bibles.lib.db import BibleDB TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), From ebaf99f4fbe4404ffa43f978848482f0f0e89233 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 23 Apr 2016 20:33:53 +0200 Subject: [PATCH 10/11] Fix traceback --- openlp/plugins/bibles/lib/sword.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index ddadc0515..6f91803a6 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -47,7 +47,7 @@ class SwordBible(BibleDB): if self.sword_path == '': self.sword_path = None - def do_import(self): + def do_import(self, bible_name=None): """ Loads a Bible from SWORD module. """ From 72c435633cde291e800faa11b633f84070208218 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 26 Apr 2016 21:04:22 +0200 Subject: [PATCH 11/11] fix merge issues --- openlp/core/ui/lib/wizard.py | 5 +- openlp/core/ui/wizard.py.THIS | 306 ---------------------------------- 2 files changed, 4 insertions(+), 307 deletions(-) delete mode 100644 openlp/core/ui/wizard.py.THIS diff --git a/openlp/core/ui/lib/wizard.py b/openlp/core/ui/lib/wizard.py index 9399616a8..5f2321f48 100644 --- a/openlp/core/ui/lib/wizard.py +++ b/openlp/core/ui/lib/wizard.py @@ -112,8 +112,9 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): def setupUi(self, image): """ Set up the wizard UI. + :param image: path to start up image """ - self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg')) + self.setWindowIcon(build_icon(':/icon/openlp-logo.svg')) self.setModal(True) self.setOptions(QtWidgets.QWizard.IndependentPages | QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage) @@ -211,6 +212,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): def on_current_id_changed(self, page_id): """ Perform necessary functions depending on which wizard page is active. + :param page_id: current page number """ if self.with_progress_page and self.page(page_id) == self.progress_page: self.pre_wizard() @@ -222,6 +224,7 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): def custom_page_changed(self, page_id): """ Called when changing to a page other than the progress page + :param page_id: current page number """ pass diff --git a/openlp/core/ui/wizard.py.THIS b/openlp/core/ui/wizard.py.THIS deleted file mode 100644 index 9399616a8..000000000 --- a/openlp/core/ui/wizard.py.THIS +++ /dev/null @@ -1,306 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 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 # -############################################################################### -""" -The :mod:``wizard`` module provides generic wizard tools for OpenLP. -""" -import logging -import os - -from PyQt5 import QtGui, QtWidgets - -from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx -from openlp.core.lib import build_icon -from openlp.core.lib.ui import add_welcome_page - -log = logging.getLogger(__name__) - - -class WizardStrings(object): - """ - Provide standard strings for wizards to use. - """ - # Applications/Formats we import from or export to. These get used in - # multiple places but do not need translating unless you find evidence of - # the writers translating their own product name. - CSV = 'CSV' - OS = 'OpenSong' - OSIS = 'OSIS' - ZEF = 'Zefania' - SWORD = 'Sword' - # These strings should need a good reason to be retranslated elsewhere. - FinishedImport = translate('OpenLP.Ui', 'Finished import.') - FormatLabel = translate('OpenLP.Ui', 'Format:') - HeaderStyle = '%s' - Importing = translate('OpenLP.Ui', 'Importing') - ImportingType = translate('OpenLP.Ui', 'Importing "%s"...') - ImportSelect = translate('OpenLP.Ui', 'Select Import Source') - ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.') - OpenTypeFile = translate('OpenLP.Ui', 'Open %s File') - OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder') - PercentSymbolFormat = translate('OpenLP.Ui', '%p%') - Ready = translate('OpenLP.Ui', 'Ready.') - StartingImport = translate('OpenLP.Ui', 'Starting import...') - YouSpecifyFile = translate('OpenLP.Ui', 'You need to specify one %s file to import from.', - 'A file type e.g. OpenSong') - YouSpecifyFiles = translate('OpenLP.Ui', 'You need to specify at least one %s file to import from.', - 'A file type e.g. OpenSong') - YouSpecifyFolder = translate('OpenLP.Ui', 'You need to specify one %s folder to import from.', - 'A song format e.g. PowerSong') - - -class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): - """ - Generic OpenLP wizard to provide generic functionality and a unified look - and feel. - - ``parent`` - The QWidget-derived parent of the wizard. - - ``plugin`` - Plugin this wizard is part of. The plugin will be saved in the "plugin" variable. - The plugin will also be used as basis for the file dialog methods this class provides. - - ``name`` - The object name this wizard should have. - - ``image`` - The image to display on the "welcome" page of the wizard. Should be 163x350. - - ``add_progress_page`` - Whether to add a progress page with a progressbar at the end of the wizard. - """ - def __init__(self, parent, plugin, name, image, add_progress_page=True): - """ - Constructor - """ - super(OpenLPWizard, self).__init__(parent) - self.plugin = plugin - self.with_progress_page = add_progress_page - self.setObjectName(name) - self.open_icon = build_icon(':/general/general_open.png') - self.delete_icon = build_icon(':/general/general_delete.png') - self.finish_button = self.button(QtWidgets.QWizard.FinishButton) - self.cancel_button = self.button(QtWidgets.QWizard.CancelButton) - self.setupUi(image) - self.register_fields() - self.custom_init() - self.custom_signals() - self.currentIdChanged.connect(self.on_current_id_changed) - if self.with_progress_page: - self.error_copy_to_button.clicked.connect(self.on_error_copy_to_button_clicked) - self.error_save_to_button.clicked.connect(self.on_error_save_to_button_clicked) - - def setupUi(self, image): - """ - Set up the wizard UI. - """ - self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg')) - self.setModal(True) - self.setOptions(QtWidgets.QWizard.IndependentPages | - QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage) - if is_macosx(): - self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png')) - else: - self.setWizardStyle(QtWidgets.QWizard.ModernStyle) - add_welcome_page(self, image) - self.add_custom_pages() - if self.with_progress_page: - self.add_progress_page() - self.retranslateUi() - - def register_fields(self): - """ - Hook method for wizards to register any fields they need. - """ - pass - - def custom_init(self): - """ - Hook method for custom initialisation - """ - pass - - def custom_signals(self): - """ - Hook method for adding custom signals - """ - pass - - def add_custom_pages(self): - """ - Hook method for wizards to add extra pages - """ - pass - - def add_progress_page(self): - """ - Add the progress page for the wizard. This page informs the user how - the wizard is progressing with its task. - """ - self.progress_page = QtWidgets.QWizardPage() - self.progress_page.setObjectName('progress_page') - self.progress_layout = QtWidgets.QVBoxLayout(self.progress_page) - self.progress_layout.setContentsMargins(48, 48, 48, 48) - self.progress_layout.setObjectName('progress_layout') - self.progress_label = QtWidgets.QLabel(self.progress_page) - self.progress_label.setObjectName('progress_label') - self.progress_label.setWordWrap(True) - self.progress_layout.addWidget(self.progress_label) - self.progress_bar = QtWidgets.QProgressBar(self.progress_page) - self.progress_bar.setObjectName('progress_bar') - self.progress_layout.addWidget(self.progress_bar) - # Add a QTextEdit and a copy to file and copy to clipboard button to be - # able to provide feedback to the user. Hidden by default. - self.error_report_text_edit = QtWidgets.QTextEdit(self.progress_page) - self.error_report_text_edit.setObjectName('error_report_text_edit') - self.error_report_text_edit.setHidden(True) - self.error_report_text_edit.setReadOnly(True) - self.progress_layout.addWidget(self.error_report_text_edit) - self.error_button_layout = QtWidgets.QHBoxLayout() - self.error_button_layout.setObjectName('error_button_layout') - spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.error_button_layout.addItem(spacer) - self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page) - self.error_copy_to_button.setObjectName('error_copy_to_button') - self.error_copy_to_button.setHidden(True) - self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png')) - self.error_button_layout.addWidget(self.error_copy_to_button) - self.error_save_to_button = QtWidgets.QPushButton(self.progress_page) - self.error_save_to_button.setObjectName('error_save_to_button') - self.error_save_to_button.setHidden(True) - self.error_save_to_button.setIcon(build_icon(':/general/general_save.png')) - self.error_button_layout.addWidget(self.error_save_to_button) - self.progress_layout.addLayout(self.error_button_layout) - self.addPage(self.progress_page) - - def exec(self): - """ - Run the wizard. - """ - self.set_defaults() - return QtWidgets.QWizard.exec(self) - - def reject(self): - """ - Stop the wizard on cancel button, close button or ESC key. - """ - log.debug('Wizard cancelled by user.') - if self.with_progress_page and self.currentPage() == self.progress_page: - Registry().execute('openlp_stop_wizard') - self.done(QtWidgets.QDialog.Rejected) - - def on_current_id_changed(self, page_id): - """ - Perform necessary functions depending on which wizard page is active. - """ - if self.with_progress_page and self.page(page_id) == self.progress_page: - self.pre_wizard() - self.perform_wizard() - self.post_wizard() - else: - self.custom_page_changed(page_id) - - def custom_page_changed(self, page_id): - """ - Called when changing to a page other than the progress page - """ - pass - - def on_error_copy_to_button_clicked(self): - """ - Called when the ``error_copy_to_button`` has been clicked. - """ - pass - - def on_error_save_to_button_clicked(self): - """ - Called when the ``error_save_to_button`` has been clicked. - """ - pass - - def increment_progress_bar(self, status_text, increment=1): - """ - Update the wizard progress page. - - :param status_text: Current status information to display. - :param increment: The value to increment the progress bar by. - """ - log.debug('IncrementBar %s', status_text) - self.progress_label.setText(status_text) - if increment > 0: - self.progress_bar.setValue(self.progress_bar.value() + increment) - self.application.process_events() - - def pre_wizard(self): - """ - Prepare the UI for the import. - """ - self.finish_button.setVisible(False) - self.progress_bar.setMinimum(0) - self.progress_bar.setMaximum(1188) - self.progress_bar.setValue(0) - - def post_wizard(self): - """ - Clean up the UI after the import has finished. - """ - self.progress_bar.setValue(self.progress_bar.maximum()) - self.finish_button.setVisible(True) - self.cancel_button.setVisible(False) - self.application.process_events() - - def get_file_name(self, title, editbox, setting_name, filters=''): - """ - Opens a QFileDialog and saves the filename to the given editbox. - - :param title: The title of the dialog (unicode). - :param editbox: An editbox (QLineEdit). - :param setting_name: The place where to save the last opened directory. - :param filters: The file extension filters. It should contain the file description - as well as the file extension. For example:: - - 'OpenLP 2 Databases (*.sqlite)' - """ - if filters: - filters += ';;' - filters += '%s (*)' % UiStrings().AllFiles - filename, filter_used = QtWidgets.QFileDialog.getOpenFileName( - self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)), - filters) - if filename: - editbox.setText(filename) - Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename) - - def get_folder(self, title, editbox, setting_name): - """ - Opens a QFileDialog and saves the selected folder to the given editbox. - - :param title: The title of the dialog (unicode). - :param editbox: An editbox (QLineEdit). - :param setting_name: The place where to save the last opened directory. - """ - folder = QtWidgets.QFileDialog.getExistingDirectory( - self, title, Settings().value(self.plugin.settings_section + '/' + setting_name), - QtWidgets.QFileDialog.ShowDirsOnly) - if folder: - editbox.setText(folder) - Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder)