From 49342f4a6960fb55cca009704166cffb9cee82cd Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 22 Jun 2014 22:12:59 +0200 Subject: [PATCH 01/69] Improve Powerpoint error handling --- .../presentations/lib/powerpointcontroller.py | 137 ++++++++++++++---- 1 file changed, 107 insertions(+), 30 deletions(-) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 09fdf2fcc..05d25b98e 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -40,6 +40,7 @@ if os.name == 'nt': import pywintypes from openlp.core.lib import ScreenList +from openlp.core.lib.ui import UiStrings, critical_error_message_box from .presentationcontroller import PresentationController, PresentationDocument @@ -99,7 +100,7 @@ class PowerpointController(PresentationController): if self.process.Presentations.Count > 0: return self.process.Quit() - except pywintypes.com_error: + except (AttributeError, pywintypes.com_error): pass self.process = None @@ -126,16 +127,23 @@ class PowerpointDocument(PresentationDocument): earlier. """ log.debug('load_presentation') - if not self.controller.process or not self.controller.process.Visible: - self.controller.start_process() try: + if not self.controller.process or not self.controller.process.Visible: + self.controller.start_process() self.controller.process.Presentations.Open(self.file_path, False, False, True) - except pywintypes.com_error: - log.debug('PPT open failed') + self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) + self.create_thumbnails() + # Powerpoint 2013 pops up when loading a file, so we minimize it again + if self.presentation.Application.Version == u'15.0': + try: + self.presentation.Application.WindowState = 2 + except: + log.error('Failed to minimize main powerpoint window') + return True + except pywintypes.com_error as e: + log.error('PPT open failed') + log.error(e) return False - self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) - self.create_thumbnails() - return True def create_thumbnails(self): """ @@ -206,23 +214,33 @@ class PowerpointDocument(PresentationDocument): Unblanks (restores) the presentation. """ log.debug('unblank_screen') - self.presentation.SlideShowSettings.Run() - self.presentation.SlideShowWindow.View.State = 1 - self.presentation.SlideShowWindow.Activate() - if self.presentation.Application.Version == '14.0': - # Unblanking is broken in PowerPoint 2010, need to redisplay - slide = self.presentation.SlideShowWindow.View.CurrentShowPosition - click = self.presentation.SlideShowWindow.View.GetClickIndex() - self.presentation.SlideShowWindow.View.GotoSlide(slide) - if click: - self.presentation.SlideShowWindow.View.GotoClick(click) + try: + self.presentation.SlideShowSettings.Run() + self.presentation.SlideShowWindow.View.State = 1 + self.presentation.SlideShowWindow.Activate() + if self.presentation.Application.Version == '14.0': + # Unblanking is broken in PowerPoint 2010, need to redisplay + slide = self.presentation.SlideShowWindow.View.CurrentShowPosition + click = self.presentation.SlideShowWindow.View.GetClickIndex() + self.presentation.SlideShowWindow.View.GotoSlide(slide) + if click: + self.presentation.SlideShowWindow.View.GotoClick(click) + except pywintypes.com_error as e: + log.error('COM error while in unblank_screen') + log.error(e) + self.show_error_msg() def blank_screen(self): """ Blanks the screen. """ log.debug('blank_screen') - self.presentation.SlideShowWindow.View.State = 3 + try: + self.presentation.SlideShowWindow.View.State = 3 + except pywintypes.com_error as e: + log.error('COM error while in blank_screen') + log.error(e) + self.show_error_msg() def is_blank(self): """ @@ -230,7 +248,12 @@ class PowerpointDocument(PresentationDocument): """ log.debug('is_blank') if self.is_active(): - return self.presentation.SlideShowWindow.View.State == 3 + try: + return self.presentation.SlideShowWindow.View.State == 3 + except pywintypes.com_error as e: + log.error('COM error while in is_blank') + log.error(e) + self.show_error_msg() else: return False @@ -239,7 +262,12 @@ class PowerpointDocument(PresentationDocument): Stops the current presentation and hides the output. """ log.debug('stop_presentation') - self.presentation.SlideShowWindow.View.Exit() + try: + self.presentation.SlideShowWindow.View.Exit() + except pywintypes.com_error as e: + log.error('COM error while in stop_presentation') + log.error(e) + self.show_error_msg() if os.name == 'nt': def start_presentation(self): @@ -259,24 +287,48 @@ class PowerpointDocument(PresentationDocument): ppt_window = self.presentation.SlideShowSettings.Run() if not ppt_window: return - ppt_window.Top = size.y() * 72 / dpi - ppt_window.Height = size.height() * 72 / dpi - ppt_window.Left = size.x() * 72 / dpi - ppt_window.Width = size.width() * 72 / dpi + try: + ppt_window.Top = size.y() * 72 / dpi + ppt_window.Height = size.height() * 72 / dpi + ppt_window.Left = size.x() * 72 / dpi + ppt_window.Width = size.width() * 72 / dpi + except AttributeError as e: + log.error('AttributeError while in start_presentation') + log.error(e) + # Powerpoint 2013 pops up when starting a file, so we minimize it again + if self.presentation.Application.Version == u'15.0': + try: + self.presentation.Application.WindowState = 2 + except: + log.error('Failed to minimize main powerpoint window') def get_slide_number(self): """ Returns the current slide number. """ log.debug('get_slide_number') - return self.presentation.SlideShowWindow.View.CurrentShowPosition + ret = 0 + try: + ret = self.presentation.SlideShowWindow.View.CurrentShowPosition + except pywintypes.com_error as e: + log.error('COM error while in get_slide_number') + log.error(e) + self.show_error_msg() + return ret def get_slide_count(self): """ Returns total number of slides. """ log.debug('get_slide_count') - return self.presentation.Slides.Count + ret = 0 + try: + ret = self.presentation.Slides.Count + except pywintypes.com_error as e: + log.error('COM error while in get_slide_count') + log.error(e) + self.show_error_msg() + return ret def goto_slide(self, slide_no): """ @@ -285,14 +337,25 @@ class PowerpointDocument(PresentationDocument): :param slide_no: The slide the text is required for, starting at 1 """ log.debug('goto_slide') - self.presentation.SlideShowWindow.View.GotoSlide(slide_no) + try: + self.presentation.SlideShowWindow.View.GotoSlide(slide_no) + except pywintypes.com_error as e: + log.error('COM error while in goto_slide') + log.error(e) + self.show_error_msg() def next_step(self): """ Triggers the next effect of slide on the running presentation. """ log.debug('next_step') - self.presentation.SlideShowWindow.View.Next() + try: + self.presentation.SlideShowWindow.View.Next() + except pywintypes.com_error as e: + log.error('COM error while in next_step') + log.error(e) + self.show_error_msg() + return if self.get_slide_number() > self.get_slide_count(): self.previous_step() @@ -301,7 +364,12 @@ class PowerpointDocument(PresentationDocument): Triggers the previous slide on the running presentation. """ log.debug('previous_step') - self.presentation.SlideShowWindow.View.Previous() + try: + self.presentation.SlideShowWindow.View.Previous() + except pywintypes.com_error as e: + log.error('COM error while in previous_step') + log.error(e) + self.show_error_msg() def get_slide_text(self, slide_no): """ @@ -319,6 +387,15 @@ class PowerpointDocument(PresentationDocument): """ return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes) + def show_error_msg(self): + """ + Stop presentation and display an error message. + """ + self.stop_presentation() + critical_error_message_box(UiStrings().Error, translate('PresentationPlugin.PowerpointDocument', + 'An error occurred in the Powerpoint integration ' + 'and the presentation will be stopped. ' + 'Relstart the presentation if you wish to present it.')) def _get_text_from_shapes(shapes): """ From e1743650516a292cb07edbd0995fa2a159512c12 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 23 Jun 2014 13:38:17 +0200 Subject: [PATCH 02/69] Fix theme export Fixes: https://launchpad.net/bugs/1332990 --- openlp/core/ui/thememanager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index fdd2ea592..714964846 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -391,9 +391,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R source = os.path.join(self.path, theme) for files in os.walk(source): for name in files[2]: - theme_zip.write( - os.path.join(source, name).encode('utf-8'), os.path.join(theme, name).encode('utf-8') - ) + theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) QtGui.QMessageBox.information(self, translate('OpenLP.ThemeManager', 'Theme Exported'), translate('OpenLP.ThemeManager', From aa0e1ca1070a3347b07762d140b3d6f6e8c6b5b2 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 23 Jun 2014 15:51:56 +0200 Subject: [PATCH 03/69] Add test --- openlp/core/ui/thememanager.py | 27 ++++---- .../openlp_core_ui/test_thememanager.py | 62 +++++++++++++++++++ tests/resources/themes/Default/Default.xml | 34 ++++++++++ 3 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 tests/functional/openlp_core_ui/test_thememanager.py create mode 100644 tests/resources/themes/Default/Default.xml diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 714964846..fb0788b99 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -383,15 +383,9 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R '/last directory export')) self.application.set_busy_cursor() if path: - Settings().setValue(self.settings_section + '/last directory export', path) - theme_path = os.path.join(path, theme + '.otz') - theme_zip = None try: - theme_zip = zipfile.ZipFile(theme_path, 'w') - source = os.path.join(self.path, theme) - for files in os.walk(source): - for name in files[2]: - theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) + Settings().setValue(self.settings_section + '/last directory export', path) + self._export_theme(path, theme) QtGui.QMessageBox.information(self, translate('OpenLP.ThemeManager', 'Theme Exported'), translate('OpenLP.ThemeManager', @@ -401,11 +395,22 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'), translate('OpenLP.ThemeManager', 'Your theme could not be exported due to an error.')) - finally: - if theme_zip: - theme_zip.close() self.application.set_normal_cursor() + def _export_theme(self, path, theme): + """ + Create the zipfile with the theme contents. + :param path: Location where the zip file will be placed + :param theme: The name of the theme to be exported + """ + theme_path = os.path.join(path, theme + '.otz') + theme_zip = zipfile.ZipFile(theme_path, 'w') + source = os.path.join(self.path, theme) + for files in os.walk(source): + for name in files[2]: + theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) + theme_zip.close() + def on_import_theme(self, field=None): """ Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from diff --git a/tests/functional/openlp_core_ui/test_thememanager.py b/tests/functional/openlp_core_ui/test_thememanager.py new file mode 100644 index 000000000..3555b8843 --- /dev/null +++ b/tests/functional/openlp_core_ui/test_thememanager.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +Package to test the openlp.core.ui.thememanager package. +""" +import zipfile +import os + +from unittest import TestCase +from tests.interfaces import MagicMock + +from openlp.core.ui import ThemeManager + +RESOURCES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources', 'themes')) + + +class TestThemeManager(TestCase): + + def export_theme_test(self): + """ + Test exporting a theme . + """ + # GIVEN: A new ThemeManager instance. + theme_manager = ThemeManager() + theme_manager.path = RESOURCES_PATH + zipfile.ZipFile.__init__ = MagicMock() + zipfile.ZipFile.__init__.return_value = None + zipfile.ZipFile.write = MagicMock() + + # WHEN: The theme is exported + theme_manager._export_theme('/some/path', 'Default') + + # THEN: The zipfile should be created at the given path + zipfile.ZipFile.__init__.assert_called_with('/some/path/Default.otz', 'w') + zipfile.ZipFile.write.assert_called_with(os.path.join(RESOURCES_PATH, 'Default', 'Default.xml'), + 'Default/Default.xml') diff --git a/tests/resources/themes/Default/Default.xml b/tests/resources/themes/Default/Default.xml new file mode 100644 index 000000000..d77731005 --- /dev/null +++ b/tests/resources/themes/Default/Default.xml @@ -0,0 +1,34 @@ + + + Default + + #000000 + + + Arial + #FFFFFF + 40 + False + False + 0 + + True + False + + + Arial + #FFFFFF + 12 + False + False + 0 + + True + False + + + 0 + 0 + False + + From 39fbbf779d930d00bc3edb34229b6951e72d548c Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 23 Jun 2014 15:54:13 +0200 Subject: [PATCH 04/69] Move this line out of try/catch block --- openlp/core/ui/thememanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index fb0788b99..c42b9b664 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -383,8 +383,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R '/last directory export')) self.application.set_busy_cursor() if path: + Settings().setValue(self.settings_section + '/last directory export', path) try: - Settings().setValue(self.settings_section + '/last directory export', path) self._export_theme(path, theme) QtGui.QMessageBox.information(self, translate('OpenLP.ThemeManager', 'Theme Exported'), From f92afc296b862efe040f656c525cc9709680e9b8 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 25 Jun 2014 14:23:31 +0200 Subject: [PATCH 05/69] First go at an importer for Worship Assistant --- openlp/plugins/songs/lib/importer.py | 31 ++-- .../songs/lib/worshipassistantimport.py | 144 ++++++++++++++++++ 2 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 openlp/plugins/songs/lib/worshipassistantimport.py diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 7ce637285..6d01da309 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -50,6 +50,7 @@ from .sundayplusimport import SundayPlusImport from .foilpresenterimport import FoilPresenterImport from .zionworximport import ZionWorxImport from .propresenterimport import ProPresenterImport +from .worshipassistantimport import WorshipAssistantImport # Imports that might fail @@ -167,8 +168,9 @@ class SongFormat(object): SongsOfFellowship = 16 SundayPlus = 17 WordsOfWorship = 18 - WorshipCenterPro = 19 - ZionWorx = 20 + WorshipAssistant = 19 + WorshipCenterPro = 20 + ZionWorx = 21 # Set optional attribute defaults __defaults__ = { @@ -321,6 +323,16 @@ class SongFormat(object): 'prefix': 'wordsOfWorship', 'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') }, + WorshipAssistant: { + 'class': WorshipAssistantImport, + 'name': 'Worship Assistant 0', + 'prefix': 'worshipAssistant', + 'selectMode': SongFormatSelect.SingleFile, + 'filter': '%s (*.csv)' % translate('SongsPlugin.ImportWizardForm', 'Worship Assistant Files'), + 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'Worship Assistant (CSV)'), + 'descriptionText': translate('SongsPlugin.ImportWizardForm', + 'In Worship Assistant, export your Database to a CSV file.') + }, WorshipCenterPro: { 'name': 'WorshipCenter Pro', 'prefix': 'worshipCenterPro', @@ -370,16 +382,17 @@ class SongFormat(object): SongFormat.SongsOfFellowship, SongFormat.SundayPlus, SongFormat.WordsOfWorship, + SongFormat.WorshipAssistant, SongFormat.WorshipCenterPro, SongFormat.ZionWorx ] @staticmethod - def get(format, *attributes): + def get(song_format, *attributes): """ Return requested song format attribute(s). - :param format: A song format from SongFormat. + :param song_format: A song format from SongFormat. :param attributes: Zero or more song format attributes from SongFormat. Return type depends on number of supplied attributes: @@ -389,23 +402,23 @@ class SongFormat(object): :>1: Return tuple of requested attribute values. """ if not attributes: - return SongFormat.__attributes__.get(format) + return SongFormat.__attributes__.get(song_format) elif len(attributes) == 1: default = SongFormat.__defaults__.get(attributes[0]) - return SongFormat.__attributes__[format].get(attributes[0], default) + return SongFormat.__attributes__[song_format].get(attributes[0], default) else: values = [] for attr in attributes: default = SongFormat.__defaults__.get(attr) - values.append(SongFormat.__attributes__[format].get(attr, default)) + values.append(SongFormat.__attributes__[song_format].get(attr, default)) return tuple(values) @staticmethod - def set(format, attribute, value): + def set(song_format, attribute, value): """ Set specified song format attribute to the supplied value. """ - SongFormat.__attributes__[format][attribute] = value + SongFormat.__attributes__[song_format][attribute] = value SongFormat.set(SongFormat.SongsOfFellowship, 'availability', HAS_SOF) diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py new file mode 100644 index 000000000..683ec6456 --- /dev/null +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`worshipassistantimport` module provides the functionality for importing +Worship Assistant songs into the OpenLP database. +""" +import csv +import logging + +from openlp.core.common import translate +from openlp.plugins.songs.lib.songimport import SongImport + +log = logging.getLogger(__name__) + +# Used to strip control chars (except 10=LF, 13=CR) +CONTROL_CHARS_MAP = dict.fromkeys(list(range(10)) + [11, 12] + list(range(14, 32)) + [127]) + + +class WorshipAssistantImport(SongImport): + """ + The :class:`WorshipAssistantImport` class provides the ability to import songs + from Worship Assistant, via a dump of the database to a CSV file. + + The following fields are in the exported CSV file: + + * ``SONGNR`` Song ID (Discarded by importer) + * ``TITLE`` Song title + * ``AUTHOR`` Song author. May containt multiple authors. + * ``COPYRIGHT`` Copyright information + * ``FIRSTLINE`` Unknown (Discarded by importer) + * ``PRIKEY`` Primary chord key + * ``ALTKEY`` Alternate chord key + * ``TEMPO`` Tempo + * ``FOCUS`` Unknown (Discarded by importer) + * ``THEME`` Theme (Discarded by importer) + * ``SCRIPTURE`` Associated scripture (Discarded by importer) + * ``ACTIVE`` Boolean value (Discarded by importer) + * ``SONGBOOK`` Boolean value (Discarded by importer) + * ``TIMESIG`` Unknown (Discarded by importer) + * ``INTRODUCED`` Date the song was created (Discarded by importer) + * ``LASTUSED`` Date the song was last used (Discarded by importer) + * ``TIMESUSED`` How many times the song was used (Discarded by importer) + * ``TIMESUSED`` How many times the song was used (Discarded by importer) + * ``CCLINR`` CCLI Number + * ``USER1`` User Field 1 (Discarded by importer) + * ``USER2`` User Field 2 (Discarded by importer) + * ``USER3`` User Field 3 (Discarded by importer) + * ``USER4`` User Field 4 (Discarded by importer) + * ``USER5`` User Field 5 (Discarded by importer) + * ``ROADMAP`` Verse order + * ``FILELINK1`` Associated file 1 (Discarded by importer) + * ``OVERMAP`` Unknown (Discarded by importer) + * ``FILELINK2`` Associated file 2 (Discarded by importer) + * ``LYRICS`` The song lyrics as plain text (Discarded by importer) + * ``INFO`` Unknown (Discarded by importer) + * ``LYRICS2`` The song lyrics with verse numbers + * ``BACKGROUND`` Unknown (Discarded by importer) + """ + def do_import(self): + """ + Receive a CSV file to import. + """ + with open(self.import_source, 'r', encoding='latin-1') as songs_file: + field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords', + 'DefaultStyle'] + songs_reader = csv.DictReader(songs_file)#, field_names) + try: + records = list(songs_reader) + except csv.Error as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), + translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') % + (songs_reader.line_num, e)) + return + num_records = len(records) + log.info('%s records found in CSV file' % num_records) + self.import_wizard.progress_bar.setMaximum(num_records) + for index, record in enumerate(records, 1): + if self.stop_import_flag: + return + # The CSV file has a line in the middle of the file where the headers are repeated. + # We need to skip this line. + if record['TITLE'] == "TITLE" and record['COPYRIGHT'] == 'COPYRIGHT' and record['AUTHOR'] == 'AUTHOR': + continue + self.set_defaults() + try: + self.title = self._decode(record['TITLE']) + self.parse_author(self._decode(record['AUTHOR'])) + self.add_copyright(self._decode(record['COPYRIGHT'])) + lyrics = self._decode(record['LYRICS2']) + except UnicodeDecodeError as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index), + translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e) + continue + except TypeError as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', + 'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e) + return + verse = '' + for line in lyrics.splitlines(): + if line and not line.isspace(): + verse += line + '\n' + elif verse: + self.add_verse(verse) + verse = '' + if verse: + self.add_verse(verse) + if not self.finish(): + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + + (': "' + self.title + '"' if self.title else '')) + + def _decode(self, str): + """ + Decodes CSV input to unicode, stripping all control characters (except new lines). + """ + # This encoding choice seems OK. ZionWorx has no option for setting the + # encoding for its songs, so we assume encoding is always the same. + return str + #return str(str, 'cp1252').translate(CONTROL_CHARS_MAP) From 4ebfa33aac66b26eb106e2b2daf58edf6a40cec1 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 25 Jun 2014 15:49:03 +0200 Subject: [PATCH 06/69] Parse verse names --- .../songs/lib/worshipassistantimport.py | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py index 683ec6456..ee9cd52cd 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -32,8 +32,10 @@ Worship Assistant songs into the OpenLP database. """ import csv import logging +import re from openlp.core.common import translate +from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) @@ -87,9 +89,7 @@ class WorshipAssistantImport(SongImport): Receive a CSV file to import. """ with open(self.import_source, 'r', encoding='latin-1') as songs_file: - field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords', - 'DefaultStyle'] - songs_reader = csv.DictReader(songs_file)#, field_names) + songs_reader = csv.DictReader(songs_file) try: records = list(songs_reader) except csv.Error as e: @@ -105,7 +105,7 @@ class WorshipAssistantImport(SongImport): return # The CSV file has a line in the middle of the file where the headers are repeated. # We need to skip this line. - if record['TITLE'] == "TITLE" and record['COPYRIGHT'] == 'COPYRIGHT' and record['AUTHOR'] == 'AUTHOR': + if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': continue self.set_defaults() try: @@ -123,13 +123,29 @@ class WorshipAssistantImport(SongImport): return verse = '' for line in lyrics.splitlines(): - if line and not line.isspace(): + if line.startswith('['): # verse marker + # drop the square brackets + right_bracket = line.find(']') + content = line[1:right_bracket].lower() + # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not + # have concept of part verses, so just ignore any non integers on the end (including floats)) + match = re.match('(\D*)(\d+)', content) + if match is not None: + verse_tag = match.group(1) + verse_num = match.group(2) + else: + # otherwise we assume number 1 and take the whole prefix as the verse tag + verse_tag = content + verse_num = '1' + verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 + verse_tag = VerseType.tags[verse_index] + elif line and not line.isspace(): verse += line + '\n' elif verse: - self.add_verse(verse) + self.add_verse(verse, verse_tag+verse_num) verse = '' if verse: - self.add_verse(verse) + self.add_verse(verse, verse_tag+verse_num) if not self.finish(): self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + (': "' + self.title + '"' if self.title else '')) From c3e9d0c5b31a38dd23096c9192eb3b44d42ca1f2 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 25 Jun 2014 17:03:00 +0200 Subject: [PATCH 07/69] Add test --- openlp/plugins/songs/lib/cclifileimport.py | 2 +- .../songs/lib/worshipassistantimport.py | 162 +++++++++--------- .../songs/test_opensongimport.py | 6 +- .../songs/test_propresenterimport.py | 2 +- .../songs/test_songshowplusimport.py | 6 +- tests/helpers/songfileimport.py | 2 +- 6 files changed, 92 insertions(+), 88 deletions(-) diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py index eda235ca1..69c20d1cc 100644 --- a/openlp/plugins/songs/lib/cclifileimport.py +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -64,7 +64,7 @@ class CCLIFileImport(SongImport): filename = str(filename) log.debug('Importing CCLI File: %s', filename) if os.path.isfile(filename): - detect_file = open(filename, 'r') + detect_file = open(filename, 'rb') detect_content = detect_file.read(2048) try: str(detect_content, 'utf-8') diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py index ee9cd52cd..d371044b1 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -30,6 +30,7 @@ The :mod:`worshipassistantimport` module provides the functionality for importing Worship Assistant songs into the OpenLP database. """ +import chardet import csv import logging import re @@ -40,8 +41,7 @@ from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) -# Used to strip control chars (except 10=LF, 13=CR) -CONTROL_CHARS_MAP = dict.fromkeys(list(range(10)) + [11, 12] + list(range(14, 32)) + [127]) +EMPTY_STR = 'NULL' class WorshipAssistantImport(SongImport): @@ -53,12 +53,12 @@ class WorshipAssistantImport(SongImport): * ``SONGNR`` Song ID (Discarded by importer) * ``TITLE`` Song title - * ``AUTHOR`` Song author. May containt multiple authors. + * ``AUTHOR`` Song author. * ``COPYRIGHT`` Copyright information * ``FIRSTLINE`` Unknown (Discarded by importer) - * ``PRIKEY`` Primary chord key - * ``ALTKEY`` Alternate chord key - * ``TEMPO`` Tempo + * ``PRIKEY`` Primary chord key (Discarded by importer) + * ``ALTKEY`` Alternate chord key (Discarded by importer) + * ``TEMPO`` Tempo (Discarded by importer) * ``FOCUS`` Unknown (Discarded by importer) * ``THEME`` Theme (Discarded by importer) * ``SCRIPTURE`` Associated scripture (Discarded by importer) @@ -75,86 +75,90 @@ class WorshipAssistantImport(SongImport): * ``USER3`` User Field 3 (Discarded by importer) * ``USER4`` User Field 4 (Discarded by importer) * ``USER5`` User Field 5 (Discarded by importer) - * ``ROADMAP`` Verse order + * ``ROADMAP`` Verse order used for the presentation (Discarded by importer) * ``FILELINK1`` Associated file 1 (Discarded by importer) - * ``OVERMAP`` Unknown (Discarded by importer) + * ``OVERMAP`` Verse order used for printing (Discarded by importer) * ``FILELINK2`` Associated file 2 (Discarded by importer) - * ``LYRICS`` The song lyrics as plain text (Discarded by importer) + * ``LYRICS`` The song lyrics used for printing (Discarded by importer, LYRICS2 is used instead) * ``INFO`` Unknown (Discarded by importer) - * ``LYRICS2`` The song lyrics with verse numbers + * ``LYRICS2`` The song lyrics used for the presentation * ``BACKGROUND`` Unknown (Discarded by importer) """ def do_import(self): """ Receive a CSV file to import. """ - with open(self.import_source, 'r', encoding='latin-1') as songs_file: - songs_reader = csv.DictReader(songs_file) - try: - records = list(songs_reader) - except csv.Error as e: - self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), - translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') % - (songs_reader.line_num, e)) - return - num_records = len(records) - log.info('%s records found in CSV file' % num_records) - self.import_wizard.progress_bar.setMaximum(num_records) - for index, record in enumerate(records, 1): - if self.stop_import_flag: - return - # The CSV file has a line in the middle of the file where the headers are repeated. - # We need to skip this line. - if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': - continue - self.set_defaults() - try: - self.title = self._decode(record['TITLE']) - self.parse_author(self._decode(record['AUTHOR'])) - self.add_copyright(self._decode(record['COPYRIGHT'])) - lyrics = self._decode(record['LYRICS2']) - except UnicodeDecodeError as e: - self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index), - translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e) - continue - except TypeError as e: - self.log_error(translate('SongsPlugin.WorshipAssistantImport', - 'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e) - return - verse = '' - for line in lyrics.splitlines(): - if line.startswith('['): # verse marker - # drop the square brackets - right_bracket = line.find(']') - content = line[1:right_bracket].lower() - # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not - # have concept of part verses, so just ignore any non integers on the end (including floats)) - match = re.match('(\D*)(\d+)', content) - if match is not None: - verse_tag = match.group(1) - verse_num = match.group(2) - else: - # otherwise we assume number 1 and take the whole prefix as the verse tag - verse_tag = content - verse_num = '1' - verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 - verse_tag = VerseType.tags[verse_index] - elif line and not line.isspace(): - verse += line + '\n' - elif verse: - self.add_verse(verse, verse_tag+verse_num) - verse = '' - if verse: - self.add_verse(verse, verse_tag+verse_num) - if not self.finish(): - self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index - + (': "' + self.title + '"' if self.title else '')) + # Get encoding + detect_file = open(self.import_source, 'rb') + detect_content = detect_file.read() + details = chardet.detect(detect_content) + detect_file.close() + songs_file = open(self.import_source, 'r', encoding=details['encoding']) - def _decode(self, str): - """ - Decodes CSV input to unicode, stripping all control characters (except new lines). - """ - # This encoding choice seems OK. ZionWorx has no option for setting the - # encoding for its songs, so we assume encoding is always the same. - return str - #return str(str, 'cp1252').translate(CONTROL_CHARS_MAP) + songs_reader = csv.DictReader(songs_file) + try: + records = list(songs_reader) + except csv.Error as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), + translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') % + (songs_reader.line_num, e)) + return + num_records = len(records) + log.info('%s records found in CSV file' % num_records) + self.import_wizard.progress_bar.setMaximum(num_records) + for index, record in enumerate(records, 1): + if self.stop_import_flag: + return + # Ensure that all keys are uppercase + record = dict((k.upper(), v) for k, v in record.items()) + # The CSV file has a line in the middle of the file where the headers are repeated. + # We need to skip this line. + if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': + continue + self.set_defaults() + try: + self.title = record['TITLE'] + if record['AUTHOR'] != EMPTY_STR: + self.parse_author(record['AUTHOR']) + if record['COPYRIGHT']!= EMPTY_STR: + self.add_copyright(record['COPYRIGHT']) + if record['CCLINR'] != EMPTY_STR: + self.ccli_number = record['CCLINR'] + lyrics = record['LYRICS2'] + except UnicodeDecodeError as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index), + translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e) + continue + except TypeError as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', + 'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e) + return + verse = '' + for line in lyrics.splitlines(): + if line.startswith('['): # verse marker + # drop the square brackets + right_bracket = line.find(']') + content = line[1:right_bracket].lower() + # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not + # have concept of part verses, so just ignore any non integers on the end (including floats)) + match = re.match('(\D*)(\d+)', content) + if match is not None: + verse_tag = match.group(1) + verse_num = match.group(2) + else: + # otherwise we assume number 1 and take the whole prefix as the verse tag + verse_tag = content + verse_num = '1' + verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 + verse_tag = VerseType.tags[verse_index] + elif line and not line.isspace(): + verse += line + '\n' + elif verse: + self.add_verse(verse, verse_tag+verse_num) + verse = '' + if verse: + self.add_verse(verse, verse_tag+verse_num) + if not self.finish(): + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + + (': "' + self.title + '"' if self.title else '')) + songs_file.close() diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 70d3b342a..96d6bff0b 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -52,11 +52,11 @@ class TestOpenSongFileImport(SongImportTestHelper): """ Test that loading an OpenSong file works correctly on various files """ - self.file_import(os.path.join(TEST_PATH, 'Amazing Grace'), + self.file_import([os.path.join(TEST_PATH, 'Amazing Grace')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer'), + self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer')], self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) - self.file_import(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five'), + self.file_import([os.path.join(TEST_PATH, 'One, Two, Three, Four, Five')], self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_propresenterimport.py b/tests/functional/openlp_plugins/songs/test_propresenterimport.py index 971ddbdf6..10e2defc6 100644 --- a/tests/functional/openlp_plugins/songs/test_propresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_propresenterimport.py @@ -50,5 +50,5 @@ class TestProPresenterFileImport(SongImportTestHelper): """ Test that loading an ProPresenter file works correctly """ - self.file_import(os.path.join(TEST_PATH, 'Amazing Grace.pro4'), + self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index 08400fdc5..dfee265e3 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -53,11 +53,11 @@ class TestSongShowPlusFileImport(SongImportTestHelper): """ Test that loading a SongShow Plus file works correctly on various files """ - self.file_import(os.path.join(TEST_PATH, 'Amazing Grace.sbsong'), + self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong'), + self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) - self.file_import(os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong'), + self.file_import([os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json'))) diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 36beef6e5..80b2ee268 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -95,7 +95,7 @@ class SongImportTestHelper(TestCase): importer.topics = [] # WHEN: Importing the source file - importer.import_source = [source_file_name] + importer.import_source = source_file_name add_verse_calls = self._get_data(result_data, 'verses') author_calls = self._get_data(result_data, 'authors') ccli_number = self._get_data(result_data, 'ccli_number') From 5eb0ac618ecc733a00a0fdc1e16b7ffd0d5e32da Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 25 Jun 2014 17:04:13 +0200 Subject: [PATCH 08/69] PEP8 --- openlp/plugins/songs/lib/worshipassistantimport.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py index d371044b1..980f7a801 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -120,7 +120,7 @@ class WorshipAssistantImport(SongImport): self.title = record['TITLE'] if record['AUTHOR'] != EMPTY_STR: self.parse_author(record['AUTHOR']) - if record['COPYRIGHT']!= EMPTY_STR: + if record['COPYRIGHT'] != EMPTY_STR: self.add_copyright(record['COPYRIGHT']) if record['CCLINR'] != EMPTY_STR: self.ccli_number = record['CCLINR'] @@ -135,12 +135,10 @@ class WorshipAssistantImport(SongImport): return verse = '' for line in lyrics.splitlines(): - if line.startswith('['): # verse marker + if line.startswith('['): # verse marker # drop the square brackets right_bracket = line.find(']') content = line[1:right_bracket].lower() - # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not - # have concept of part verses, so just ignore any non integers on the end (including floats)) match = re.match('(\D*)(\d+)', content) if match is not None: verse_tag = match.group(1) From 93c3a57ea9f3dcbce52ea925dc83190f25d33b6c Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 25 Jun 2014 17:04:28 +0200 Subject: [PATCH 09/69] Add missing files --- .../songs/test_worshipassistantimport.py | 54 +++++++++++++++++++ .../worshipassistantsongs/du_herr.csv | 30 +++++++++++ .../worshipassistantsongs/du_herr.json | 21 ++++++++ 3 files changed, 105 insertions(+) create mode 100644 tests/functional/openlp_plugins/songs/test_worshipassistantimport.py create mode 100644 tests/resources/worshipassistantsongs/du_herr.csv create mode 100644 tests/resources/worshipassistantsongs/du_herr.json diff --git a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py new file mode 100644 index 000000000..9d968beaa --- /dev/null +++ b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`worshipassistantimport` module provides the functionality for importing +WorshipAssistant song files into the current installation database. +""" + +import os + +from tests.helpers.songfileimport import SongImportTestHelper + +TEST_PATH = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'worshipassistantsongs')) + + +class TestWorshipAssistantFileImport(SongImportTestHelper): + + def __init__(self, *args, **kwargs): + self.importer_class_name = 'WorshipAssistantImport' + self.importer_module_name = 'worshipassistantimport' + super(TestWorshipAssistantFileImport, self).__init__(*args, **kwargs) + + def test_song_import(self): + """ + Test that loading an Worship Assistant file works correctly + """ + self.file_import(os.path.join(TEST_PATH, 'du_herr.csv'), + self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json'))) diff --git a/tests/resources/worshipassistantsongs/du_herr.csv b/tests/resources/worshipassistantsongs/du_herr.csv new file mode 100644 index 000000000..72c5b4735 --- /dev/null +++ b/tests/resources/worshipassistantsongs/du_herr.csv @@ -0,0 +1,30 @@ +"SongID","SongNr","Title","Author","Copyright","FirstLine","PriKey","AltKey","Tempo","Focus","Theme","Scripture","Active","Songbook","TimeSig","Introduced","LastUsed","TimesUsed","CCLINr","User1","User2","User3","User4","User5","Roadmap","Overmap","FileLink1","FileLink2","Updated","Lyrics","Info","Lyrics2","Background" +"4ee399dc-edda-4aa9-891e-a859ca093c78","NULL","Du, Herr, verläßt mich nicht","Carl Brockhaus / Johann Georg Bäßler 1806","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","1","1","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2014-06-25 12:15:28.317","","NULL","[1] +Du, Herr, verläßt mich nicht. +Auf Dich mein Herz allein vertraut, +Mein Auge glaubend auf Dich schaut. +Du bist mein Heil, mein Licht, +Mein Fels, mein sichrer Hort. +Bin ich versucht, gibt's Not und Leid, +Du bleibst mein Trost, mein Arm im Streit, +Mein Licht am dunklen Ort. + +[2] +Ich weiß, daß Du mich liebst. +Bist mir in jeder Lage nah', +Wohin ich gehe – Du bist da, +Ja, Du mir alles gibst. +Ich überlaß mich Dir; +Denn Du, Herr, kennst mich ganz und gar +Und führst mich sicher, wunderbar, +Und bist selbst alles mir. + +[3] +In dieser Wüste hier +Find't nirgend meine Seele Ruh', +Denn meine Ruh' bist, Jesu, Du. +Wohl mir, ich geh' zu Dir! +Bald werd' ich bei Dir sein, +Bald mit den Deinen ewiglich +Anbeten, loben, preisen Dich, +Mich Deiner stets erfreun.","NULL" diff --git a/tests/resources/worshipassistantsongs/du_herr.json b/tests/resources/worshipassistantsongs/du_herr.json new file mode 100644 index 000000000..56f3a7f0c --- /dev/null +++ b/tests/resources/worshipassistantsongs/du_herr.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "Carl Brockhaus / Johann Georg Bäßler 1806" + ], + "title": "Du, Herr, verläßt mich nicht", + "verse_order_list": [], + "verses": [ + [ + "Du, Herr, verläßt mich nicht.\nAuf Dich mein Herz allein vertraut,\nMein Auge glaubend auf Dich schaut.\nDu bist mein Heil, mein Licht,\nMein Fels, mein sichrer Hort.\nBin ich versucht, gibt's Not und Leid,\nDu bleibst mein Trost, mein Arm im Streit,\nMein Licht am dunklen Ort.\n", + "v1" + ], + [ + "Ich weiß, daß Du mich liebst.\nBist mir in jeder Lage nah',\nWohin ich gehe – Du bist da,\nJa, Du mir alles gibst.\nIch überlaß mich Dir;\nDenn Du, Herr, kennst mich ganz und gar\nUnd führst mich sicher, wunderbar,\nUnd bist selbst alles mir.\n", + "v2" + ], + [ + "In dieser Wüste hier\nFind't nirgend meine Seele Ruh',\nDenn meine Ruh' bist, Jesu, Du.\nWohl mir, ich geh' zu Dir!\nBald werd' ich bei Dir sein,\nBald mit den Deinen ewiglich\nAnbeten, loben, preisen Dich,\nMich Deiner stets erfreun.\n", + "v3" + ] + ] +} \ No newline at end of file From 66827a7676b1a7a9bce3966483430200cd424140 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 26 Jun 2014 09:58:59 +0200 Subject: [PATCH 10/69] Parse verse order --- openlp/plugins/songs/lib/songimport.py | 1 + .../songs/lib/worshipassistantimport.py | 18 ++++++++++++++---- .../songs/test_worshipassistantimport.py | 2 ++ .../worshipassistantsongs/du_herr.json | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index b8fcc604b..18bb571d3 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -266,6 +266,7 @@ class SongImport(QtCore.QObject): """ Add an author to the list """ + print(author) if author in self.authors: return self.authors.append(author) diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py index 980f7a801..6831ec450 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -68,21 +68,20 @@ class WorshipAssistantImport(SongImport): * ``INTRODUCED`` Date the song was created (Discarded by importer) * ``LASTUSED`` Date the song was last used (Discarded by importer) * ``TIMESUSED`` How many times the song was used (Discarded by importer) - * ``TIMESUSED`` How many times the song was used (Discarded by importer) * ``CCLINR`` CCLI Number * ``USER1`` User Field 1 (Discarded by importer) * ``USER2`` User Field 2 (Discarded by importer) * ``USER3`` User Field 3 (Discarded by importer) * ``USER4`` User Field 4 (Discarded by importer) * ``USER5`` User Field 5 (Discarded by importer) - * ``ROADMAP`` Verse order used for the presentation (Discarded by importer) + * ``ROADMAP`` Verse order used for the presentation * ``FILELINK1`` Associated file 1 (Discarded by importer) * ``OVERMAP`` Verse order used for printing (Discarded by importer) * ``FILELINK2`` Associated file 2 (Discarded by importer) * ``LYRICS`` The song lyrics used for printing (Discarded by importer, LYRICS2 is used instead) * ``INFO`` Unknown (Discarded by importer) * ``LYRICS2`` The song lyrics used for the presentation - * ``BACKGROUND`` Unknown (Discarded by importer) + * ``BACKGROUND`` Custom background (Discarded by importer) """ def do_import(self): """ @@ -116,14 +115,18 @@ class WorshipAssistantImport(SongImport): if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': continue self.set_defaults() + verse_order_list = [] try: self.title = record['TITLE'] if record['AUTHOR'] != EMPTY_STR: self.parse_author(record['AUTHOR']) + print(record['AUTHOR']) if record['COPYRIGHT'] != EMPTY_STR: self.add_copyright(record['COPYRIGHT']) if record['CCLINR'] != EMPTY_STR: self.ccli_number = record['CCLINR'] + if record['ROADMAP'] != EMPTY_STR: + verse_order_list = record['ROADMAP'].split(',') lyrics = record['LYRICS2'] except UnicodeDecodeError as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index), @@ -149,6 +152,11 @@ class WorshipAssistantImport(SongImport): verse_num = '1' verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 verse_tag = VerseType.tags[verse_index] + # Update verse order when the verse name has changed + if content != verse_tag + verse_num: + for i in range(len(verse_order_list)): + if verse_order_list[i].lower() == content.lower(): + verse_order_list[i] = verse_tag + verse_num elif line and not line.isspace(): verse += line + '\n' elif verse: @@ -156,7 +164,9 @@ class WorshipAssistantImport(SongImport): verse = '' if verse: self.add_verse(verse, verse_tag+verse_num) + if verse_order_list: + self.verse_order_list = verse_order_list if not self.finish(): - self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index + (': "' + self.title + '"' if self.title else '')) songs_file.close() diff --git a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py index 9d968beaa..c0c5c7416 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py @@ -52,3 +52,5 @@ class TestWorshipAssistantFileImport(SongImportTestHelper): """ self.file_import(os.path.join(TEST_PATH, 'du_herr.csv'), self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json'))) + self.file_import(os.path.join(TEST_PATH, 'would_you_be_free.csv'), + self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json'))) diff --git a/tests/resources/worshipassistantsongs/du_herr.json b/tests/resources/worshipassistantsongs/du_herr.json index 56f3a7f0c..1df700df8 100644 --- a/tests/resources/worshipassistantsongs/du_herr.json +++ b/tests/resources/worshipassistantsongs/du_herr.json @@ -18,4 +18,4 @@ "v3" ] ] -} \ No newline at end of file +} From c63883402383702fb2750e003f53e42de1707d7b Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 26 Jun 2014 09:59:16 +0200 Subject: [PATCH 11/69] Add missing files --- .../would_you_be_free.csv | 30 +++++++++++++++++++ .../would_you_be_free.json | 19 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/resources/worshipassistantsongs/would_you_be_free.csv create mode 100644 tests/resources/worshipassistantsongs/would_you_be_free.json diff --git a/tests/resources/worshipassistantsongs/would_you_be_free.csv b/tests/resources/worshipassistantsongs/would_you_be_free.csv new file mode 100644 index 000000000..a454ddbf5 --- /dev/null +++ b/tests/resources/worshipassistantsongs/would_you_be_free.csv @@ -0,0 +1,30 @@ +SONGNR,TITLE,AUTHOR,COPYRIGHT,FIRSTLINE,PRIKEY,ALTKEY,TEMPO,FOCUS,THEME,SCRIPTURE,ACTIVE,SONGBOOK,TIMESIG,INTRODUCED,LASTUSED,TIMESUSED,CCLINR,USER1,USER2,USER3,USER4,USER5,ROADMAP,FILELINK1,OVERMAP,FILELINK2,LYRICS,INFO,LYRICS2,Background +"7","Would You Be Free","Jones, Lewis E.","Public Domain","Would you be free from your burden of sin?","G","","Moderate","Only To Others","","","N","Y","","1899-12-30","1899-12-30","","","","","","","","1,C,1","","","",".G C G + Would you be free from your burden of sin? +. D D7 G + There's power in the blood, power in the blood +. C G + Would you o'er evil a victory win? +. D D7 G + There's wonderful power in the blood + +.G C G + There is power, power, wonder working power +.D G + In the blood of the Lamb +. C G + There is power, power, wonder working power +. D G + In the precious blood of the Lamb +","","[1] +Would you be free from your burden of sin? +There's power in the blood, power in the blood +Would you o'er evil a victory win? +There's wonderful power in the blood + +[C] +There is power, power, wonder working power +In the blood of the Lamb +There is power, power, wonder working power +In the precious blood of the Lamb +","" diff --git a/tests/resources/worshipassistantsongs/would_you_be_free.json b/tests/resources/worshipassistantsongs/would_you_be_free.json new file mode 100644 index 000000000..96bc06a59 --- /dev/null +++ b/tests/resources/worshipassistantsongs/would_you_be_free.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "Jones", + "Lewis E" + ], + "title": "Would You Be Free", + "verse_order_list": ["v1", "c1", "v1"], + "copyright": "Public Domain", + "verses": [ + [ + "Would you be free from your burden of sin? \nThere's power in the blood, power in the blood \nWould you o'er evil a victory win? \nThere's wonderful power in the blood \n", + "v1" + ], + [ + "There is power, power, wonder working power \nIn the blood of the Lamb \nThere is power, power, wonder working power \nIn the precious blood of the Lamb \n", + "c1" + ] + ] +} From a52dc69c89f4e965f6224ba6022dd99a71f42215 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 26 Jun 2014 10:04:33 +0200 Subject: [PATCH 12/69] Remove debug output --- openlp/plugins/songs/lib/songimport.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 18bb571d3..b8fcc604b 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -266,7 +266,6 @@ class SongImport(QtCore.QObject): """ Add an author to the list """ - print(author) if author in self.authors: return self.authors.append(author) From 78f1756380b4576a8c57ef98db16b7d95c507bcc Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 26 Jun 2014 10:35:53 +0200 Subject: [PATCH 13/69] Fix biblegateway url --- openlp/plugins/bibles/lib/http.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 64b024639..6b26dfabe 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -225,7 +225,7 @@ class BGExtract(RegistryProperties): url_book_name = urllib.parse.quote(book_name.encode("utf-8")) url_params = 'search=%s+%s&version=%s' % (url_book_name, chapter, version) soup = get_soup_for_bible_ref( - 'http://www.biblegateway.com/passage/?%s' % url_params, + 'http://legacy.biblegateway.com/passage/?%s' % url_params, pre_parse_regex=r'', pre_parse_substitute='') if not soup: return None @@ -252,7 +252,7 @@ class BGExtract(RegistryProperties): """ log.debug('BGExtract.get_books_from_http("%s")', version) url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version}) - reference_url = 'http://www.biblegateway.com/versions/?%s#books' % url_params + reference_url = 'http://legacy.biblegateway.com/versions/?%s#books' % url_params page = get_web_page(reference_url) if not page: send_error_message('download') From b4be73b616bad50b9fe732cddd45b092cdbaa1d6 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 26 Jun 2014 11:21:46 +0200 Subject: [PATCH 14/69] Fix bzr tags test --- tests/utils/test_bzr_tags.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index 393f4ce25..acadbd8c4 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -50,10 +50,6 @@ TAGS = [ ['1.9.11', '2039'], ['1.9.12', '2063'], ['2.0', '2118'], - ['2.0.1', '?'], - ['2.0.2', '?'], - ['2.0.3', '?'], - ['2.0.4', '?'], ['2.1.0', '2119'] ] From 7364d4962f7b70aa9f2536a2c347269e402a9a29 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 30 Jun 2014 09:18:26 +0200 Subject: [PATCH 15/69] Small fixes --- openlp/plugins/songs/lib/worshipassistantimport.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/worshipassistantimport.py index 6831ec450..772fe8622 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/worshipassistantimport.py @@ -93,7 +93,6 @@ class WorshipAssistantImport(SongImport): details = chardet.detect(detect_content) detect_file.close() songs_file = open(self.import_source, 'r', encoding=details['encoding']) - songs_reader = csv.DictReader(songs_file) try: records = list(songs_reader) @@ -109,7 +108,7 @@ class WorshipAssistantImport(SongImport): if self.stop_import_flag: return # Ensure that all keys are uppercase - record = dict((k.upper(), v) for k, v in record.items()) + record = dict((field.upper(), value) for field, value in record.items()) # The CSV file has a line in the middle of the file where the headers are repeated. # We need to skip this line. if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2': From 9702870afa6e8cd11fb6cf64b816f230c70f6213 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 30 Jun 2014 09:30:19 +0200 Subject: [PATCH 16/69] Close and delete zip in case of exception --- openlp/core/ui/thememanager.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index c42b9b664..95df35831 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -404,12 +404,17 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R :param theme: The name of the theme to be exported """ theme_path = os.path.join(path, theme + '.otz') - theme_zip = zipfile.ZipFile(theme_path, 'w') - source = os.path.join(self.path, theme) - for files in os.walk(source): - for name in files[2]: - theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) - theme_zip.close() + try: + theme_zip = zipfile.ZipFile(theme_path, 'w') + source = os.path.join(self.path, theme) + for files in os.walk(source): + for name in files[2]: + theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) + except (IOError, OSError): + if theme_zip: + theme_zip.close() + shutil.rmtree(theme_path, True) + raise def on_import_theme(self, field=None): """ From af6537116c785735c1dd80292cfa0c238f0ea413 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 30 Jun 2014 14:36:35 +0200 Subject: [PATCH 17/69] Close file also on success --- openlp/core/ui/thememanager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 95df35831..c68d1694b 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -415,6 +415,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R theme_zip.close() shutil.rmtree(theme_path, True) raise + else: + theme_zip.close() def on_import_theme(self, field=None): """ From 7d2f8fa6cd02537fdf961c1c53da17b3bf75c603 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 1 Jul 2014 22:10:26 +0100 Subject: [PATCH 18/69] Fix setup.py --- openlp/.version | 2 +- openlp/core/utils/__init__.py | 4 ++-- resources/openlp.desktop | 6 ------ setup.py | 6 +++--- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/openlp/.version b/openlp/.version index 3245d0c77..406870ece 100644 --- a/openlp/.version +++ b/openlp/.version @@ -1 +1 @@ -2.1.0-bzr2234 +2.1.0-bzr2389 diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index add663132..9b024eb84 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -149,9 +149,9 @@ def get_application_version(): # If they are equal, then this tree is tarball with the source for the release. We do not want the revision # number in the full version. if tree_revision == tag_revision: - full_version = tag_version + full_version = tag_version.decode('utf-8') else: - full_version = '%s-bzr%s' % (tag_version, tree_revision) + full_version = '%s-bzr%s' % (tag_version.decode('utf-8'), tree_revision.decode('utf-8')) else: # We're not running the development version, let's use the file. filepath = AppLocation.get_directory(AppLocation.VersionDir) diff --git a/resources/openlp.desktop b/resources/openlp.desktop index b17cbaf96..d585f4022 100755 --- a/resources/openlp.desktop +++ b/resources/openlp.desktop @@ -1,7 +1,5 @@ [Desktop Entry] Categories=AudioVideo; -Comment[de]= -Comment= Exec=openlp %F GenericName[de]=Church lyrics projection GenericName=Church lyrics projection @@ -9,11 +7,7 @@ Icon=openlp MimeType=application/x-openlp-service; Name[de]=OpenLP Name=OpenLP -Path= StartupNotify=true Terminal=false Type=Application -X-DBUS-ServiceName= -X-DBUS-StartupType= X-KDE-SubstituteUID=false -X-KDE-Username= diff --git a/setup.py b/setup.py index fc4a6f89b..fbf53d6d5 100755 --- a/setup.py +++ b/setup.py @@ -106,9 +106,9 @@ try: # If they are equal, then this tree is tarball with the source for the release. We do not want the revision number # in the version string. if tree_revision == tag_revision: - version_string = tag_version + version_string = tag_version.decode('utf-8') else: - version_string = '%s-bzr%s' % (tag_version, tree_revision) + version_string = '%s-bzr%s' % (tag_version.decode('utf-8'), tree_revision.decode('utf-8')) ver_file = open(VERSION_FILE, 'w') ver_file.write(version_string) except: @@ -152,7 +152,7 @@ using a computer and a data projector.""", 'Operating System :: POSIX :: BSD :: FreeBSD', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', 'Topic :: Desktop Environment :: Gnome', 'Topic :: Desktop Environment :: K Desktop Environment (KDE)', 'Topic :: Multimedia', From b3041a528764b7cdda0ce7fbfec7ee1f8f1c1135 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 1 Jul 2014 22:11:13 +0100 Subject: [PATCH 19/69] Fix version --- openlp/.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/.version b/openlp/.version index 406870ece..3245d0c77 100644 --- a/openlp/.version +++ b/openlp/.version @@ -1 +1 @@ -2.1.0-bzr2389 +2.1.0-bzr2234 From f649f0af3c3c252f4b0c8d310170f8a7ad27f352 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 19:13:23 +0100 Subject: [PATCH 20/69] Fix initialisation --- openlp/core/lib/renderer.py | 1 - openlp/core/ui/maindisplay.py | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 71a1f6058..ab4a5a4df 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -59,7 +59,6 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): """ super(Renderer, self).__init__(None) # Need live behaviour if this is also working as a pseudo MainDisplay. - self.is_live = True self.screens = ScreenList() self.theme_level = ThemeLevel.Global self.global_theme_name = '' diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 946299aca..5c905c972 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -66,11 +66,8 @@ class Display(QtGui.QGraphicsView): if hasattr(parent, 'is_live') and parent.is_live: self.is_live = True if self.is_live: - super(Display, self).__init__() - # Overwrite the parent() method. self.parent = lambda: parent - else: - super(Display, self).__init__(parent) + super(Display, self).__init__() self.controller = parent self.screen = {} # FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with From 4ac921a2e7292f27f837dc264b31436c16bebc1b Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 19:38:10 +0100 Subject: [PATCH 21/69] tests --- .../openlp_core_common/test_registrymixin.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/functional/openlp_core_common/test_registrymixin.py diff --git a/tests/functional/openlp_core_common/test_registrymixin.py b/tests/functional/openlp_core_common/test_registrymixin.py new file mode 100644 index 000000000..75e134d5a --- /dev/null +++ b/tests/functional/openlp_core_common/test_registrymixin.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +Package to test the openlp.core.common package. +""" +import os +from unittest import TestCase + +from openlp.core.common import RegistryMixin, Registry + +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..', 'resources')) + + +class TestRegistryMixin(TestCase): + + def registry_mixin_missing_test(self): + """ + Test the registry creation and its usage + """ + # GIVEN: A new registry + Registry.create() + + # WHEN: I create a new class + mock_1 = Test1() + + # THEN: The following methods are missing + self.assertEqual(len(Registry().functions_list), 0), 'The function should not be in the dict anymore.' + + def registry_mixin_present_test(self): + """ + Test the registry creation and its usage + """ + # GIVEN: A new registry + Registry.create() + + # WHEN: I create a new class + mock_2 = Test2() + + # THEN: The following bootstrap methods should be present + self.assertEqual(len(Registry().functions_list), 2), 'The bootstrap functions should be in the dict.' + + +class Test1(object): + def __init__(self): + pass + + +class Test2(RegistryMixin): + def __init__(self): + super(Test2, self).__init__(None) \ No newline at end of file From f71c4cc7af7e5544c5e021aff75daaa2ca1691a1 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 19:58:52 +0100 Subject: [PATCH 22/69] remove nonvalid test --- tests/functional/openlp_core_lib/test_renderer.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_renderer.py b/tests/functional/openlp_core_lib/test_renderer.py index 8814a21a0..8df4816bb 100644 --- a/tests/functional/openlp_core_lib/test_renderer.py +++ b/tests/functional/openlp_core_lib/test_renderer.py @@ -65,16 +65,6 @@ class TestRenderer(TestCase): """ del self.screens - def initial_renderer_test(self): - """ - Test the initial renderer state - """ - # GIVEN: A new renderer instance. - renderer = Renderer() - # WHEN: the default renderer is built. - # THEN: The renderer should be a live controller. - self.assertEqual(renderer.is_live, True, 'The base renderer should be a live controller') - def default_screen_layout_test(self): """ Test the default layout calculations From 3f889e08d4ea72ae940bcb5c174d93c6e423f0a8 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 20:34:28 +0100 Subject: [PATCH 23/69] Fix setup.py --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index fbf53d6d5..28f3658f1 100755 --- a/setup.py +++ b/setup.py @@ -105,6 +105,8 @@ try: tag_version, tag_revision = tags[-1].split() # If they are equal, then this tree is tarball with the source for the release. We do not want the revision number # in the version string. + tree_revision = tree_revision.strip() + tag_revision = tag_revision.strip() if tree_revision == tag_revision: version_string = tag_version.decode('utf-8') else: From 6847ee2e37e4f4db3a514eed3ad85ed113bf4b9d Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 20:47:54 +0100 Subject: [PATCH 24/69] remove bl --- tests/functional/openlp_core_common/test_registrymixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_common/test_registrymixin.py b/tests/functional/openlp_core_common/test_registrymixin.py index 75e134d5a..800445637 100644 --- a/tests/functional/openlp_core_common/test_registrymixin.py +++ b/tests/functional/openlp_core_common/test_registrymixin.py @@ -73,4 +73,4 @@ class Test1(object): class Test2(RegistryMixin): def __init__(self): - super(Test2, self).__init__(None) \ No newline at end of file + super(Test2, self).__init__(None) From 12c8663f8e2e6e151d0d5ec1f397fc893822ce64 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 2 Jul 2014 20:52:26 +0100 Subject: [PATCH 25/69] indent --- tests/functional/openlp_core_common/test_registrymixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_common/test_registrymixin.py b/tests/functional/openlp_core_common/test_registrymixin.py index 800445637..d8636ac94 100644 --- a/tests/functional/openlp_core_common/test_registrymixin.py +++ b/tests/functional/openlp_core_common/test_registrymixin.py @@ -73,4 +73,4 @@ class Test1(object): class Test2(RegistryMixin): def __init__(self): - super(Test2, self).__init__(None) + super(Test2, self).__init__(None) From 79c7c583988c1f19f9183877a6fad6f635d15f58 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 3 Jul 2014 13:21:12 +0200 Subject: [PATCH 26/69] Added test for powerpointcontroller --- .../presentations/lib/powerpointcontroller.py | 50 ++++--- .../test_powerpointcontroller.py | 131 ++++++++++++++++++ 2 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 05d25b98e..0f9c2ff35 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -40,7 +40,8 @@ if os.name == 'nt': import pywintypes from openlp.core.lib import ScreenList -from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.ui import UiStrings, critical_error_message_box, translate +from openlp.core.common import trace_error_handler from .presentationcontroller import PresentationController, PresentationDocument @@ -139,10 +140,11 @@ class PowerpointDocument(PresentationDocument): self.presentation.Application.WindowState = 2 except: log.error('Failed to minimize main powerpoint window') + trace_error_handler(log) return True - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('PPT open failed') - log.error(e) + trace_error_handler(log) return False def create_thumbnails(self): @@ -225,9 +227,9 @@ class PowerpointDocument(PresentationDocument): self.presentation.SlideShowWindow.View.GotoSlide(slide) if click: self.presentation.SlideShowWindow.View.GotoClick(click) - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in unblank_screen') - log.error(e) + trace_error_handler(log) self.show_error_msg() def blank_screen(self): @@ -237,9 +239,9 @@ class PowerpointDocument(PresentationDocument): log.debug('blank_screen') try: self.presentation.SlideShowWindow.View.State = 3 - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in blank_screen') - log.error(e) + trace_error_handler(log) self.show_error_msg() def is_blank(self): @@ -250,9 +252,9 @@ class PowerpointDocument(PresentationDocument): if self.is_active(): try: return self.presentation.SlideShowWindow.View.State == 3 - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in is_blank') - log.error(e) + trace_error_handler(log) self.show_error_msg() else: return False @@ -264,9 +266,9 @@ class PowerpointDocument(PresentationDocument): log.debug('stop_presentation') try: self.presentation.SlideShowWindow.View.Exit() - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in stop_presentation') - log.error(e) + trace_error_handler(log) self.show_error_msg() if os.name == 'nt': @@ -301,6 +303,7 @@ class PowerpointDocument(PresentationDocument): self.presentation.Application.WindowState = 2 except: log.error('Failed to minimize main powerpoint window') + trace_error_handler(log) def get_slide_number(self): """ @@ -310,9 +313,9 @@ class PowerpointDocument(PresentationDocument): ret = 0 try: ret = self.presentation.SlideShowWindow.View.CurrentShowPosition - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in get_slide_number') - log.error(e) + trace_error_handler(log) self.show_error_msg() return ret @@ -324,9 +327,9 @@ class PowerpointDocument(PresentationDocument): ret = 0 try: ret = self.presentation.Slides.Count - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in get_slide_count') - log.error(e) + trace_error_handler(log) self.show_error_msg() return ret @@ -339,9 +342,9 @@ class PowerpointDocument(PresentationDocument): log.debug('goto_slide') try: self.presentation.SlideShowWindow.View.GotoSlide(slide_no) - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in goto_slide') - log.error(e) + trace_error_handler(log) self.show_error_msg() def next_step(self): @@ -351,9 +354,9 @@ class PowerpointDocument(PresentationDocument): log.debug('next_step') try: self.presentation.SlideShowWindow.View.Next() - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in next_step') - log.error(e) + trace_error_handler(log) self.show_error_msg() return if self.get_slide_number() > self.get_slide_count(): @@ -366,9 +369,9 @@ class PowerpointDocument(PresentationDocument): log.debug('previous_step') try: self.presentation.SlideShowWindow.View.Previous() - except pywintypes.com_error as e: + except pywintypes.com_error: log.error('COM error while in previous_step') - log.error(e) + trace_error_handler(log) self.show_error_msg() def get_slide_text(self, slide_no): @@ -392,10 +395,11 @@ class PowerpointDocument(PresentationDocument): Stop presentation and display an error message. """ self.stop_presentation() - critical_error_message_box(UiStrings().Error, translate('PresentationPlugin.PowerpointDocument', + critical_error_message_box(UiStrings().Error, translate('PresentationPlugin.PowerpointDocument', 'An error occurred in the Powerpoint integration ' 'and the presentation will be stopped. ' - 'Relstart the presentation if you wish to present it.')) + 'Restart the presentation if you wish to present it.')) + def _get_text_from_shapes(shapes): """ diff --git a/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py b/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py new file mode 100644 index 000000000..da58ef880 --- /dev/null +++ b/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +Functional tests to test the PowerPointController class and related methods. +""" +import os +if os.name == 'nt': + import pywintypes +import shutil +from unittest import TestCase +from tempfile import mkdtemp + +from tests.functional import patch, MagicMock +from tests.helpers.testmixin import TestMixin + +from openlp.plugins.presentations.lib.powerpointcontroller import PowerpointController, PowerpointDocument + + +class TestPowerpointController(TestCase, TestMixin): + """ + Test the PowerpointController Class + """ + + def setUp(self): + """ + Set up the patches and mocks need for all tests. + """ + self.get_application() + self.build_settings() + self.mock_plugin = MagicMock() + self.temp_folder = mkdtemp() + self.mock_plugin.settings_section = self.temp_folder + + def tearDown(self): + """ + Stop the patches + """ + self.destroy_settings() + shutil.rmtree(self.temp_folder) + + def constructor_test(self): + """ + Test the Constructor from the PowerpointController + """ + # GIVEN: No presentation controller + controller = None + + # WHEN: The presentation controller object is created + controller = PowerpointController(plugin=self.mock_plugin) + + # THEN: The name of the presentation controller should be correct + self.assertEqual('Powerpoint', controller.name, + 'The name of the presentation controller should be correct') + + +class TestPowerpointDocument(TestCase): + """ + Test the PowerpointDocument Class + """ + + def setUp(self): + """ + Set up the patches and mocks need for all tests. + """ + self.powerpoint_document_stop_presentation_patcher = patch( + 'openlp.plugins.presentations.lib.powerpointcontroller.PowerpointDocument.stop_presentation') + self.presentation_document_get_temp_folder_patcher = patch( + 'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument.get_temp_folder') + self.presentation_document_setup_patcher = patch( + 'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument._setup') + self.mock_powerpoint_document_stop_presentation = self.powerpoint_document_stop_presentation_patcher.start() + self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start() + self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start() + self.mock_controller = MagicMock() + self.mock_presentation = MagicMock() + self.mock_presentation_document_get_temp_folder.return_value = 'temp folder' + + def tearDown(self): + """ + Stop the patches + """ + self.powerpoint_document_stop_presentation_patcher.stop() + self.presentation_document_get_temp_folder_patcher.stop() + self.presentation_document_setup_patcher.stop() + + def show_error_msg_test(self): + """ + Test the PowerpointDocument.show_error_msg() method gets called on com exception + """ + if os.name == 'nt': + # GIVEN: A PowerpointDocument with mocked controller and presentation + with patch('openlp.plugins.presentations.lib.powerpointcontroller.critical_error_message_box') as \ + mocked_critical_error_message_box: + instance = PowerpointDocument(self.mock_controller, self.mock_presentation) + instance.presentation = MagicMock() + instance.presentation.SlideShowWindow.View.GotoSlide = MagicMock(side_effect=pywintypes.com_error('1')) + + # WHEN: Calling goto_slide which will throw an exception + instance.goto_slide(42) + + # THEN: mocked_critical_error_message_box should have been called + mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the Powerpoint ' + 'integration and the presentation will be stopped.' + ' Restart the presentation if you wish to ' + 'present it.') From d59be6ca822e8e1b4b64f62882e4c497f0954350 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 3 Jul 2014 18:54:51 +0200 Subject: [PATCH 27/69] Move song import plugins to subfolder --- openlp/plugins/songs/forms/editsongform.py | 2 +- .../plugins/songs/forms/songreviewwidget.py | 2 +- openlp/plugins/songs/lib/importer.py | 34 ++++++------ openlp/plugins/songs/lib/mediaitem.py | 2 +- openlp/plugins/songs/lib/openlyricsexport.py | 2 +- .../songs/lib/{xml.py => openlyricsxml.py} | 0 .../plugins/songs/lib/songimport/__init__.py | 31 +++++++++++ .../lib/{ => songimport}/cclifileimport.py | 0 .../lib/{ => songimport}/dreambeamimport.py | 2 +- .../lib/{ => songimport}/easyslidesimport.py | 2 +- .../songs/lib/{ => songimport}/ewimport.py | 0 .../{ => songimport}/foilpresenterimport.py | 4 +- .../lib/{ => songimport}/mediashoutimport.py | 2 +- .../songs/lib/{ => songimport}/olpimport.py | 0 .../songs/lib/{ => songimport}/oooimport.py | 0 .../lib/{ => songimport}/openlyricsimport.py | 4 +- .../lib/{ => songimport}/opensongimport.py | 2 +- .../lib/{ => songimport}/powersongimport.py | 2 +- .../{ => songimport}/propresenterimport.py | 0 .../songs/lib/{ => songimport}/sofimport.py | 0 .../lib/{ => songimport}/songbeamerimport.py | 2 +- .../songs/lib/{ => songimport}/songimport.py | 2 +- .../lib/{ => songimport}/songproimport.py | 2 +- .../{ => songimport}/songshowplusimport.py | 2 +- .../lib/{ => songimport}/sundayplusimport.py | 2 +- .../worshipassistantimport.py | 2 +- .../worshipcenterproimport.py | 2 +- .../songs/lib/{ => songimport}/wowimport.py | 2 +- .../lib/{ => songimport}/zionworximport.py | 2 +- openlp/plugins/songs/lib/songselect.py | 2 +- openlp/plugins/songs/songsplugin.py | 2 +- .../openlp_plugins/songs/test_ewimport.py | 52 +++++++++---------- .../songs/test_foilpresenterimport.py | 30 +++++------ .../songs/test_openlyricsimport.py | 6 +-- .../songs/test_opensongimport.py | 10 ++-- .../songs/test_songbeamerimport.py | 10 ++-- .../songs/test_songshowplusimport.py | 12 ++--- .../songs/test_worshipcenterproimport.py | 4 +- .../songs/test_zionworximport.py | 6 +-- tests/helpers/songfileimport.py | 12 ++--- 40 files changed, 143 insertions(+), 112 deletions(-) rename openlp/plugins/songs/lib/{xml.py => openlyricsxml.py} (100%) create mode 100644 openlp/plugins/songs/lib/songimport/__init__.py rename openlp/plugins/songs/lib/{ => songimport}/cclifileimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/dreambeamimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/easyslidesimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/ewimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/foilpresenterimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/mediashoutimport.py (98%) rename openlp/plugins/songs/lib/{ => songimport}/olpimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/oooimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/openlyricsimport.py (96%) rename openlp/plugins/songs/lib/{ => songimport}/opensongimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/powersongimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/propresenterimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/sofimport.py (100%) rename openlp/plugins/songs/lib/{ => songimport}/songbeamerimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/songimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/songproimport.py (98%) rename openlp/plugins/songs/lib/{ => songimport}/songshowplusimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/sundayplusimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/worshipassistantimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/worshipcenterproimport.py (98%) rename openlp/plugins/songs/lib/{ => songimport}/wowimport.py (99%) rename openlp/plugins/songs/lib/{ => songimport}/zionworximport.py (98%) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 2125922fe..6b5ccb041 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -44,7 +44,7 @@ from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_me from openlp.plugins.songs.lib import VerseType, clean_song from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.xml import SongXML +from openlp.plugins.songs.lib.openlyricsxml import SongXML from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog from openlp.plugins.songs.forms.editverseform import EditVerseForm from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm diff --git a/openlp/plugins/songs/forms/songreviewwidget.py b/openlp/plugins/songs/forms/songreviewwidget.py index 02d7b8774..7f5f9c0c6 100644 --- a/openlp/plugins/songs/forms/songreviewwidget.py +++ b/openlp/plugins/songs/forms/songreviewwidget.py @@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import build_icon from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.xml import SongXML +from openlp.plugins.songs.lib.openlyricsxml import SongXML class SongReviewWidget(QtGui.QWidget): diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 6d01da309..9c0b889ca 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -34,23 +34,23 @@ import logging from openlp.core.common import translate, UiStrings from openlp.core.ui.wizard import WizardStrings -from .opensongimport import OpenSongImport -from .easyslidesimport import EasySlidesImport -from .olpimport import OpenLPSongImport -from .openlyricsimport import OpenLyricsImport -from .wowimport import WowImport -from .cclifileimport import CCLIFileImport -from .dreambeamimport import DreamBeamImport -from .powersongimport import PowerSongImport -from .ewimport import EasyWorshipSongImport -from .songbeamerimport import SongBeamerImport -from .songshowplusimport import SongShowPlusImport -from .songproimport import SongProImport -from .sundayplusimport import SundayPlusImport -from .foilpresenterimport import FoilPresenterImport -from .zionworximport import ZionWorxImport -from .propresenterimport import ProPresenterImport -from .worshipassistantimport import WorshipAssistantImport +from .songimport.opensongimport import OpenSongImport +from .songimport.easyslidesimport import EasySlidesImport +from .songimport.olpimport import OpenLPSongImport +from .songimport.openlyricsimport import OpenLyricsImport +from .songimport.wowimport import WowImport +from .songimport.cclifileimport import CCLIFileImport +from .songimport.dreambeamimport import DreamBeamImport +from .songimport.powersongimport import PowerSongImport +from .songimport.ewimport import EasyWorshipSongImport +from .songimport.songbeamerimport import SongBeamerImport +from .songimport.songshowplusimport import SongShowPlusImport +from .songimport.songproimport import SongProImport +from .songimport.sundayplusimport import SundayPlusImport +from .songimport.foilpresenterimport import FoilPresenterImport +from .songimport.zionworximport import ZionWorxImport +from .songimport.propresenterimport import ProPresenterImport +from .songimport.worshipassistantimport import WorshipAssistantImport # Imports that might fail diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index d57c8fbcc..fde103c5f 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -46,7 +46,7 @@ from openlp.plugins.songs.forms.songexportform import SongExportForm from openlp.plugins.songs.lib import VerseType, clean_string, delete_song from openlp.plugins.songs.lib.db import Author, AuthorType, Song, Book, MediaFile from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.xml import OpenLyrics, SongXML +from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, SongXML log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 72210e89f..0458b893b 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -37,7 +37,7 @@ from lxml import etree from openlp.core.common import RegistryProperties, check_directory_exists, translate from openlp.core.utils import clean_filename -from openlp.plugins.songs.lib.xml import OpenLyrics +from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/openlyricsxml.py similarity index 100% rename from openlp/plugins/songs/lib/xml.py rename to openlp/plugins/songs/lib/openlyricsxml.py diff --git a/openlp/plugins/songs/lib/songimport/__init__.py b/openlp/plugins/songs/lib/songimport/__init__.py new file mode 100644 index 000000000..f57136ecf --- /dev/null +++ b/openlp/plugins/songs/lib/songimport/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`~openlp.plugins.songs.lib.import` module contains a importers for the Songs plugin. +""" diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/songimport/cclifileimport.py similarity index 100% rename from openlp/plugins/songs/lib/cclifileimport.py rename to openlp/plugins/songs/lib/songimport/cclifileimport.py diff --git a/openlp/plugins/songs/lib/dreambeamimport.py b/openlp/plugins/songs/lib/songimport/dreambeamimport.py similarity index 99% rename from openlp/plugins/songs/lib/dreambeamimport.py rename to openlp/plugins/songs/lib/songimport/dreambeamimport.py index 375867aac..e5afd65f4 100644 --- a/openlp/plugins/songs/lib/dreambeamimport.py +++ b/openlp/plugins/songs/lib/songimport/dreambeamimport.py @@ -35,7 +35,7 @@ import logging from lxml import etree, objectify from openlp.core.lib import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/easyslidesimport.py b/openlp/plugins/songs/lib/songimport/easyslidesimport.py similarity index 99% rename from openlp/plugins/songs/lib/easyslidesimport.py rename to openlp/plugins/songs/lib/songimport/easyslidesimport.py index ca9a9b755..f30ae49e5 100644 --- a/openlp/plugins/songs/lib/easyslidesimport.py +++ b/openlp/plugins/songs/lib/songimport/easyslidesimport.py @@ -33,7 +33,7 @@ import re from lxml import etree, objectify from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/songimport/ewimport.py similarity index 100% rename from openlp/plugins/songs/lib/ewimport.py rename to openlp/plugins/songs/lib/songimport/ewimport.py diff --git a/openlp/plugins/songs/lib/foilpresenterimport.py b/openlp/plugins/songs/lib/songimport/foilpresenterimport.py similarity index 99% rename from openlp/plugins/songs/lib/foilpresenterimport.py rename to openlp/plugins/songs/lib/songimport/foilpresenterimport.py index 2b31718c2..67911de76 100644 --- a/openlp/plugins/songs/lib/foilpresenterimport.py +++ b/openlp/plugins/songs/lib/songimport/foilpresenterimport.py @@ -99,10 +99,10 @@ from lxml import etree, objectify from openlp.core.lib import translate from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport from openlp.plugins.songs.lib.db import Author, Book, Song, Topic from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.xml import SongXML +from openlp.plugins.songs.lib.openlyricsxml import SongXML log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/mediashoutimport.py b/openlp/plugins/songs/lib/songimport/mediashoutimport.py similarity index 98% rename from openlp/plugins/songs/lib/mediashoutimport.py rename to openlp/plugins/songs/lib/songimport/mediashoutimport.py index 99850e950..8eab61a96 100644 --- a/openlp/plugins/songs/lib/mediashoutimport.py +++ b/openlp/plugins/songs/lib/songimport/mediashoutimport.py @@ -33,7 +33,7 @@ a MediaShout database into the OpenLP database. import pyodbc from openlp.core.lib import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E'] diff --git a/openlp/plugins/songs/lib/olpimport.py b/openlp/plugins/songs/lib/songimport/olpimport.py similarity index 100% rename from openlp/plugins/songs/lib/olpimport.py rename to openlp/plugins/songs/lib/songimport/olpimport.py diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/songimport/oooimport.py similarity index 100% rename from openlp/plugins/songs/lib/oooimport.py rename to openlp/plugins/songs/lib/songimport/oooimport.py diff --git a/openlp/plugins/songs/lib/openlyricsimport.py b/openlp/plugins/songs/lib/songimport/openlyricsimport.py similarity index 96% rename from openlp/plugins/songs/lib/openlyricsimport.py rename to openlp/plugins/songs/lib/songimport/openlyricsimport.py index 031c5ba72..74329bfd8 100644 --- a/openlp/plugins/songs/lib/openlyricsimport.py +++ b/openlp/plugins/songs/lib/songimport/openlyricsimport.py @@ -37,9 +37,9 @@ import os from lxml import etree from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.xml import OpenLyrics, OpenLyricsError +from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, OpenLyricsError log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/songimport/opensongimport.py similarity index 99% rename from openlp/plugins/songs/lib/opensongimport.py rename to openlp/plugins/songs/lib/songimport/opensongimport.py index 3d9733dd8..a52b67b0f 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/songimport/opensongimport.py @@ -35,7 +35,7 @@ from lxml.etree import Error, LxmlError from openlp.core.common import translate from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/powersongimport.py b/openlp/plugins/songs/lib/songimport/powersongimport.py similarity index 99% rename from openlp/plugins/songs/lib/powersongimport.py rename to openlp/plugins/songs/lib/songimport/powersongimport.py index cd568bc2c..1cad5e33e 100644 --- a/openlp/plugins/songs/lib/powersongimport.py +++ b/openlp/plugins/songs/lib/songimport/powersongimport.py @@ -35,7 +35,7 @@ import fnmatch import os from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/propresenterimport.py b/openlp/plugins/songs/lib/songimport/propresenterimport.py similarity index 100% rename from openlp/plugins/songs/lib/propresenterimport.py rename to openlp/plugins/songs/lib/songimport/propresenterimport.py diff --git a/openlp/plugins/songs/lib/sofimport.py b/openlp/plugins/songs/lib/songimport/sofimport.py similarity index 100% rename from openlp/plugins/songs/lib/sofimport.py rename to openlp/plugins/songs/lib/songimport/sofimport.py diff --git a/openlp/plugins/songs/lib/songbeamerimport.py b/openlp/plugins/songs/lib/songimport/songbeamerimport.py similarity index 99% rename from openlp/plugins/songs/lib/songbeamerimport.py rename to openlp/plugins/songs/lib/songimport/songbeamerimport.py index 9c5e74c06..fbd016cda 100644 --- a/openlp/plugins/songs/lib/songbeamerimport.py +++ b/openlp/plugins/songs/lib/songimport/songbeamerimport.py @@ -36,7 +36,7 @@ import os import re from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport/songimport.py similarity index 99% rename from openlp/plugins/songs/lib/songimport.py rename to openlp/plugins/songs/lib/songimport/songimport.py index b8fcc604b..5382efbe5 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport/songimport.py @@ -39,7 +39,7 @@ from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.xml import SongXML +from openlp.plugins.songs.lib.openlyricsxml import SongXML log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songproimport.py b/openlp/plugins/songs/lib/songimport/songproimport.py similarity index 98% rename from openlp/plugins/songs/lib/songproimport.py rename to openlp/plugins/songs/lib/songimport/songproimport.py index 86411a499..853a1d9eb 100644 --- a/openlp/plugins/songs/lib/songproimport.py +++ b/openlp/plugins/songs/lib/songimport/songproimport.py @@ -33,7 +33,7 @@ songs into the OpenLP database. import re from openlp.plugins.songs.lib import strip_rtf -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport class SongProImport(SongImport): diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songimport/songshowplusimport.py similarity index 99% rename from openlp/plugins/songs/lib/songshowplusimport.py rename to openlp/plugins/songs/lib/songimport/songshowplusimport.py index aebded029..352e55d96 100644 --- a/openlp/plugins/songs/lib/songshowplusimport.py +++ b/openlp/plugins/songs/lib/songimport/songshowplusimport.py @@ -38,7 +38,7 @@ import struct from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport TITLE = 1 AUTHOR = 2 diff --git a/openlp/plugins/songs/lib/sundayplusimport.py b/openlp/plugins/songs/lib/songimport/sundayplusimport.py similarity index 99% rename from openlp/plugins/songs/lib/sundayplusimport.py rename to openlp/plugins/songs/lib/songimport/sundayplusimport.py index 5c5f73047..fded3bca3 100644 --- a/openlp/plugins/songs/lib/sundayplusimport.py +++ b/openlp/plugins/songs/lib/songimport/sundayplusimport.py @@ -32,7 +32,7 @@ import re from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib import strip_rtf -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport HOTKEY_TO_VERSE_TYPE = { '1': 'v1', diff --git a/openlp/plugins/songs/lib/worshipassistantimport.py b/openlp/plugins/songs/lib/songimport/worshipassistantimport.py similarity index 99% rename from openlp/plugins/songs/lib/worshipassistantimport.py rename to openlp/plugins/songs/lib/songimport/worshipassistantimport.py index 772fe8622..412a17c35 100644 --- a/openlp/plugins/songs/lib/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/songimport/worshipassistantimport.py @@ -37,7 +37,7 @@ import re from openlp.core.common import translate from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/worshipcenterproimport.py b/openlp/plugins/songs/lib/songimport/worshipcenterproimport.py similarity index 98% rename from openlp/plugins/songs/lib/worshipcenterproimport.py rename to openlp/plugins/songs/lib/songimport/worshipcenterproimport.py index b24d2ae83..b6c32a8c0 100644 --- a/openlp/plugins/songs/lib/worshipcenterproimport.py +++ b/openlp/plugins/songs/lib/songimport/worshipcenterproimport.py @@ -35,7 +35,7 @@ import logging import pyodbc from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/songimport/wowimport.py similarity index 99% rename from openlp/plugins/songs/lib/wowimport.py rename to openlp/plugins/songs/lib/songimport/wowimport.py index c92b0ee2a..c135ca620 100644 --- a/openlp/plugins/songs/lib/wowimport.py +++ b/openlp/plugins/songs/lib/songimport/wowimport.py @@ -34,7 +34,7 @@ import os import logging from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport BLOCK_TYPES = ('V', 'C', 'B') diff --git a/openlp/plugins/songs/lib/zionworximport.py b/openlp/plugins/songs/lib/songimport/zionworximport.py similarity index 98% rename from openlp/plugins/songs/lib/zionworximport.py rename to openlp/plugins/songs/lib/songimport/zionworximport.py index dfdc2373d..8d939f244 100644 --- a/openlp/plugins/songs/lib/zionworximport.py +++ b/openlp/plugins/songs/lib/songimport/zionworximport.py @@ -34,7 +34,7 @@ import csv import logging from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index 6fd084a47..61b02a66e 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -38,7 +38,7 @@ from html.parser import HTMLParser from bs4 import BeautifulSoup, NavigableString from openlp.plugins.songs.lib import Song, VerseType, clean_song, Author -from openlp.plugins.songs.lib.xml import SongXML +from openlp.plugins.songs.lib.openlyricsxml import SongXML USER_AGENT = 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9000 ' \ 'Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 ' \ diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 79fc282a6..c97e3835f 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -49,7 +49,7 @@ from openlp.plugins.songs.lib import clean_song, upgrade from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.mediaitem import SongSearch from openlp.plugins.songs.lib.importer import SongFormat -from openlp.plugins.songs.lib.olpimport import OpenLPSongImport +from openlp.plugins.songs.lib.songimport.olpimport import OpenLPSongImport from openlp.plugins.songs.lib.mediaitem import SongMediaItem from openlp.plugins.songs.lib.songstab import SongsTab diff --git a/tests/functional/openlp_plugins/songs/test_ewimport.py b/tests/functional/openlp_plugins/songs/test_ewimport.py index ea557711b..c28dc72aa 100644 --- a/tests/functional/openlp_plugins/songs/test_ewimport.py +++ b/tests/functional/openlp_plugins/songs/test_ewimport.py @@ -35,7 +35,7 @@ from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.ewimport import EasyWorshipSongImport, FieldDescEntry, FieldType +from openlp.plugins.songs.lib.songimport.ewimport import EasyWorshipSongImport, FieldDescEntry, FieldType TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs')) @@ -178,7 +178,7 @@ class TestEasyWorshipSongImport(TestCase): Test creating an instance of the EasyWorship file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -192,7 +192,7 @@ class TestEasyWorshipSongImport(TestCase): Test finding an existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions. - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.field_descriptions = TEST_FIELD_DESCS @@ -210,7 +210,7 @@ class TestEasyWorshipSongImport(TestCase): Test finding an non-existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.field_descriptions = TEST_FIELD_DESCS @@ -228,8 +228,8 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of # field descriptions - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -246,7 +246,7 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`get_field` module """ # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.encoding = TEST_DATA_ENCODING @@ -269,7 +269,7 @@ class TestEasyWorshipSongImport(TestCase): """ for test_results in GET_MEMO_FIELD_TEST_RESULTS: # GIVEN: A mocked out SongImport class, a mocked out "manager", a mocked out memo_file and an encoding - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() mocked_memo_file = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -300,8 +300,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module opens the correct files """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.side_effect = [True, False] @@ -319,8 +319,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module produces an error when Songs.MB not found. """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.log_error = MagicMock() @@ -339,8 +339,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module handles invalid database files correctly """ # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.return_value = True @@ -358,10 +358,10 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module handles invalid memo files correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path, \ patch('builtins.open') as mocked_open, \ - patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct: + patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.return_value = True @@ -385,10 +385,10 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` converts the code page to the encoding correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.os.path') as mocked_os_path, \ - patch('builtins.open'), patch('openlp.plugins.songs.lib.ewimport.struct') as mocked_struct, \ - patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \ + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path, \ + patch('builtins.open'), patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct, \ + patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -413,8 +413,8 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') as \ + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_manager = MagicMock() @@ -469,8 +469,8 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.ewimport.retrieve_windows_encoding') \ + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') \ as mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_manager = MagicMock() @@ -509,7 +509,7 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and mocked out "author" method. - with patch('openlp.plugins.songs.lib.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): mocked_manager = MagicMock() mocked_add_author = MagicMock() importer = EasyWorshipSongImportLogger(mocked_manager) diff --git a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py index 61206b9fa..15247a361 100644 --- a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.functional import patch, MagicMock -from openlp.plugins.songs.lib.foilpresenterimport import FoilPresenter +from openlp.plugins.songs.lib.songimport.foilpresenterimport import FoilPresenter TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', '/resources/foilpresentersongs')) @@ -57,27 +57,27 @@ class TestFoilPresenter(TestCase): # _process_topics def setUp(self): - self.child_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._child') - self.clean_song_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.clean_song') - self.objectify_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.objectify') + self.child_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._child') + self.clean_song_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.clean_song') + self.objectify_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.objectify') self.process_authors_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_authors') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_authors') self.process_cclinumber_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_cclinumber') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_cclinumber') self.process_comments_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_comments') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_comments') self.process_lyrics_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_lyrics') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_lyrics') self.process_songbooks_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_songbooks') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_songbooks') self.process_titles_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_titles') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_titles') self.process_topics_patcher = \ - patch('openlp.plugins.songs.lib.foilpresenterimport.FoilPresenter._process_topics') - self.re_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.re') - self.song_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.Song') - self.song_xml_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.SongXML') - self.translate_patcher = patch('openlp.plugins.songs.lib.foilpresenterimport.translate') + patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_topics') + self.re_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.re') + self.song_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.Song') + self.song_xml_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.SongXML') + self.translate_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.translate') self.mocked_child = self.child_patcher.start() self.mocked_clean_song = self.clean_song_patcher.start() diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py index 93ecafb78..2166b950c 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py @@ -34,8 +34,8 @@ import os from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.openlyricsimport import OpenLyricsImport -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.openlyricsimport import OpenLyricsImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'openlyricssongs')) @@ -69,7 +69,7 @@ class TestOpenLyricsImport(TestCase): Test creating an instance of the OpenLyrics file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.openlyricsimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 96d6bff0b..8e7fee0af 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- + # -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 ############################################################################### @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.helpers.songfileimport import SongImportTestHelper -from openlp.plugins.songs.lib.opensongimport import OpenSongImport +from openlp.plugins.songs.lib.songimport.opensongimport import OpenSongImport from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath( @@ -69,7 +69,7 @@ class TestOpenSongImport(TestCase): Test creating an instance of the OpenSong file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -83,7 +83,7 @@ class TestOpenSongImport(TestCase): Test OpenSongImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = OpenSongImport(mocked_manager, filenames=[]) @@ -104,7 +104,7 @@ class TestOpenSongImport(TestCase): Test OpenSongImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = OpenSongImport(mocked_manager, filenames=[]) diff --git a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py index a69d4a86c..9ca0ab790 100644 --- a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py +++ b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.songbeamerimport import SongBeamerImport +from openlp.plugins.songs.lib.songimport.songbeamerimport import SongBeamerImport from openlp.plugins.songs.lib import VerseType TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), @@ -64,7 +64,7 @@ class TestSongBeamerImport(TestCase): Test creating an instance of the SongBeamer file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -78,7 +78,7 @@ class TestSongBeamerImport(TestCase): Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongBeamerImport(mocked_manager, filenames=[]) @@ -99,7 +99,7 @@ class TestSongBeamerImport(TestCase): Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongBeamerImport(mocked_manager, filenames=[]) @@ -122,7 +122,7 @@ class TestSongBeamerImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): for song_file in SONG_TEST_DATA: mocked_manager = MagicMock() mocked_import_wizard = MagicMock() diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index dfee265e3..8d6a42287 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -35,7 +35,7 @@ from unittest import TestCase from tests.helpers.songfileimport import SongImportTestHelper from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songshowplusimport import SongShowPlusImport +from openlp.plugins.songs.lib.songimport.songshowplusimport import SongShowPlusImport from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath( @@ -70,7 +70,7 @@ class TestSongShowPlusImport(TestCase): Test creating an instance of the SongShow Plus file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -84,7 +84,7 @@ class TestSongShowPlusImport(TestCase): Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -105,7 +105,7 @@ class TestSongShowPlusImport(TestCase): Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -126,7 +126,7 @@ class TestSongShowPlusImport(TestCase): Test to_openlp_verse_tag method by simulating adding a verse """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): mocked_manager = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -154,7 +154,7 @@ class TestSongShowPlusImport(TestCase): Test to_openlp_verse_tag method by simulating adding a verse to the verse order """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): mocked_manager = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 9a58a6c2b..263397cc9 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -37,7 +37,7 @@ if os.name != 'nt': import pyodbc -from openlp.plugins.songs.lib.worshipcenterproimport import WorshipCenterProImport +from openlp.plugins.songs.lib.songimport.worshipcenterproimport import WorshipCenterProImport from tests.functional import patch, MagicMock @@ -141,7 +141,7 @@ class TestWorshipCenterProSongImport(TestCase): Test creating an instance of the WorshipCenter Pro file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/functional/openlp_plugins/songs/test_zionworximport.py b/tests/functional/openlp_plugins/songs/test_zionworximport.py index c5669e9c8..a3f5bb20b 100644 --- a/tests/functional/openlp_plugins/songs/test_zionworximport.py +++ b/tests/functional/openlp_plugins/songs/test_zionworximport.py @@ -33,8 +33,8 @@ This module contains tests for the ZionWorx song importer. from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.zionworximport import ZionWorxImport -from openlp.plugins.songs.lib.songimport import SongImport +from openlp.plugins.songs.lib.songimport.zionworximport import ZionWorxImport +from openlp.plugins.songs.lib.songimport.songimport import SongImport class TestZionWorxImport(TestCase): @@ -46,7 +46,7 @@ class TestZionWorxImport(TestCase): Test creating an instance of the ZionWorx file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.zionworximport.SongImport'): + with patch('openlp.plugins.songs.lib.songimport.zionworximport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 80b2ee268..0b0e3515d 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -43,7 +43,7 @@ class SongImportTestHelper(TestCase): def __init__(self, *args, **kwargs): super(SongImportTestHelper, self).__init__(*args, **kwargs) self.importer_module = __import__( - 'openlp.plugins.songs.lib.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) + 'openlp.plugins.songs.lib.songimport.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) self.importer_class = getattr(self.importer_module, self.importer_class_name) def setUp(self): @@ -51,14 +51,14 @@ class SongImportTestHelper(TestCase): Patch and set up the mocks required. """ self.add_copyright_patcher = patch( - 'openlp.plugins.songs.lib.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name)) self.add_verse_patcher = patch( - 'openlp.plugins.songs.lib.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name)) self.finish_patcher = patch( - 'openlp.plugins.songs.lib.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.songimport.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) self.add_author_patcher = patch( - 'openlp.plugins.songs.lib.%s.%s.add_author' % (self.importer_module_name, self.importer_class_name)) - self.song_import_patcher = patch('openlp.plugins.songs.lib.%s.SongImport' % self.importer_module_name) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_author' % (self.importer_module_name, self.importer_class_name)) + self.song_import_patcher = patch('openlp.plugins.songs.lib.songimport.%s.SongImport' % self.importer_module_name) self.mocked_add_copyright = self.add_copyright_patcher.start() self.mocked_add_verse = self.add_verse_patcher.start() self.mocked_finish = self.finish_patcher.start() From 3b7d5f53babe6856d1b51e7e566071ed8a026269 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 3 Jul 2014 19:57:13 +0200 Subject: [PATCH 28/69] PEP8 --- openlp/plugins/songs/lib/songimport/__init__.py | 2 +- .../openlp_plugins/songs/test_opensongimport.py | 2 +- .../songs/test_worshipcenterproimport.py | 12 ++++++------ tests/helpers/songfileimport.py | 12 ++++++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/openlp/plugins/songs/lib/songimport/__init__.py b/openlp/plugins/songs/lib/songimport/__init__.py index f57136ecf..da302572e 100644 --- a/openlp/plugins/songs/lib/songimport/__init__.py +++ b/openlp/plugins/songs/lib/songimport/__init__.py @@ -27,5 +27,5 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`~openlp.plugins.songs.lib.import` module contains a importers for the Songs plugin. +The :mod:`~openlp.plugins.songs.lib.import` module contains importers for the Songs plugin. """ diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 8e7fee0af..09fad7bc3 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -1,4 +1,4 @@ - # -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 ############################################################################### diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 263397cc9..27c688aa0 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -156,9 +156,9 @@ class TestWorshipCenterProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method, # a mocked "manager" and a mocked out log_error method. - with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ - patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ - patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: + with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ + patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.translate') as mocked_translate: mocked_manager = MagicMock() mocked_log_error = MagicMock() mocked_translate.return_value = 'Translated Text' @@ -185,9 +185,9 @@ class TestWorshipCenterProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out # translate method, a mocked "manager", add_verse method & mocked_finish method. - with patch('openlp.plugins.songs.lib.worshipcenterproimport.SongImport'), \ - patch('openlp.plugins.songs.lib.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ - patch('openlp.plugins.songs.lib.worshipcenterproimport.translate') as mocked_translate: + with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'), \ + patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ + patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.translate') as mocked_translate: mocked_manager = MagicMock() mocked_import_wizard = MagicMock() mocked_add_verse = MagicMock() diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 0b0e3515d..003ade543 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -51,14 +51,18 @@ class SongImportTestHelper(TestCase): Patch and set up the mocks required. """ self.add_copyright_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_copyright' % (self.importer_module_name, + self.importer_class_name)) self.add_verse_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_verse' % (self.importer_module_name, + self.importer_class_name)) self.finish_patcher = patch( 'openlp.plugins.songs.lib.songimport.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) self.add_author_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_author' % (self.importer_module_name, self.importer_class_name)) - self.song_import_patcher = patch('openlp.plugins.songs.lib.songimport.%s.SongImport' % self.importer_module_name) + 'openlp.plugins.songs.lib.songimport.%s.%s.add_author' % (self.importer_module_name, + self.importer_class_name)) + self.song_import_patcher = patch('openlp.plugins.songs.lib.songimport.%s.SongImport' % + self.importer_module_name) self.mocked_add_copyright = self.add_copyright_patcher.start() self.mocked_add_verse = self.add_verse_patcher.start() self.mocked_finish = self.finish_patcher.start() From c9b47e8e6f89ffd12905ee55cb50680557c22cb9 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 3 Jul 2014 19:57:46 +0200 Subject: [PATCH 29/69] PEP8 --- .../openlp_plugins/songs/test_worshipcenterproimport.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 27c688aa0..0558ad195 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -157,7 +157,8 @@ class TestWorshipCenterProSongImport(TestCase): # GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method, # a mocked "manager" and a mocked out log_error method. with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc.connect') as mocked_pyodbc_connect, \ + patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc.connect') \ + as mocked_pyodbc_connect, \ patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.translate') as mocked_translate: mocked_manager = MagicMock() mocked_log_error = MagicMock() From 9f345523649b224c549f039fd899b7f96c87c5f0 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 3 Jul 2014 23:30:41 +0200 Subject: [PATCH 30/69] PowerPraise importer Fixes: https://launchpad.net/bugs/1336929 --- openlp/plugins/songs/lib/powerpraiseimport.py | 70 +++++++++++++++++++ .../songs/test_powerpraiseimport.py | 54 ++++++++++++++ .../songs/test_propresenterimport.py | 2 +- tests/helpers/songfileimport.py | 20 +++++- .../Näher, mein Gott zu Dir.json | 18 +++++ .../Näher, mein Gott zu Dir.ppl | 2 + 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 openlp/plugins/songs/lib/powerpraiseimport.py create mode 100644 tests/functional/openlp_plugins/songs/test_powerpraiseimport.py create mode 100644 tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json create mode 100644 tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.ppl diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py new file mode 100644 index 000000000..56ebff542 --- /dev/null +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`powerpraiseimport` module provides the functionality for importing +Powerpraise song files into the current database. +""" + +import os +import base64 +from lxml import objectify + +from openlp.core.ui.wizard import WizardStrings +from openlp.plugins.songs.lib import strip_rtf +from .songimport import SongImport + + +class PowerpraiseImport(SongImport): + """ + The :class:`PowerpraiseImport` class provides OpenLP with the + ability to import Powerpraise song files. + """ + def do_import(self): + self.import_wizard.progress_bar.setMaximum(len(self.import_source)) + for file_path in self.import_source: + if self.stop_import_flag: + return + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) + root = objectify.parse(open(file_path, 'rb')).getroot() + self.process_song(root) + + def process_song(self, root): + self.set_defaults() + self.title = root.general.title + count = 0; + for part in root.songtext.part: + verse_text = "" + count += 1 + for slide in part.slide: + for line in slide.line: + verse_text += line + print(verse_text) + self.add_verse(verse_text, "v%d" % count) + if not self.finish(): + self.log_error(self.import_source) diff --git a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py new file mode 100644 index 000000000..924cf127c --- /dev/null +++ b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`powerpraiseimport` module provides the functionality for importing +ProPresenter song files into the current installation database. +""" + +import os + +from tests.helpers.songfileimport import SongImportTestHelper + +TEST_PATH = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs')) + + +class TestPowerpraiseFileImport(SongImportTestHelper): + + def __init__(self, *args, **kwargs): + self.importer_class_name = 'PowerpraiseImport' + self.importer_module_name = 'powerpraiseimport' + super(TestPowerpraiseFileImport, self).__init__(*args, **kwargs) + + def test_song_import(self): + """ + Test that loading a PowerPraise file works correctly + """ + self.file_import([os.path.join(TEST_PATH, 'Näher, mein Gott zu Dir.ppl')], + self.load_external_result_data(os.path.join(TEST_PATH, 'Näher, mein Gott zu Dir.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_propresenterimport.py b/tests/functional/openlp_plugins/songs/test_propresenterimport.py index 10e2defc6..9f5760849 100644 --- a/tests/functional/openlp_plugins/songs/test_propresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_propresenterimport.py @@ -48,7 +48,7 @@ class TestProPresenterFileImport(SongImportTestHelper): def test_song_import(self): """ - Test that loading an ProPresenter file works correctly + Test that loading a ProPresenter file works correctly """ self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 80b2ee268..afa3e48bd 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -31,10 +31,13 @@ The :mod:`songfileimporthelper` modules provides a helper class and methods to e song files from third party applications. """ import json +import logging from unittest import TestCase from tests.functional import patch, MagicMock, call +log = logging.getLogger(__name__) + class SongImportTestHelper(TestCase): """ @@ -107,9 +110,21 @@ class SongImportTestHelper(TestCase): topics = self._get_data(result_data, 'topics') verse_order_list = self._get_data(result_data, 'verse_order_list') - # THEN: do_import should return none, the song data should be as expected, and finish should have been - # called. + # THEN: do_import should return none, the song data should be as expected, and finish should have been called. self.assertIsNone(importer.do_import(), 'do_import should return None when it has completed') + + # Debug information - will be displayed when the test fails + log.debug("Title imported: %s" % importer.title) + log.debug("Verses imported: %s" % self.mocked_add_verse.mock_calls) + log.debug("Verse order imported: %s" % importer.verse_order_list) + log.debug("Authors imported: %s" % self.mocked_add_author.mock_calls) + log.debug("CCLI No. imported: %s" % importer.ccli_number) + log.debug("Comments imported: %s" % importer.comments) + log.debug("Songbook imported: %s" % importer.song_book_name) + log.debug("Song number imported: %s" % importer.song_number) + log.debug("Song copyright imported: %s" % importer.song_number) + log.debug("Topics imported: %s" % importer.topics) + self.assertEqual(importer.title, title, 'title for %s should be "%s"' % (source_file_name, title)) for author in author_calls: self.mocked_add_author.assert_any_call(author) @@ -119,6 +134,7 @@ class SongImportTestHelper(TestCase): self.assertEqual(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' % (source_file_name, ccli_number)) expected_calls = [] + print(self.mocked_add_verse.mock_calls) for verse_text, verse_tag in add_verse_calls: self.mocked_add_verse.assert_any_call(verse_text, verse_tag) expected_calls.append(call(verse_text, verse_tag)) diff --git a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json new file mode 100644 index 000000000..54094f748 --- /dev/null +++ b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json @@ -0,0 +1,18 @@ +{ + "title": "Näher, mein Gott, zu Dir", + "verse_order_list": [], + "verses": [ + [ + "Näher, mein Gott, zu Dir,sei meine Bitt'!Näher, o Herr, zu Dirmit jedem Schritt.Nur an dem Herzen Deinkann ich geborgen sein;deshalb die Bitte mein:Näher zu Dir!", + "v1" + ], + [ + "Näher, mein Gott, zu Dir!Ein jeder Tagsoll es neu zeigen mir,was er vermag:Wie seiner Gnade Macht,Erlösung hat gebracht,in uns're Sündennacht.Näher zu Dir!", + "v2" + ], + [ + "Näher, mein Gott, zu Dir!Dich bet' ich an.Wie vieles hast an mir,Du doch getan!Von Banden frei und los,ruh' ich in Deinem Schoss.Ja, Deine Gnad' ist gross!Näher zu Dir!", + "v3" + ] + ] +} \ No newline at end of file diff --git a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.ppl b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.ppl new file mode 100644 index 000000000..c0c7f8c19 --- /dev/null +++ b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.ppl @@ -0,0 +1,2 @@ + +Näher, mein Gott, zu DirAnbetungDeutschNäher, mein Gott, zu Dir,sei meine Bitt'!Näher, o Herr, zu Dirmit jedem Schritt.Nur an dem Herzen Deinkann ich geborgen sein;deshalb die Bitte mein:Näher zu Dir!Näher, mein Gott, zu Dir!Ein jeder Tagsoll es neu zeigen mir,was er vermag:Wie seiner Gnade Macht,Erlösung hat gebracht,in uns're Sündennacht.Näher zu Dir!Näher, mein Gott, zu Dir!Dich bet' ich an.Wie vieles hast an mir,Du doch getan!Von Banden frei und los,ruh' ich in Deinem Schoss.Ja, Deine Gnad' ist gross!Näher zu Dir!Teil 1Teil 2Teil 3lastslideText und Musik: Lowell Mason, 1792-1872firstslidegrünes Buch 339Times New Roman44truetrue167772153015Times New Roman20falsefalse167772153020Times New Roman14falsefalse167772153020Times New Roman30falsefalse167772153020false0true0125Blumen\Blume 3.jpg
30
20
leftcenterinline50406070302040
From 7112356c21d65e48bbbbf5b539bd2a4eb573179d Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 3 Jul 2014 23:48:52 +0200 Subject: [PATCH 31/69] Parse verse order --- openlp/plugins/songs/lib/powerpraiseimport.py | 19 +++++++++++++++---- tests/helpers/songfileimport.py | 1 - .../Näher, mein Gott zu Dir.json | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py index 56ebff542..27b9c5c17 100644 --- a/openlp/plugins/songs/lib/powerpraiseimport.py +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -57,14 +57,25 @@ class PowerpraiseImport(SongImport): def process_song(self, root): self.set_defaults() self.title = root.general.title - count = 0; + verse_order_list = [] + for item in root.order.item: + verse_order_list.append(str(item)) + + count = 0 for part in root.songtext.part: - verse_text = "" count += 1 + verse_def = "v%d" % count + original_verse_def = part.get('caption') + verse_text = "" for slide in part.slide: for line in slide.line: verse_text += line - print(verse_text) - self.add_verse(verse_text, "v%d" % count) + self.add_verse(verse_text, verse_def) + # Update verse name in verse order list + for i in range(len(verse_order_list)): + if verse_order_list[i].lower() == original_verse_def.lower(): + verse_order_list[i] = verse_def + + self.verse_order_list = verse_order_list if not self.finish(): self.log_error(self.import_source) diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index afa3e48bd..613bb5c96 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -134,7 +134,6 @@ class SongImportTestHelper(TestCase): self.assertEqual(importer.ccli_number, ccli_number, 'ccli_number for %s should be %s' % (source_file_name, ccli_number)) expected_calls = [] - print(self.mocked_add_verse.mock_calls) for verse_text, verse_tag in add_verse_calls: self.mocked_add_verse.assert_any_call(verse_text, verse_tag) expected_calls.append(call(verse_text, verse_tag)) diff --git a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json index 54094f748..b3200ba00 100644 --- a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json +++ b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json @@ -1,6 +1,6 @@ { "title": "Näher, mein Gott, zu Dir", - "verse_order_list": [], + "verse_order_list": ["v1", "v2", "v3"], "verses": [ [ "Näher, mein Gott, zu Dir,sei meine Bitt'!Näher, o Herr, zu Dirmit jedem Schritt.Nur an dem Herzen Deinkann ich geborgen sein;deshalb die Bitte mein:Näher zu Dir!", From 87eb8804de277b90e1e8dde0f33d8da9877ee6aa Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 00:06:18 +0200 Subject: [PATCH 32/69] Fixes --- openlp/plugins/songs/lib/importer.py | 31 ++++++++++++------- openlp/plugins/songs/lib/powerpraiseimport.py | 12 ++++--- .../songs/test_powerpraiseimport.py | 6 ++-- .../Näher, mein Gott zu Dir.json | 6 ++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 6d01da309..659d64d3e 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -51,6 +51,7 @@ from .foilpresenterimport import FoilPresenterImport from .zionworximport import ZionWorxImport from .propresenterimport import ProPresenterImport from .worshipassistantimport import WorshipAssistantImport +from .powerpraiseimport import PowerPraiseImport # Imports that might fail @@ -160,17 +161,18 @@ class SongFormat(object): FoilPresenter = 8 MediaShout = 9 OpenSong = 10 - PowerSong = 11 - ProPresenter = 12 - SongBeamer = 13 - SongPro = 14 - SongShowPlus = 15 - SongsOfFellowship = 16 - SundayPlus = 17 - WordsOfWorship = 18 - WorshipAssistant = 19 - WorshipCenterPro = 20 - ZionWorx = 21 + PowerPraise = 11 + PowerSong = 12 + ProPresenter = 13 + SongBeamer = 14 + SongPro = 15 + SongShowPlus = 16 + SongsOfFellowship = 17 + SundayPlus = 18 + WordsOfWorship = 19 + WorshipAssistant = 20 + WorshipCenterPro = 21 + ZionWorx = 22 # Set optional attribute defaults __defaults__ = { @@ -266,6 +268,12 @@ class SongFormat(object): 'name': WizardStrings.OS, 'prefix': 'openSong' }, + PowerPraise: { + 'class': PowerPraiseImport, + 'name': 'PowerPraise', + 'prefix': 'powerPraise', + 'filter': '%s (*.ppl)' % translate('SongsPlugin.ImportWizardForm', 'PowerPraise Song Files') + }, PowerSong: { 'class': PowerSongImport, 'name': 'PowerSong 1.0', @@ -374,6 +382,7 @@ class SongFormat(object): SongFormat.FoilPresenter, SongFormat.MediaShout, SongFormat.OpenSong, + SongFormat.PowerPraise, SongFormat.PowerSong, SongFormat.ProPresenter, SongFormat.SongBeamer, diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py index 27b9c5c17..0e7bcd9af 100644 --- a/openlp/plugins/songs/lib/powerpraiseimport.py +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -40,7 +40,7 @@ from openlp.plugins.songs.lib import strip_rtf from .songimport import SongImport -class PowerpraiseImport(SongImport): +class PowerPraiseImport(SongImport): """ The :class:`PowerpraiseImport` class provides OpenLP with the ability to import Powerpraise song files. @@ -56,7 +56,7 @@ class PowerpraiseImport(SongImport): def process_song(self, root): self.set_defaults() - self.title = root.general.title + self.title = str(root.general.title) verse_order_list = [] for item in root.order.item: verse_order_list.append(str(item)) @@ -66,11 +66,13 @@ class PowerpraiseImport(SongImport): count += 1 verse_def = "v%d" % count original_verse_def = part.get('caption') - verse_text = "" + verse_text = [] for slide in part.slide: + if not hasattr(slide, 'line'): + continue # No content for line in slide.line: - verse_text += line - self.add_verse(verse_text, verse_def) + verse_text.append(str(line)) + self.add_verse('\n'.join(verse_text), verse_def) # Update verse name in verse order list for i in range(len(verse_order_list)): if verse_order_list[i].lower() == original_verse_def.lower(): diff --git a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py index 924cf127c..2d5a42e6f 100644 --- a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py +++ b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py @@ -39,12 +39,12 @@ TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs')) -class TestPowerpraiseFileImport(SongImportTestHelper): +class TestPowerPraiseFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): - self.importer_class_name = 'PowerpraiseImport' + self.importer_class_name = 'PowerPraiseImport' self.importer_module_name = 'powerpraiseimport' - super(TestPowerpraiseFileImport, self).__init__(*args, **kwargs) + super(TestPowerPraiseFileImport, self).__init__(*args, **kwargs) def test_song_import(self): """ diff --git a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json index b3200ba00..7f258f9e9 100644 --- a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json +++ b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json @@ -3,15 +3,15 @@ "verse_order_list": ["v1", "v2", "v3"], "verses": [ [ - "Näher, mein Gott, zu Dir,sei meine Bitt'!Näher, o Herr, zu Dirmit jedem Schritt.Nur an dem Herzen Deinkann ich geborgen sein;deshalb die Bitte mein:Näher zu Dir!", + "Näher, mein Gott, zu Dir,\nsei meine Bitt'!\nNäher, o Herr, zu Dir\nmit jedem Schritt.\nNur an dem Herzen Dein\nkann ich geborgen sein;\ndeshalb die Bitte mein:\nNäher zu Dir!", "v1" ], [ - "Näher, mein Gott, zu Dir!Ein jeder Tagsoll es neu zeigen mir,was er vermag:Wie seiner Gnade Macht,Erlösung hat gebracht,in uns're Sündennacht.Näher zu Dir!", + "Näher, mein Gott, zu Dir!\nEin jeder Tag\nsoll es neu zeigen mir,\nwas er vermag:\nWie seiner Gnade Macht,\nErlösung hat gebracht,\nin uns're Sündennacht.\nNäher zu Dir!", "v2" ], [ - "Näher, mein Gott, zu Dir!Dich bet' ich an.Wie vieles hast an mir,Du doch getan!Von Banden frei und los,ruh' ich in Deinem Schoss.Ja, Deine Gnad' ist gross!Näher zu Dir!", + "Näher, mein Gott, zu Dir!\nDich bet' ich an.\nWie vieles hast an mir,\nDu doch getan!\nVon Banden frei und los,\nruh' ich in Deinem Schoss.\nJa, Deine Gnad' ist gross!\nNäher zu Dir!", "v3" ] ] From 953adf714595923601be7b288b39bec3d5a39dce Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 10:35:24 +0200 Subject: [PATCH 33/69] A blank line! --- openlp/plugins/songs/lib/powerpraiseimport.py | 1 - tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py index 0e7bcd9af..ecf1c55fb 100644 --- a/openlp/plugins/songs/lib/powerpraiseimport.py +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -60,7 +60,6 @@ class PowerPraiseImport(SongImport): verse_order_list = [] for item in root.order.item: verse_order_list.append(str(item)) - count = 0 for part in root.songtext.part: count += 1 diff --git a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json index 7f258f9e9..630b71949 100644 --- a/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json +++ b/tests/resources/powerpraisesongs/Näher, mein Gott zu Dir.json @@ -15,4 +15,4 @@ "v3" ] ] -} \ No newline at end of file +} From 686f8d243746404c7e3dd70c979b25c531798a78 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 11:31:06 +0200 Subject: [PATCH 34/69] More renaming --- openlp/plugins/songs/lib/importer.py | 54 +++++++++---------- .../lib/{songimport => importers}/__init__.py | 0 .../cclifile.py} | 0 .../dreambeam.py} | 2 +- .../easyslides.py} | 2 +- .../ewimport.py => importers/easyworship.py} | 0 .../foilpresenter.py} | 2 +- .../mediashout.py} | 2 +- .../olpimport.py => importers/openlp.py} | 0 .../openlyrics.py} | 2 +- .../oooimport.py => importers/openoffice.py} | 2 +- .../opensong.py} | 2 +- .../powersong.py} | 4 +- .../propresenter.py} | 0 .../songbeamer.py} | 2 +- .../{songimport => importers}/songimport.py | 0 .../songproimport.py => importers/songpro.py} | 2 +- .../songshowplus.py} | 2 +- .../songsoffellowship.py} | 8 +-- .../sundayplus.py} | 2 +- .../wordsofworship.py} | 4 +- .../worshipassistant.py} | 4 +- .../worshipcenterpro.py} | 2 +- .../zionworx.py} | 2 +- openlp/plugins/songs/songsplugin.py | 2 +- .../openlp_plugins/songs/test_ewimport.py | 52 +++++++++--------- .../songs/test_foilpresenterimport.py | 30 +++++------ .../songs/test_openlyricsimport.py | 6 +-- .../songs/test_opensongimport.py | 10 ++-- .../songs/test_propresenterimport.py | 2 +- .../songs/test_songbeamerimport.py | 10 ++-- .../songs/test_songshowplusimport.py | 14 ++--- .../songs/test_worshipassistantimport.py | 2 +- .../songs/test_worshipcenterproimport.py | 16 +++--- .../songs/test_zionworximport.py | 6 +-- tests/helpers/songfileimport.py | 12 ++--- 36 files changed, 131 insertions(+), 131 deletions(-) rename openlp/plugins/songs/lib/{songimport => importers}/__init__.py (100%) rename openlp/plugins/songs/lib/{songimport/cclifileimport.py => importers/cclifile.py} (100%) rename openlp/plugins/songs/lib/{songimport/dreambeamimport.py => importers/dreambeam.py} (99%) rename openlp/plugins/songs/lib/{songimport/easyslidesimport.py => importers/easyslides.py} (99%) rename openlp/plugins/songs/lib/{songimport/ewimport.py => importers/easyworship.py} (100%) rename openlp/plugins/songs/lib/{songimport/foilpresenterimport.py => importers/foilpresenter.py} (99%) rename openlp/plugins/songs/lib/{songimport/mediashoutimport.py => importers/mediashout.py} (98%) rename openlp/plugins/songs/lib/{songimport/olpimport.py => importers/openlp.py} (100%) rename openlp/plugins/songs/lib/{songimport/openlyricsimport.py => importers/openlyrics.py} (98%) rename openlp/plugins/songs/lib/{songimport/oooimport.py => importers/openoffice.py} (99%) rename openlp/plugins/songs/lib/{songimport/opensongimport.py => importers/opensong.py} (99%) rename openlp/plugins/songs/lib/{songimport/powersongimport.py => importers/powersong.py} (98%) rename openlp/plugins/songs/lib/{songimport/propresenterimport.py => importers/propresenter.py} (100%) rename openlp/plugins/songs/lib/{songimport/songbeamerimport.py => importers/songbeamer.py} (99%) rename openlp/plugins/songs/lib/{songimport => importers}/songimport.py (100%) rename openlp/plugins/songs/lib/{songimport/songproimport.py => importers/songpro.py} (98%) rename openlp/plugins/songs/lib/{songimport/songshowplusimport.py => importers/songshowplus.py} (99%) rename openlp/plugins/songs/lib/{songimport/sofimport.py => importers/songsoffellowship.py} (98%) rename openlp/plugins/songs/lib/{songimport/sundayplusimport.py => importers/sundayplus.py} (99%) rename openlp/plugins/songs/lib/{songimport/wowimport.py => importers/wordsofworship.py} (98%) rename openlp/plugins/songs/lib/{songimport/worshipassistantimport.py => importers/worshipassistant.py} (98%) rename openlp/plugins/songs/lib/{songimport/worshipcenterproimport.py => importers/worshipcenterpro.py} (98%) rename openlp/plugins/songs/lib/{songimport/zionworximport.py => importers/zionworx.py} (98%) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 9c0b889ca..bb622bcf9 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -34,23 +34,23 @@ import logging from openlp.core.common import translate, UiStrings from openlp.core.ui.wizard import WizardStrings -from .songimport.opensongimport import OpenSongImport -from .songimport.easyslidesimport import EasySlidesImport -from .songimport.olpimport import OpenLPSongImport -from .songimport.openlyricsimport import OpenLyricsImport -from .songimport.wowimport import WowImport -from .songimport.cclifileimport import CCLIFileImport -from .songimport.dreambeamimport import DreamBeamImport -from .songimport.powersongimport import PowerSongImport -from .songimport.ewimport import EasyWorshipSongImport -from .songimport.songbeamerimport import SongBeamerImport -from .songimport.songshowplusimport import SongShowPlusImport -from .songimport.songproimport import SongProImport -from .songimport.sundayplusimport import SundayPlusImport -from .songimport.foilpresenterimport import FoilPresenterImport -from .songimport.zionworximport import ZionWorxImport -from .songimport.propresenterimport import ProPresenterImport -from .songimport.worshipassistantimport import WorshipAssistantImport +from .importers.opensong import OpenSongImport +from .importers.easyslides import EasySlidesImport +from .importers.openlp import OpenLPSongImport +from .importers.openlyrics import OpenLyricsImport +from .importers.wordsofworship import WordsOfWorshipImport +from .importers.cclifile import CCLIFileImport +from .importers.dreambeam import DreamBeamImport +from .importers.powersong import PowerSongImport +from .importers.easyworship import EasyWorshipSongImport +from .importers.songbeamer import SongBeamerImport +from .importers.songshowplus import SongShowPlusImport +from .importers.songpro import SongProImport +from .importers.sundayplus import SundayPlusImport +from .importers.foilpresenter import FoilPresenterImport +from .importers.zionworx import ZionWorxImport +from .importers.propresenter import ProPresenterImport +from .importers.worshipassistant import WorshipAssistantImport # Imports that might fail @@ -58,13 +58,13 @@ log = logging.getLogger(__name__) try: - from .sofimport import SofImport + from .importers.songsoffellowship import SongsOfFellowshipImport HAS_SOF = True except ImportError: - log.exception('Error importing %s', 'SofImport') + log.exception('Error importing %s', 'SongsOfFellowshipImport') HAS_SOF = False try: - from .oooimport import OooImport + from .importers.openoffice import OpenOfficeImport HAS_OOO = True except ImportError: log.exception('Error importing %s', 'OooImport') @@ -72,14 +72,14 @@ except ImportError: HAS_MEDIASHOUT = False if os.name == 'nt': try: - from .mediashoutimport import MediaShoutImport + from .importers.mediashout import MediaShoutImport HAS_MEDIASHOUT = True except ImportError: log.exception('Error importing %s', 'MediaShoutImport') HAS_WORSHIPCENTERPRO = False if os.name == 'nt': try: - from .worshipcenterproimport import WorshipCenterProImport + from .importers.worshipcenterpro import WorshipCenterProImport HAS_WORSHIPCENTERPRO = True except ImportError: log.exception('Error importing %s', 'WorshipCenterProImport') @@ -109,7 +109,7 @@ class SongFormat(object): Name of the format, e.g. ``'OpenLyrics'`` ``'prefix'`` - Prefix for Qt objects. Use mixedCase, e.g. ``'open_lyrics'`` + Prefix for Qt objects. Use mixedCase, e.g. ``'openLyrics'`` See ``SongImportForm.add_file_select_item()`` Optional attributes for each song format: @@ -190,7 +190,7 @@ class SongFormat(object): OpenLyrics: { 'class': OpenLyricsImport, 'name': 'OpenLyrics', - 'prefix': 'open_lyrics', + 'prefix': 'openLyrics', 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song') }, @@ -318,7 +318,7 @@ class SongFormat(object): 'filter': '%s (*.ptf)' % translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files') }, WordsOfWorship: { - 'class': WowImport, + 'class': WordsOfWorshipImport, 'name': 'Words of Worship', 'prefix': 'wordsOfWorship', 'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') @@ -423,10 +423,10 @@ class SongFormat(object): SongFormat.set(SongFormat.SongsOfFellowship, 'availability', HAS_SOF) if HAS_SOF: - SongFormat.set(SongFormat.SongsOfFellowship, 'class', SofImport) + SongFormat.set(SongFormat.SongsOfFellowship, 'class', SongsOfFellowshipImport) SongFormat.set(SongFormat.Generic, 'availability', HAS_OOO) if HAS_OOO: - SongFormat.set(SongFormat.Generic, 'class', OooImport) + SongFormat.set(SongFormat.Generic, 'class', OpenOfficeImport) SongFormat.set(SongFormat.MediaShout, 'availability', HAS_MEDIASHOUT) if HAS_MEDIASHOUT: SongFormat.set(SongFormat.MediaShout, 'class', MediaShoutImport) diff --git a/openlp/plugins/songs/lib/songimport/__init__.py b/openlp/plugins/songs/lib/importers/__init__.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/__init__.py rename to openlp/plugins/songs/lib/importers/__init__.py diff --git a/openlp/plugins/songs/lib/songimport/cclifileimport.py b/openlp/plugins/songs/lib/importers/cclifile.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/cclifileimport.py rename to openlp/plugins/songs/lib/importers/cclifile.py diff --git a/openlp/plugins/songs/lib/songimport/dreambeamimport.py b/openlp/plugins/songs/lib/importers/dreambeam.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/dreambeamimport.py rename to openlp/plugins/songs/lib/importers/dreambeam.py index e5afd65f4..38aab4ae7 100644 --- a/openlp/plugins/songs/lib/songimport/dreambeamimport.py +++ b/openlp/plugins/songs/lib/importers/dreambeam.py @@ -35,7 +35,7 @@ import logging from lxml import etree, objectify from openlp.core.lib import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/easyslidesimport.py b/openlp/plugins/songs/lib/importers/easyslides.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/easyslidesimport.py rename to openlp/plugins/songs/lib/importers/easyslides.py index f30ae49e5..93e7fc4db 100644 --- a/openlp/plugins/songs/lib/songimport/easyslidesimport.py +++ b/openlp/plugins/songs/lib/importers/easyslides.py @@ -33,7 +33,7 @@ import re from lxml import etree, objectify from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/ewimport.py b/openlp/plugins/songs/lib/importers/easyworship.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/ewimport.py rename to openlp/plugins/songs/lib/importers/easyworship.py diff --git a/openlp/plugins/songs/lib/songimport/foilpresenterimport.py b/openlp/plugins/songs/lib/importers/foilpresenter.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/foilpresenterimport.py rename to openlp/plugins/songs/lib/importers/foilpresenter.py index 67911de76..482fbc06a 100644 --- a/openlp/plugins/songs/lib/songimport/foilpresenterimport.py +++ b/openlp/plugins/songs/lib/importers/foilpresenter.py @@ -99,7 +99,7 @@ from lxml import etree, objectify from openlp.core.lib import translate from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.db import Author, Book, Song, Topic from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.openlyricsxml import SongXML diff --git a/openlp/plugins/songs/lib/songimport/mediashoutimport.py b/openlp/plugins/songs/lib/importers/mediashout.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/mediashoutimport.py rename to openlp/plugins/songs/lib/importers/mediashout.py index 8eab61a96..d82304fae 100644 --- a/openlp/plugins/songs/lib/songimport/mediashoutimport.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -33,7 +33,7 @@ a MediaShout database into the OpenLP database. import pyodbc from openlp.core.lib import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E'] diff --git a/openlp/plugins/songs/lib/songimport/olpimport.py b/openlp/plugins/songs/lib/importers/openlp.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/olpimport.py rename to openlp/plugins/songs/lib/importers/openlp.py diff --git a/openlp/plugins/songs/lib/songimport/openlyricsimport.py b/openlp/plugins/songs/lib/importers/openlyrics.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/openlyricsimport.py rename to openlp/plugins/songs/lib/importers/openlyrics.py index 74329bfd8..78fcbf2af 100644 --- a/openlp/plugins/songs/lib/songimport/openlyricsimport.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -37,7 +37,7 @@ import os from lxml import etree from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, OpenLyricsError diff --git a/openlp/plugins/songs/lib/songimport/oooimport.py b/openlp/plugins/songs/lib/importers/openoffice.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/oooimport.py rename to openlp/plugins/songs/lib/importers/openoffice.py index 0e388b54f..0e499f7ae 100644 --- a/openlp/plugins/songs/lib/songimport/oooimport.py +++ b/openlp/plugins/songs/lib/importers/openoffice.py @@ -52,7 +52,7 @@ except ImportError: PAGE_BOTH = 6 -class OooImport(SongImport): +class OpenOfficeImport(SongImport): """ Import songs from Impress/Powerpoint docs using Impress """ diff --git a/openlp/plugins/songs/lib/songimport/opensongimport.py b/openlp/plugins/songs/lib/importers/opensong.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/opensongimport.py rename to openlp/plugins/songs/lib/importers/opensong.py index a52b67b0f..e1502a903 100644 --- a/openlp/plugins/songs/lib/songimport/opensongimport.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -35,7 +35,7 @@ from lxml.etree import Error, LxmlError from openlp.core.common import translate from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/powersongimport.py b/openlp/plugins/songs/lib/importers/powersong.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/powersongimport.py rename to openlp/plugins/songs/lib/importers/powersong.py index 1cad5e33e..89c847ab0 100644 --- a/openlp/plugins/songs/lib/songimport/powersongimport.py +++ b/openlp/plugins/songs/lib/importers/powersong.py @@ -35,7 +35,7 @@ import fnmatch import os from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) @@ -90,7 +90,7 @@ class PowerSongImport(SongImport): """ Receive either a list of files or a folder (unicode) to import. """ - from .importer import SongFormat + from openlp.plugins.songs.lib.importer import SongFormat ps_string = SongFormat.get(SongFormat.PowerSong, 'name') if isinstance(self.import_source, str): if os.path.isdir(self.import_source): diff --git a/openlp/plugins/songs/lib/songimport/propresenterimport.py b/openlp/plugins/songs/lib/importers/propresenter.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/propresenterimport.py rename to openlp/plugins/songs/lib/importers/propresenter.py diff --git a/openlp/plugins/songs/lib/songimport/songbeamerimport.py b/openlp/plugins/songs/lib/importers/songbeamer.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/songbeamerimport.py rename to openlp/plugins/songs/lib/importers/songbeamer.py index fbd016cda..4c5873e2a 100644 --- a/openlp/plugins/songs/lib/songimport/songbeamerimport.py +++ b/openlp/plugins/songs/lib/importers/songbeamer.py @@ -36,7 +36,7 @@ import os import re from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py similarity index 100% rename from openlp/plugins/songs/lib/songimport/songimport.py rename to openlp/plugins/songs/lib/importers/songimport.py diff --git a/openlp/plugins/songs/lib/songimport/songproimport.py b/openlp/plugins/songs/lib/importers/songpro.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/songproimport.py rename to openlp/plugins/songs/lib/importers/songpro.py index 853a1d9eb..52d702097 100644 --- a/openlp/plugins/songs/lib/songimport/songproimport.py +++ b/openlp/plugins/songs/lib/importers/songpro.py @@ -33,7 +33,7 @@ songs into the OpenLP database. import re from openlp.plugins.songs.lib import strip_rtf -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport class SongProImport(SongImport): diff --git a/openlp/plugins/songs/lib/songimport/songshowplusimport.py b/openlp/plugins/songs/lib/importers/songshowplus.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/songshowplusimport.py rename to openlp/plugins/songs/lib/importers/songshowplus.py index 352e55d96..d53cc33f1 100644 --- a/openlp/plugins/songs/lib/songimport/songshowplusimport.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -38,7 +38,7 @@ import struct from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport TITLE = 1 AUTHOR = 2 diff --git a/openlp/plugins/songs/lib/songimport/sofimport.py b/openlp/plugins/songs/lib/importers/songsoffellowship.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/sofimport.py rename to openlp/plugins/songs/lib/importers/songsoffellowship.py index e44034648..c1ef8666f 100644 --- a/openlp/plugins/songs/lib/songimport/sofimport.py +++ b/openlp/plugins/songs/lib/importers/songsoffellowship.py @@ -37,13 +37,13 @@ import logging import os import re -from .oooimport import OooImport +from .openoffice import OpenOfficeImport log = logging.getLogger(__name__) if os.name == 'nt': - from .oooimport import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH + from .openoffice import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH RuntimeException = Exception else: try: @@ -62,7 +62,7 @@ except ImportError: ITALIC = 2 -class SofImport(OooImport): +class SongsOfFellowshipImport(OpenOfficeImport): """ Import songs provided on disks with the Songs of Fellowship music books VOLS1_2.RTF, sof3words.rtf and sof4words.rtf @@ -83,7 +83,7 @@ class SofImport(OooImport): Initialise the class. Requires a songmanager class which is passed to SongImport for writing song to disk """ - OooImport.__init__(self, manager, **kwargs) + OpenOfficeImport.__init__(self, manager, **kwargs) self.song = False def process_ooo_document(self): diff --git a/openlp/plugins/songs/lib/songimport/sundayplusimport.py b/openlp/plugins/songs/lib/importers/sundayplus.py similarity index 99% rename from openlp/plugins/songs/lib/songimport/sundayplusimport.py rename to openlp/plugins/songs/lib/importers/sundayplus.py index fded3bca3..b664efb54 100644 --- a/openlp/plugins/songs/lib/songimport/sundayplusimport.py +++ b/openlp/plugins/songs/lib/importers/sundayplus.py @@ -32,7 +32,7 @@ import re from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib import strip_rtf -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport HOTKEY_TO_VERSE_TYPE = { '1': 'v1', diff --git a/openlp/plugins/songs/lib/songimport/wowimport.py b/openlp/plugins/songs/lib/importers/wordsofworship.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/wowimport.py rename to openlp/plugins/songs/lib/importers/wordsofworship.py index c135ca620..ce80c19ce 100644 --- a/openlp/plugins/songs/lib/songimport/wowimport.py +++ b/openlp/plugins/songs/lib/importers/wordsofworship.py @@ -34,14 +34,14 @@ import os import logging from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport BLOCK_TYPES = ('V', 'C', 'B') log = logging.getLogger(__name__) -class WowImport(SongImport): +class WordsOfWorshipImport(SongImport): """ The :class:`WowImport` class provides the ability to import song files from Words of Worship. diff --git a/openlp/plugins/songs/lib/songimport/worshipassistantimport.py b/openlp/plugins/songs/lib/importers/worshipassistant.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/worshipassistantimport.py rename to openlp/plugins/songs/lib/importers/worshipassistant.py index 412a17c35..6ddc71159 100644 --- a/openlp/plugins/songs/lib/songimport/worshipassistantimport.py +++ b/openlp/plugins/songs/lib/importers/worshipassistant.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`worshipassistantimport` module provides the functionality for importing +The :mod:`worshipassistant` module provides the functionality for importing Worship Assistant songs into the OpenLP database. """ import chardet @@ -37,7 +37,7 @@ import re from openlp.core.common import translate from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/worshipcenterproimport.py b/openlp/plugins/songs/lib/importers/worshipcenterpro.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/worshipcenterproimport.py rename to openlp/plugins/songs/lib/importers/worshipcenterpro.py index b6c32a8c0..817bd8cae 100644 --- a/openlp/plugins/songs/lib/songimport/worshipcenterproimport.py +++ b/openlp/plugins/songs/lib/importers/worshipcenterpro.py @@ -35,7 +35,7 @@ import logging import pyodbc from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport/zionworximport.py b/openlp/plugins/songs/lib/importers/zionworx.py similarity index 98% rename from openlp/plugins/songs/lib/songimport/zionworximport.py rename to openlp/plugins/songs/lib/importers/zionworx.py index 8d939f244..0b97aee26 100644 --- a/openlp/plugins/songs/lib/songimport/zionworximport.py +++ b/openlp/plugins/songs/lib/importers/zionworx.py @@ -34,7 +34,7 @@ import csv import logging from openlp.core.common import translate -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index c97e3835f..5cbedc994 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -49,7 +49,7 @@ from openlp.plugins.songs.lib import clean_song, upgrade from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.mediaitem import SongSearch from openlp.plugins.songs.lib.importer import SongFormat -from openlp.plugins.songs.lib.songimport.olpimport import OpenLPSongImport +from openlp.plugins.songs.lib.importers.openlp import OpenLPSongImport from openlp.plugins.songs.lib.mediaitem import SongMediaItem from openlp.plugins.songs.lib.songstab import SongsTab diff --git a/tests/functional/openlp_plugins/songs/test_ewimport.py b/tests/functional/openlp_plugins/songs/test_ewimport.py index c28dc72aa..f441084e7 100644 --- a/tests/functional/openlp_plugins/songs/test_ewimport.py +++ b/tests/functional/openlp_plugins/songs/test_ewimport.py @@ -35,7 +35,7 @@ from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.songimport.ewimport import EasyWorshipSongImport, FieldDescEntry, FieldType +from openlp.plugins.songs.lib.importers.easyworship import EasyWorshipSongImport, FieldDescEntry, FieldType TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'easyworshipsongs')) @@ -178,7 +178,7 @@ class TestEasyWorshipSongImport(TestCase): Test creating an instance of the EasyWorship file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -192,7 +192,7 @@ class TestEasyWorshipSongImport(TestCase): Test finding an existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions. - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.field_descriptions = TEST_FIELD_DESCS @@ -210,7 +210,7 @@ class TestEasyWorshipSongImport(TestCase): Test finding an non-existing field in a given list using the :mod:`find_field` """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.field_descriptions = TEST_FIELD_DESCS @@ -228,8 +228,8 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out struct class, and a mocked out "manager" and a list of # field descriptions - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct: + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -246,7 +246,7 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`get_field` module """ # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.encoding = TEST_DATA_ENCODING @@ -269,7 +269,7 @@ class TestEasyWorshipSongImport(TestCase): """ for test_results in GET_MEMO_FIELD_TEST_RESULTS: # GIVEN: A mocked out SongImport class, a mocked out "manager", a mocked out memo_file and an encoding - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() mocked_memo_file = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -300,8 +300,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module opens the correct files """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.side_effect = [True, False] @@ -319,8 +319,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module produces an error when Songs.MB not found. """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) importer.log_error = MagicMock() @@ -339,8 +339,8 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module handles invalid database files correctly """ # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path: + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.return_value = True @@ -358,10 +358,10 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` module handles invalid memo files correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path, \ + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \ patch('builtins.open') as mocked_open, \ - patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct: + patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) mocked_os_path.isfile.return_value = True @@ -385,10 +385,10 @@ class TestEasyWorshipSongImport(TestCase): Test the :mod:`do_import` converts the code page to the encoding correctly """ # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.os.path') as mocked_os_path, \ - patch('builtins.open'), patch('openlp.plugins.songs.lib.songimport.ewimport.struct') as mocked_struct, \ - patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') as \ + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \ + patch('builtins.open'), patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct, \ + patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_manager = MagicMock() importer = EasyWorshipSongImport(mocked_manager, filenames=[]) @@ -413,8 +413,8 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') as \ + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_manager = MagicMock() @@ -469,8 +469,8 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.ewimport.retrieve_windows_encoding') \ + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') \ as mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding.return_value = 'cp1252' mocked_manager = MagicMock() @@ -509,7 +509,7 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and mocked out "author" method. - with patch('openlp.plugins.songs.lib.songimport.ewimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() mocked_add_author = MagicMock() importer = EasyWorshipSongImportLogger(mocked_manager) diff --git a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py index 15247a361..3886443ca 100644 --- a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.functional import patch, MagicMock -from openlp.plugins.songs.lib.songimport.foilpresenterimport import FoilPresenter +from openlp.plugins.songs.lib.importers.foilpresenter import FoilPresenter TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', '/resources/foilpresentersongs')) @@ -57,27 +57,27 @@ class TestFoilPresenter(TestCase): # _process_topics def setUp(self): - self.child_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._child') - self.clean_song_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.clean_song') - self.objectify_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.objectify') + self.child_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._child') + self.clean_song_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.clean_song') + self.objectify_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.objectify') self.process_authors_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_authors') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_authors') self.process_cclinumber_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_cclinumber') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_cclinumber') self.process_comments_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_comments') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_comments') self.process_lyrics_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_lyrics') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_lyrics') self.process_songbooks_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_songbooks') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_songbooks') self.process_titles_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_titles') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_titles') self.process_topics_patcher = \ - patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.FoilPresenter._process_topics') - self.re_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.re') - self.song_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.Song') - self.song_xml_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.SongXML') - self.translate_patcher = patch('openlp.plugins.songs.lib.songimport.foilpresenterimport.translate') + patch('openlp.plugins.songs.lib.importers.foilpresenter.FoilPresenter._process_topics') + self.re_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.re') + self.song_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.Song') + self.song_xml_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.SongXML') + self.translate_patcher = patch('openlp.plugins.songs.lib.importers.foilpresenter.translate') self.mocked_child = self.child_patcher.start() self.mocked_clean_song = self.clean_song_patcher.start() diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py index 2166b950c..25db3e9e4 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py @@ -34,8 +34,8 @@ import os from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.songimport.openlyricsimport import OpenLyricsImport -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport +from openlp.plugins.songs.lib.importers.songimport import SongImport TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'openlyricssongs')) @@ -69,7 +69,7 @@ class TestOpenLyricsImport(TestCase): Test creating an instance of the OpenLyrics file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.openlyricsimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.openlyrics.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 09fad7bc3..07b275f98 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.helpers.songfileimport import SongImportTestHelper -from openlp.plugins.songs.lib.songimport.opensongimport import OpenSongImport +from openlp.plugins.songs.lib.importers.opensong import OpenSongImport from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath( @@ -45,7 +45,7 @@ class TestOpenSongFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): self.importer_class_name = 'OpenSongImport' - self.importer_module_name = 'opensongimport' + self.importer_module_name = 'opensong' super(TestOpenSongFileImport, self).__init__(*args, **kwargs) def test_song_import(self): @@ -69,7 +69,7 @@ class TestOpenSongImport(TestCase): Test creating an instance of the OpenSong file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -83,7 +83,7 @@ class TestOpenSongImport(TestCase): Test OpenSongImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = OpenSongImport(mocked_manager, filenames=[]) @@ -104,7 +104,7 @@ class TestOpenSongImport(TestCase): Test OpenSongImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.opensongimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = OpenSongImport(mocked_manager, filenames=[]) diff --git a/tests/functional/openlp_plugins/songs/test_propresenterimport.py b/tests/functional/openlp_plugins/songs/test_propresenterimport.py index 10e2defc6..bc313e250 100644 --- a/tests/functional/openlp_plugins/songs/test_propresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_propresenterimport.py @@ -43,7 +43,7 @@ class TestProPresenterFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): self.importer_class_name = 'ProPresenterImport' - self.importer_module_name = 'propresenterimport' + self.importer_module_name = 'propresenter' super(TestProPresenterFileImport, self).__init__(*args, **kwargs) def test_song_import(self): diff --git a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py index 9ca0ab790..3d872ae65 100644 --- a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py +++ b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py @@ -34,7 +34,7 @@ import os from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.songimport.songbeamerimport import SongBeamerImport +from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport from openlp.plugins.songs.lib import VerseType TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), @@ -64,7 +64,7 @@ class TestSongBeamerImport(TestCase): Test creating an instance of the SongBeamer file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -78,7 +78,7 @@ class TestSongBeamerImport(TestCase): Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongBeamerImport(mocked_manager, filenames=[]) @@ -99,7 +99,7 @@ class TestSongBeamerImport(TestCase): Test SongBeamerImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongBeamerImport(mocked_manager, filenames=[]) @@ -122,7 +122,7 @@ class TestSongBeamerImport(TestCase): # GIVEN: Test files with a mocked out SongImport class, a mocked out "manager", a mocked out "import_wizard", # and mocked out "author", "add_copyright", "add_verse", "finish" methods. - with patch('openlp.plugins.songs.lib.songimport.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport'): for song_file in SONG_TEST_DATA: mocked_manager = MagicMock() mocked_import_wizard = MagicMock() diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index 8d6a42287..77e1196bc 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -35,7 +35,7 @@ from unittest import TestCase from tests.helpers.songfileimport import SongImportTestHelper from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib.songimport.songshowplusimport import SongShowPlusImport +from openlp.plugins.songs.lib.importers.songshowplus import SongShowPlusImport from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath( @@ -46,7 +46,7 @@ class TestSongShowPlusFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): self.importer_class_name = 'SongShowPlusImport' - self.importer_module_name = 'songshowplusimport' + self.importer_module_name = 'songshowplus' super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs) def test_song_import(self): @@ -70,7 +70,7 @@ class TestSongShowPlusImport(TestCase): Test creating an instance of the SongShow Plus file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -84,7 +84,7 @@ class TestSongShowPlusImport(TestCase): Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -105,7 +105,7 @@ class TestSongShowPlusImport(TestCase): Test SongShowPlusImport.do_import handles different invalid import_source values """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -126,7 +126,7 @@ class TestSongShowPlusImport(TestCase): Test to_openlp_verse_tag method by simulating adding a verse """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) @@ -154,7 +154,7 @@ class TestSongShowPlusImport(TestCase): Test to_openlp_verse_tag method by simulating adding a verse to the verse order """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.songshowplusimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() importer = SongShowPlusImport(mocked_manager, filenames=[]) diff --git a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py index c0c5c7416..63ead5b30 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py @@ -43,7 +43,7 @@ class TestWorshipAssistantFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): self.importer_class_name = 'WorshipAssistantImport' - self.importer_module_name = 'worshipassistantimport' + self.importer_module_name = 'worshipassistant' super(TestWorshipAssistantFileImport, self).__init__(*args, **kwargs) def test_song_import(self): diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 0558ad195..cd51e3384 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -37,7 +37,7 @@ if os.name != 'nt': import pyodbc -from openlp.plugins.songs.lib.songimport.worshipcenterproimport import WorshipCenterProImport +from openlp.plugins.songs.lib.importers.worshipcenterpro import WorshipCenterProImport from tests.functional import patch, MagicMock @@ -141,7 +141,7 @@ class TestWorshipCenterProSongImport(TestCase): Test creating an instance of the WorshipCenter Pro file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created @@ -156,10 +156,10 @@ class TestWorshipCenterProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out pyodbc module, a mocked out translate method, # a mocked "manager" and a mocked out log_error method. - with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc.connect') \ + with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.worshipcenterpro.pyodbc.connect') \ as mocked_pyodbc_connect, \ - patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.translate') as mocked_translate: + patch('openlp.plugins.songs.lib.importers.worshipcenterpro.translate') as mocked_translate: mocked_manager = MagicMock() mocked_log_error = MagicMock() mocked_translate.return_value = 'Translated Text' @@ -186,9 +186,9 @@ class TestWorshipCenterProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out pyodbc module with a simulated recordset, a mocked out # translate method, a mocked "manager", add_verse method & mocked_finish method. - with patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.SongImport'), \ - patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.pyodbc') as mocked_pyodbc, \ - patch('openlp.plugins.songs.lib.songimport.worshipcenterproimport.translate') as mocked_translate: + with patch('openlp.plugins.songs.lib.importers.worshipcenterpro.SongImport'), \ + patch('openlp.plugins.songs.lib.importers.worshipcenterpro.pyodbc') as mocked_pyodbc, \ + patch('openlp.plugins.songs.lib.importers.worshipcenterpro.translate') as mocked_translate: mocked_manager = MagicMock() mocked_import_wizard = MagicMock() mocked_add_verse = MagicMock() diff --git a/tests/functional/openlp_plugins/songs/test_zionworximport.py b/tests/functional/openlp_plugins/songs/test_zionworximport.py index a3f5bb20b..faedc7005 100644 --- a/tests/functional/openlp_plugins/songs/test_zionworximport.py +++ b/tests/functional/openlp_plugins/songs/test_zionworximport.py @@ -33,8 +33,8 @@ This module contains tests for the ZionWorx song importer. from unittest import TestCase from tests.functional import MagicMock, patch -from openlp.plugins.songs.lib.songimport.zionworximport import ZionWorxImport -from openlp.plugins.songs.lib.songimport.songimport import SongImport +from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport +from openlp.plugins.songs.lib.importers.songimport import SongImport class TestZionWorxImport(TestCase): @@ -46,7 +46,7 @@ class TestZionWorxImport(TestCase): Test creating an instance of the ZionWorx file importer """ # GIVEN: A mocked out SongImport class, and a mocked out "manager" - with patch('openlp.plugins.songs.lib.songimport.zionworximport.SongImport'): + with patch('openlp.plugins.songs.lib.importers.zionworx.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 003ade543..6fae4d31d 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -43,7 +43,7 @@ class SongImportTestHelper(TestCase): def __init__(self, *args, **kwargs): super(SongImportTestHelper, self).__init__(*args, **kwargs) self.importer_module = __import__( - 'openlp.plugins.songs.lib.songimport.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) + 'openlp.plugins.songs.lib.importers.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) self.importer_class = getattr(self.importer_module, self.importer_class_name) def setUp(self): @@ -51,17 +51,17 @@ class SongImportTestHelper(TestCase): Patch and set up the mocks required. """ self.add_copyright_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_copyright' % (self.importer_module_name, + 'openlp.plugins.songs.lib.importers.%s.%s.add_copyright' % (self.importer_module_name, self.importer_class_name)) self.add_verse_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_verse' % (self.importer_module_name, + 'openlp.plugins.songs.lib.importers.%s.%s.add_verse' % (self.importer_module_name, self.importer_class_name)) self.finish_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) + 'openlp.plugins.songs.lib.importers.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) self.add_author_patcher = patch( - 'openlp.plugins.songs.lib.songimport.%s.%s.add_author' % (self.importer_module_name, + 'openlp.plugins.songs.lib.importers.%s.%s.add_author' % (self.importer_module_name, self.importer_class_name)) - self.song_import_patcher = patch('openlp.plugins.songs.lib.songimport.%s.SongImport' % + self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.%s.SongImport' % self.importer_module_name) self.mocked_add_copyright = self.add_copyright_patcher.start() self.mocked_add_verse = self.add_verse_patcher.start() From f089e7522e762f4ccb1a26f66bea19dd8c61801e Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 11:35:10 +0200 Subject: [PATCH 35/69] Cleanups --- openlp/plugins/songs/lib/importers/dreambeam.py | 3 +-- openlp/plugins/songs/lib/importers/easyworship.py | 3 +-- openlp/plugins/songs/lib/importers/mediashout.py | 2 +- openlp/plugins/songs/lib/importers/openlp.py | 2 +- openlp/plugins/songs/lib/importers/openlyrics.py | 2 +- openlp/plugins/songs/lib/importers/powersong.py | 2 +- openlp/plugins/songs/lib/importers/propresenter.py | 2 +- openlp/plugins/songs/lib/importers/songbeamer.py | 2 +- openlp/plugins/songs/lib/importers/songpro.py | 2 +- openlp/plugins/songs/lib/importers/songshowplus.py | 2 +- openlp/plugins/songs/lib/importers/wordsofworship.py | 5 ++--- openlp/plugins/songs/lib/importers/zionworx.py | 3 +-- 12 files changed, 13 insertions(+), 17 deletions(-) diff --git a/openlp/plugins/songs/lib/importers/dreambeam.py b/openlp/plugins/songs/lib/importers/dreambeam.py index 38aab4ae7..458961df0 100644 --- a/openlp/plugins/songs/lib/importers/dreambeam.py +++ b/openlp/plugins/songs/lib/importers/dreambeam.py @@ -27,8 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`dreambeamimport` module provides the functionality for importing -DreamBeam songs into the OpenLP database. +The :mod:`dreambeam` module provides the functionality for importing DreamBeam songs into the OpenLP database. """ import logging diff --git a/openlp/plugins/songs/lib/importers/easyworship.py b/openlp/plugins/songs/lib/importers/easyworship.py index c56e1dba1..761f83f59 100644 --- a/openlp/plugins/songs/lib/importers/easyworship.py +++ b/openlp/plugins/songs/lib/importers/easyworship.py @@ -27,8 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`ewimport` module provides the functionality for importing -EasyWorship song databases into the current installation database. +The :mod:`easyworship` module provides the functionality for importing EasyWorship song databases into OpenLP. """ import os diff --git a/openlp/plugins/songs/lib/importers/mediashout.py b/openlp/plugins/songs/lib/importers/mediashout.py index d82304fae..19d1b1d9d 100644 --- a/openlp/plugins/songs/lib/importers/mediashout.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`mediashoutimport` module provides the functionality for importing +The :mod:`mediashout` module provides the functionality for importing a MediaShout database into the OpenLP database. """ import pyodbc diff --git a/openlp/plugins/songs/lib/importers/openlp.py b/openlp/plugins/songs/lib/importers/openlp.py index f4b066ef0..1a27e8d69 100644 --- a/openlp/plugins/songs/lib/importers/openlp.py +++ b/openlp/plugins/songs/lib/importers/openlp.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`olpimport` module provides the functionality for importing OpenLP +The :mod:`openlp` module provides the functionality for importing OpenLP song databases into the current installation database. """ import logging diff --git a/openlp/plugins/songs/lib/importers/openlyrics.py b/openlp/plugins/songs/lib/importers/openlyrics.py index 78fcbf2af..9bb20dbf4 100644 --- a/openlp/plugins/songs/lib/importers/openlyrics.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`openlyricsimport` module provides the functionality for importing +The :mod:`openlyrics` module provides the functionality for importing songs which are saved as OpenLyrics files. """ diff --git a/openlp/plugins/songs/lib/importers/powersong.py b/openlp/plugins/songs/lib/importers/powersong.py index 89c847ab0..5aa0038f4 100644 --- a/openlp/plugins/songs/lib/importers/powersong.py +++ b/openlp/plugins/songs/lib/importers/powersong.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`powersongimport` module provides the functionality for importing +The :mod:`powersong` module provides the functionality for importing PowerSong songs into the OpenLP database. """ import logging diff --git a/openlp/plugins/songs/lib/importers/propresenter.py b/openlp/plugins/songs/lib/importers/propresenter.py index 6ce3c0819..3bf7f9cd8 100644 --- a/openlp/plugins/songs/lib/importers/propresenter.py +++ b/openlp/plugins/songs/lib/importers/propresenter.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`propresenterimport` module provides the functionality for importing +The :mod:`propresenter` module provides the functionality for importing ProPresenter song files into the current installation database. """ diff --git a/openlp/plugins/songs/lib/importers/songbeamer.py b/openlp/plugins/songs/lib/importers/songbeamer.py index 4c5873e2a..9a7429f02 100644 --- a/openlp/plugins/songs/lib/importers/songbeamer.py +++ b/openlp/plugins/songs/lib/importers/songbeamer.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`songbeamerimport` module provides the functionality for importing SongBeamer songs into the OpenLP database. +The :mod:`songbeamer` module provides the functionality for importing SongBeamer songs into the OpenLP database. """ import chardet import codecs diff --git a/openlp/plugins/songs/lib/importers/songpro.py b/openlp/plugins/songs/lib/importers/songpro.py index 52d702097..efe1a85ea 100644 --- a/openlp/plugins/songs/lib/importers/songpro.py +++ b/openlp/plugins/songs/lib/importers/songpro.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`songproimport` module provides the functionality for importing SongPro +The :mod:`songpro` module provides the functionality for importing SongPro songs into the OpenLP database. """ import re diff --git a/openlp/plugins/songs/lib/importers/songshowplus.py b/openlp/plugins/songs/lib/importers/songshowplus.py index d53cc33f1..6c9feab68 100644 --- a/openlp/plugins/songs/lib/importers/songshowplus.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`songshowplusimport` module provides the functionality for importing SongShow Plus songs into the OpenLP +The :mod:`songshowplus` module provides the functionality for importing SongShow Plus songs into the OpenLP database. """ import chardet diff --git a/openlp/plugins/songs/lib/importers/wordsofworship.py b/openlp/plugins/songs/lib/importers/wordsofworship.py index ce80c19ce..1b398c604 100644 --- a/openlp/plugins/songs/lib/importers/wordsofworship.py +++ b/openlp/plugins/songs/lib/importers/wordsofworship.py @@ -27,7 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`wowimport` module provides the functionality for importing Words of +The :mod:`wordsofworship` module provides the functionality for importing Words of Worship songs into the OpenLP database. """ import os @@ -43,8 +43,7 @@ log = logging.getLogger(__name__) class WordsOfWorshipImport(SongImport): """ - The :class:`WowImport` class provides the ability to import song files from - Words of Worship. + The :class:`WordsOfWorshipImport` class provides the ability to import song files from Words of Worship. **Words Of Worship Song File Format:** diff --git a/openlp/plugins/songs/lib/importers/zionworx.py b/openlp/plugins/songs/lib/importers/zionworx.py index 0b97aee26..ed3c41f3a 100644 --- a/openlp/plugins/songs/lib/importers/zionworx.py +++ b/openlp/plugins/songs/lib/importers/zionworx.py @@ -27,8 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`zionworximport` module provides the functionality for importing -ZionWorx songs into the OpenLP database. +The :mod:`zionworx` module provides the functionality for importing ZionWorx songs into the OpenLP database. """ import csv import logging From 0fb445e1177e38d6082fd06814bed888f89735ef Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 11:36:54 +0200 Subject: [PATCH 36/69] PEP8 --- tests/helpers/songfileimport.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 6fae4d31d..18e7914b9 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -42,25 +42,22 @@ class SongImportTestHelper(TestCase): """ def __init__(self, *args, **kwargs): super(SongImportTestHelper, self).__init__(*args, **kwargs) - self.importer_module = __import__( - 'openlp.plugins.songs.lib.importers.%s' % self.importer_module_name, fromlist=[self.importer_class_name]) + self.importer_module = __import__('openlp.plugins.songs.lib.importers.%s' % + self.importer_module_name, fromlist=[self.importer_class_name]) self.importer_class = getattr(self.importer_module, self.importer_class_name) def setUp(self): """ Patch and set up the mocks required. """ - self.add_copyright_patcher = patch( - 'openlp.plugins.songs.lib.importers.%s.%s.add_copyright' % (self.importer_module_name, - self.importer_class_name)) - self.add_verse_patcher = patch( - 'openlp.plugins.songs.lib.importers.%s.%s.add_verse' % (self.importer_module_name, - self.importer_class_name)) - self.finish_patcher = patch( - 'openlp.plugins.songs.lib.importers.%s.%s.finish' % (self.importer_module_name, self.importer_class_name)) - self.add_author_patcher = patch( - 'openlp.plugins.songs.lib.importers.%s.%s.add_author' % (self.importer_module_name, - self.importer_class_name)) + self.add_copyright_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_copyright' % + (self.importer_module_name, self.importer_class_name)) + self.add_verse_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_verse' % + (self.importer_module_name, self.importer_class_name)) + self.finish_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.finish' % + (self.importer_module_name, self.importer_class_name)) + self.add_author_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_author' % + (self.importer_module_name, self.importer_class_name)) self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.%s.SongImport' % self.importer_module_name) self.mocked_add_copyright = self.add_copyright_patcher.start() From 60f11d91734205f3a9481d643ab72ced72313c13 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 13:18:14 +0200 Subject: [PATCH 37/69] Always display copyright symbol in footer --- openlp/plugins/songs/forms/editsongdialog.py | 8 ++++---- openlp/plugins/songs/forms/editsongform.py | 13 ------------- openlp/plugins/songs/lib/mediaitem.py | 3 ++- openlp/plugins/songs/lib/upgrade.py | 19 ++++++++++++++++--- .../openlp_plugins/songs/test_mediaitem.py | 12 ++++++------ 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/openlp/plugins/songs/forms/editsongdialog.py b/openlp/plugins/songs/forms/editsongdialog.py index a9ca71946..6abdf5f4f 100644 --- a/openlp/plugins/songs/forms/editsongdialog.py +++ b/openlp/plugins/songs/forms/editsongdialog.py @@ -218,12 +218,12 @@ class Ui_EditSongDialog(object): self.rights_layout.setObjectName('rights_layout') self.copyright_layout = QtGui.QHBoxLayout() self.copyright_layout.setObjectName('copyright_layout') + self.copyright_label = QtGui.QLabel(self.rights_group_box) + self.copyright_label.setObjectName('copyright_label') + self.copyright_layout.addWidget(self.copyright_label) self.copyright_edit = QtGui.QLineEdit(self.rights_group_box) self.copyright_edit.setObjectName('copyright_edit') self.copyright_layout.addWidget(self.copyright_edit) - self.copyright_insert_button = QtGui.QToolButton(self.rights_group_box) - self.copyright_insert_button.setObjectName('copyright_insert_button') - self.copyright_layout.addWidget(self.copyright_insert_button) self.rights_layout.addLayout(self.copyright_layout) self.ccli_layout = QtGui.QHBoxLayout() self.ccli_layout.setObjectName('ccli_layout') @@ -318,7 +318,7 @@ class Ui_EditSongDialog(object): self.theme_group_box.setTitle(UiStrings().Theme) self.theme_add_button.setText(translate('SongsPlugin.EditSongForm', 'New &Theme')) self.rights_group_box.setTitle(translate('SongsPlugin.EditSongForm', 'Copyright Information')) - self.copyright_insert_button.setText(SongStrings.CopyrightSymbol) + self.copyright_label.setText(translate('SongsPlugin.EditSongForm', 'Copyright:')) self.ccli_label.setText(UiStrings().CCLINumberLabel) self.comments_group_box.setTitle(translate('SongsPlugin.EditSongForm', 'Comments')) self.song_tab_widget.setTabText(self.song_tab_widget.indexOf(self.theme_tab), diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 2125922fe..3af7522d2 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -75,7 +75,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): self.topic_add_button.clicked.connect(self.on_topic_add_button_clicked) self.topic_remove_button.clicked.connect(self.on_topic_remove_button_clicked) self.topics_list_view.itemClicked.connect(self.on_topic_list_view_clicked) - self.copyright_insert_button.clicked.connect(self.on_copyright_insert_button_triggered) self.verse_add_button.clicked.connect(self.on_verse_add_button_clicked) self.verse_list_widget.doubleClicked.connect(self.on_verse_edit_button_clicked) self.verse_edit_button.clicked.connect(self.on_verse_edit_button_clicked) @@ -796,18 +795,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): label_text = self.not_all_verses_used_warning self.warning_label.setText(label_text) - def on_copyright_insert_button_triggered(self): - """ - Copyright insert button pressed - """ - text = self.copyright_edit.text() - pos = self.copyright_edit.cursorPosition() - sign = SongStrings.CopyrightSymbol - text = text[:pos] + sign + text[pos:] - self.copyright_edit.setText(text) - self.copyright_edit.setFocus() - self.copyright_edit.setCursorPosition(pos + len(sign)) - def on_maintenance_button_clicked(self): """ Maintenance button pressed diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index d57c8fbcc..c4eaa73e8 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -506,7 +506,8 @@ class SongMediaItem(MediaManagerItem): if authors_translation: item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation], create_separated_list(authors_translation))) - item.raw_footer.append(song.copyright) + if song.copyright: + item.raw_footer.append('%s %s' % (SongStrings.CopyrightSymbol, song.copyright)) if self.display_songbook and song.book: item.raw_footer.append("%s #%s" % (song.book.name, song.song_number)) if Settings().value('core/ccli number'): diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 580ae767d..df841b39c 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -27,8 +27,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`upgrade` module provides a way for the database and schema that is the -backend for the Songs plugin +The :mod:`upgrade` module provides a way for the database and schema that is the backend for the Songs plugin """ import logging @@ -39,7 +38,7 @@ from sqlalchemy.sql.expression import func, false, null, text from openlp.core.lib.db import get_upgrade_op log = logging.getLogger(__name__) -__version__ = 4 +__version__ = 5 def upgrade_1(session, metadata): @@ -119,3 +118,17 @@ def upgrade_4(session, metadata): op.rename_table('authors_songs_tmp', 'authors_songs') except OperationalError: log.info('Upgrade 4 has already been run') + + +def upgrade_5(session, metadata): + """ + Version 5 upgrade + + This upgrade removes all hard-coded copyright symbols from the copyright field in the songs. + The copyright symbol is now being added directly in the footer. + """ + try: + op = get_upgrade_op(session) + op.execute('UPDATE songs SET copyright=TRIM(REPLACE(copyright, "©", ""))') + except OperationalError: + log.info('Upgrade 5 has already been run') diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index bc22a4577..da6ae4b71 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -58,7 +58,7 @@ class TestMediaItem(TestCase, TestMixin): author_list = self.media_item.generate_footer(service_item, mock_song) # THEN: I get the following Array returned - self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', 'My copyright'], + self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', '© My copyright'], 'The array should be returned correctly with a song, one author and copyright') self.assertEqual(author_list, ['my author'], 'The author list should be returned correctly with one author') @@ -97,7 +97,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: I get the following Array returned self.assertEqual(service_item.raw_footer, ['My Song', 'Words: another author', 'Music: my author', - 'Translation: translator', 'My copyright'], + 'Translation: translator', '© My copyright'], 'The array should be returned correctly with a song, two authors and copyright') self.assertEqual(author_list, ['another author', 'my author', 'translator'], 'The author list should be returned correctly with two authors') @@ -117,7 +117,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: I get the following Array returned - self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 1234'], + self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'CCLI License: 1234'], 'The array should be returned correctly with a song, an author, copyright and ccli') # WHEN: I amend the CCLI value @@ -125,7 +125,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: I would get an amended footer string - self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 4321'], + self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'CCLI License: 4321'], 'The array should be returned correctly with a song, an author, copyright and amended ccli') def build_song_footer_base_songbook_test(self): @@ -145,14 +145,14 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: The songbook should not be in the footer - self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright']) + self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright']) # WHEN: I activate the "display songbook" option self.media_item.display_songbook = True self.media_item.generate_footer(service_item, mock_song) # THEN: The songbook should be in the footer - self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12']) + self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'My songbook #12']) def authors_match_test(self): """ From 7f9ae1374e5c2c44ffcddd1e19c1fa4fbd515d47 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 4 Jul 2014 16:16:02 +0200 Subject: [PATCH 38/69] Started authortype editing Fixes: https://launchpad.net/bugs/1336933 --- openlp/plugins/songs/forms/editsongdialog.py | 4 ++++ openlp/plugins/songs/forms/editsongform.py | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/forms/editsongdialog.py b/openlp/plugins/songs/forms/editsongdialog.py index a9ca71946..cdbac7fdb 100644 --- a/openlp/plugins/songs/forms/editsongdialog.py +++ b/openlp/plugins/songs/forms/editsongdialog.py @@ -138,6 +138,9 @@ class Ui_EditSongDialog(object): self.author_remove_layout = QtGui.QHBoxLayout() self.author_remove_layout.setObjectName('author_remove_layout') self.author_remove_layout.addStretch() + self.author_edit_button = QtGui.QPushButton(self.authors_group_box) + self.author_edit_button.setObjectName('author_edit_button') + self.author_remove_layout.addWidget(self.author_edit_button) self.author_remove_button = QtGui.QPushButton(self.authors_group_box) self.author_remove_button.setObjectName('author_remove_button') self.author_remove_layout.addWidget(self.author_remove_button) @@ -305,6 +308,7 @@ class Ui_EditSongDialog(object): translate('SongsPlugin.EditSongForm', 'Title && Lyrics')) self.authors_group_box.setTitle(SongStrings.Authors) self.author_add_button.setText(translate('SongsPlugin.EditSongForm', '&Add to Song')) + self.author_edit_button.setText(translate('SongsPlugin.EditSongForm', '&Edit Author Type')) self.author_remove_button.setText(translate('SongsPlugin.EditSongForm', '&Remove')) self.maintenance_button.setText(translate('SongsPlugin.EditSongForm', '&Manage Authors, Topics, Song Books')) self.topics_group_box.setTitle(SongStrings.Topic) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 2125922fe..9c7d4a61e 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -70,6 +70,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): self.setupUi(self) # Connecting signals and slots self.author_add_button.clicked.connect(self.on_author_add_button_clicked) + self.author_edit_button.clicked.connect(self.on_author_edit_button_clicked) self.author_remove_button.clicked.connect(self.on_author_remove_button_clicked) self.authors_list_view.itemClicked.connect(self.on_authors_list_view_clicked) self.topic_add_button.clicked.connect(self.on_topic_add_button_clicked) @@ -334,6 +335,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): """ self.verse_edit_button.setEnabled(False) self.verse_delete_button.setEnabled(False) + self.author_edit_button.setEnabled(False) self.author_remove_button.setEnabled(False) self.topic_remove_button.setEnabled(False) @@ -596,9 +598,23 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): """ Run a set of actions when an author in the list is selected (mainly enable the delete button). """ - if self.authors_list_view.count() > 1: + count = self.authors_list_view.count() + if count > 0: + self.author_edit_button.setEnabled(True) + if count > 1: + # There must be at least one author self.author_remove_button.setEnabled(True) + def on_author_edit_button_clicked(self): + """ + Show a dialog to change the type of an author when the edit button is clicked + """ + self.author_edit_button.setEnabled(False) + item = self.authors_list_view.currentItem() + author_id, author_type = item.data(QtCore.Qt.UserRole) + + #dialog = QtGui.QDialog(self) + def on_author_remove_button_clicked(self): """ Remove the author from the list when the delete button is clicked. From cfd9631d042bbf3f29935137f1c8512ba71af823 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Sat, 5 Jul 2014 18:21:43 +0200 Subject: [PATCH 39/69] Parse verse names --- openlp/plugins/songs/lib/powerpraiseimport.py | 17 +++++++++--- .../songs/test_powerpraiseimport.py | 2 ++ .../powerpraisesongs/You are so faithful.json | 26 +++++++++++++++++++ .../powerpraisesongs/You are so faithful.ppl | 2 ++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/resources/powerpraisesongs/You are so faithful.json create mode 100644 tests/resources/powerpraisesongs/You are so faithful.ppl diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py index ecf1c55fb..6a67619b3 100644 --- a/openlp/plugins/songs/lib/powerpraiseimport.py +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -58,13 +58,24 @@ class PowerPraiseImport(SongImport): self.set_defaults() self.title = str(root.general.title) verse_order_list = [] + verse_count = {} for item in root.order.item: verse_order_list.append(str(item)) - count = 0 for part in root.songtext.part: - count += 1 - verse_def = "v%d" % count original_verse_def = part.get('caption') + # There are some predefined verse defitions in PowerPraise, try to parse these + if original_verse_def.startswith("Strophe") or original_verse_def.startswith("Teil"): + verse_def = 'v' + elif original_verse_def.startswith("Refrain"): + verse_def = 'c' + elif original_verse_def.startswith("Bridge"): + verse_def = 'b' + elif original_verse_def.startswith("Schluss"): + verse_def = 'e' + else: + verse_def = 'o' + verse_count[verse_def] = verse_count.get(verse_def, 0) + 1 + verse_def = '%s%d' % (verse_def, verse_count[verse_def]) verse_text = [] for slide in part.slide: if not hasattr(slide, 'line'): diff --git a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py index 2d5a42e6f..fa2c5f5b5 100644 --- a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py +++ b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py @@ -52,3 +52,5 @@ class TestPowerPraiseFileImport(SongImportTestHelper): """ self.file_import([os.path.join(TEST_PATH, 'Näher, mein Gott zu Dir.ppl')], self.load_external_result_data(os.path.join(TEST_PATH, 'Näher, mein Gott zu Dir.json'))) + self.file_import([os.path.join(TEST_PATH, 'You are so faithful.ppl')], + self.load_external_result_data(os.path.join(TEST_PATH, 'You are so faithful.json'))) diff --git a/tests/resources/powerpraisesongs/You are so faithful.json b/tests/resources/powerpraisesongs/You are so faithful.json new file mode 100644 index 000000000..855b52f67 --- /dev/null +++ b/tests/resources/powerpraisesongs/You are so faithful.json @@ -0,0 +1,26 @@ +{ + "title": "You are so faithful", + "verse_order_list": ["v1", "c1", "v2", "c1", "v3", "c1", "v4"], + "verses": [ + [ + "You are so faithful\nso faithful, so faithful.\nYou are so faithful\nso faithful, so faithful.", + "v1" + ], + [ + "That's why I praise you\nin the morning\nThat's why I praise you\nin the noontime.\nThat's why I praise you\nin the evening\nThat's why I praise you\nall the time.", + "c1" + ], + [ + "You are so loving\nso loving, so loving.\nYou are so loving\nso loving, so loving.", + "v2" + ], + [ + "You are so caring\nso caring, so caring.\nYou are so caring\nso caring, so caring.", + "v3" + ], + [ + "You are so mighty\nso mighty, so mighty.\nYou are so mighty\nso mighty, so mighty.", + "v4" + ] + ] +} diff --git a/tests/resources/powerpraisesongs/You are so faithful.ppl b/tests/resources/powerpraisesongs/You are so faithful.ppl new file mode 100644 index 000000000..420ae8fb6 --- /dev/null +++ b/tests/resources/powerpraisesongs/You are so faithful.ppl @@ -0,0 +1,2 @@ + +You are so faithfulLobpreisEnglischYou are so faithfulso faithful, so faithful.Du bist so treuso treu, so treu.You are so faithfulso faithful, so faithful.Du bist so treuso treu, so treu.That's why I praise youin the morningThat's why I praise youin the noontime.Deshalb preise ich Dicham MorgenDeshalb preise ich Dicham Mittag.That's why I praise youin the eveningThat's why I praise youall the time.Deshalb preise ich Dicham AbendDeshalb preise ich Dichallezeit.You are so lovingso loving, so loving.Du bist so liebevollso liebevoll, so liebevoll.You are so lovingso loving, so loving.Du bist so liebevollso liebevoll, so liebevoll.You are so caringso caring, so caring.Du sorgst so gutDu kümmerst dich um uns.You are so caringso caring, so caring.Du sorgst so gutDu kümmerst dich um uns.You are so mightyso mighty, so mighty.Du bist so mächtigso mächtig, so mächtig.You are so mightyso mighty, so mighty.Du bist so mächtigso mächtig, so mächtig.Strophe 1RefrainStrophe 2RefrainStrophe 3RefrainStrophe 4lastslideMusik & Copyright unbekanntfirstslideTahoma30truefalse167772153020Tahoma20falsefalse167772153020Tahoma14falsefalse167772153020Tahoma30falsefalse167772153020true0true0125Blumen\Blume 6.jpg
30
20
centercenterinline50406070302040
From 5d7b60f714974fb840a2290bc1767d224bf014d3 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Sat, 5 Jul 2014 21:56:32 +0200 Subject: [PATCH 40/69] Changing Author type functional --- openlp/plugins/songs/forms/editsongform.py | 20 +++++++++++------ openlp/plugins/songs/lib/db.py | 25 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 9c7d4a61e..10a235c5c 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -356,12 +356,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): # Types self.author_types_combo_box.clear() - self.author_types_combo_box.addItem('') # Don't iterate over the dictionary to give them this specific order - self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Words], AuthorType.Words) - self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Music], AuthorType.Music) - self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.WordsAndMusic], AuthorType.WordsAndMusic) - self.author_types_combo_box.addItem(AuthorType.Types[AuthorType.Translation], AuthorType.Translation) + for author_type in AuthorType.SortedTypes: + self.author_types_combo_box.addItem(AuthorType.Types[author_type], author_type) def load_topics(self): """ @@ -612,8 +609,17 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): self.author_edit_button.setEnabled(False) item = self.authors_list_view.currentItem() author_id, author_type = item.data(QtCore.Qt.UserRole) - - #dialog = QtGui.QDialog(self) + choice, ok = QtGui.QInputDialog.getItem(self, translate('SongsPlugin.EditSongForm', 'Edit Author Type'), + translate('SongsPlugin.EditSongForm', 'Choose type for this author'), + AuthorType.TranslatedTypes, + current=AuthorType.SortedTypes.index(author_type), + editable=False) + if not ok: + return + author = self.manager.get_object(Author, author_id) + author_type = AuthorType.from_translated_text(choice) + item.setData(QtCore.Qt.UserRole, (author_id, author_type)) + item.setText(author.get_display_name(author_type)) def on_author_remove_button_clicked(self): """ diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 16f7ea719..96a9e8c1f 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -69,17 +69,42 @@ class AuthorType(object): The 'words+music' type is not an official type, but is provided for convenience. """ + NoType = '' Words = 'words' Music = 'music' WordsAndMusic = 'words+music' Translation = 'translation' Types = { + NoType: '', Words: translate('SongsPlugin.AuthorType', 'Words', 'Author who wrote the lyrics of a song'), Music: translate('SongsPlugin.AuthorType', 'Music', 'Author who wrote the music of a song'), WordsAndMusic: translate('SongsPlugin.AuthorType', 'Words and Music', 'Author who wrote both lyrics and music of a song'), Translation: translate('SongsPlugin.AuthorType', 'Translation', 'Author who translated the song') } + SortedTypes = [ + NoType, + Words, + Music, + WordsAndMusic + ] + TranslatedTypes = [ + Types[NoType], + Types[Words], + Types[Music], + Types[WordsAndMusic] + ] + + @staticmethod + def from_translated_text(translated_type): + """ + Get the AuthorType from a translated string. + :param translated_type: Translated Author type. + """ + for key, value in AuthorType.Types.items(): + if value == translated_type: + return key + return None class Book(BaseModel): From 8e8288ddaacd440c3cce0b681f0ed2155ac4ead2 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Sat, 5 Jul 2014 22:04:17 +0200 Subject: [PATCH 41/69] Add test --- openlp/plugins/songs/lib/db.py | 2 +- tests/functional/openlp_plugins/songs/test_db.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 96a9e8c1f..a9206a397 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -104,7 +104,7 @@ class AuthorType(object): for key, value in AuthorType.Types.items(): if value == translated_type: return key - return None + return AuthorType.NoType class Book(BaseModel): diff --git a/tests/functional/openlp_plugins/songs/test_db.py b/tests/functional/openlp_plugins/songs/test_db.py index 3080db77e..53b98c045 100644 --- a/tests/functional/openlp_plugins/songs/test_db.py +++ b/tests/functional/openlp_plugins/songs/test_db.py @@ -112,3 +112,16 @@ class TestDB(TestCase): # THEN: It should have been removed and the other author should still be there self.assertEqual(1, len(song.authors_songs)) self.assertEqual(None, song.authors_songs[0].author_type) + + def test_get_author_type_from_translated_text(self): + """ + Test getting an author type from translated text + """ + # GIVEN: A string with an author type + author_type_name = AuthorType.Types[AuthorType.Words] + + # WHEN: We call the method + author_type = AuthorType.from_translated_text(author_type_name) + + # THEN: The type should be correct + self.assertEqual(author_type, AuthorType.Words) From 2938df5e022ed3aa2f1240742196ec14c701fb3e Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 6 Jul 2014 16:19:12 +0100 Subject: [PATCH 42/69] remove german --- resources/openlp.desktop | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/openlp.desktop b/resources/openlp.desktop index d585f4022..9f92f9d87 100755 --- a/resources/openlp.desktop +++ b/resources/openlp.desktop @@ -1,11 +1,9 @@ [Desktop Entry] Categories=AudioVideo; Exec=openlp %F -GenericName[de]=Church lyrics projection GenericName=Church lyrics projection Icon=openlp MimeType=application/x-openlp-service; -Name[de]=OpenLP Name=OpenLP StartupNotify=true Terminal=false From b92ca3f2093b0e4232df51edae584ec95e9a4c90 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 7 Jul 2014 13:17:24 +0200 Subject: [PATCH 43/69] Fix service up movement Fixes: https://launchpad.net/bugs/1338316 --- openlp/core/ui/servicemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 52afb5edc..592b01524 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1103,7 +1103,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage Moves the cursor selection up the window. Called by the up arrow. """ item = self.service_manager_list.currentItem() - item_before = self.service_manager_list.item_above(item) + item_before = self.service_manager_list.itemAbove(item) if item_before is None: return self.service_manager_list.setCurrentItem(item_before) From 201cfad9c48cdb66a63b45f27f73d4cf03f24aa0 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 7 Jul 2014 14:25:00 +0200 Subject: [PATCH 44/69] Remove unused imports --- openlp/plugins/songs/lib/powerpraiseimport.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/songs/lib/powerpraiseimport.py b/openlp/plugins/songs/lib/powerpraiseimport.py index 6a67619b3..ff30f9763 100644 --- a/openlp/plugins/songs/lib/powerpraiseimport.py +++ b/openlp/plugins/songs/lib/powerpraiseimport.py @@ -32,11 +32,9 @@ Powerpraise song files into the current database. """ import os -import base64 from lxml import objectify from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib import strip_rtf from .songimport import SongImport From b7a141f75ce6feb1182d0f18f63a28bff7f75efa Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 7 Jul 2014 15:30:55 +0200 Subject: [PATCH 45/69] Add Presentation Manager import Fixes: https://launchpad.net/bugs/957017 --- .../songs/lib/presentationmanagerimport.py | 93 +++++++++++++++++++ .../songs/test_presentationmanagerimport.py | 53 +++++++++++ .../Great Is Thy Faithfulness.json | 25 +++++ .../Great Is Thy Faithfulness.sng | 51 ++++++++++ 4 files changed, 222 insertions(+) create mode 100644 openlp/plugins/songs/lib/presentationmanagerimport.py create mode 100644 tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py create mode 100644 tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json create mode 100644 tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.sng diff --git a/openlp/plugins/songs/lib/presentationmanagerimport.py b/openlp/plugins/songs/lib/presentationmanagerimport.py new file mode 100644 index 000000000..11f4be81b --- /dev/null +++ b/openlp/plugins/songs/lib/presentationmanagerimport.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2013 Raoul Snyman # +# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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:`presentationmanagerimport` module provides the functionality for importing +Presentationmanager song files into the current database. +""" + +import os +from lxml import objectify + +from openlp.core.ui.wizard import WizardStrings +from .songimport import SongImport + + +class PresentationManagerImport(SongImport): + """ + The :class:`PresentationManagerImport` class provides OpenLP with the + ability to import Presentationmanager song files. + """ + def do_import(self): + self.import_wizard.progress_bar.setMaximum(len(self.import_source)) + for file_path in self.import_source: + if self.stop_import_flag: + return + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) + root = objectify.parse(open(file_path, 'rb')).getroot() + self.process_song(root) + + def process_song(self, root): + self.set_defaults() + self.title = str(root.attributes.title) + self.add_author(str(root.attributes.author)) + self.copyright = str(root.attributes.copyright) + self.ccli_number = str(root.attributes.ccli_number) + self.comments = str(root.attributes.comments) + verse_order_list = [] + verse_count = {} + duplicates = [] + for verse in root.verses.verse: + original_verse_def = verse.get('id') + # Presentation Manager stores duplicate verses instead of a verse order. + # We need to create the verse order from that. + is_duplicate = False + if original_verse_def in duplicates: + is_duplicate = True + else: + duplicates.append(original_verse_def) + if original_verse_def.startswith("Verse"): + verse_def = 'v' + elif original_verse_def.startswith("Chorus") or original_verse_def.startswith("Refrain"): + verse_def = 'c' + elif original_verse_def.startswith("Bridge"): + verse_def = 'b' + elif original_verse_def.startswith("End"): + verse_def = 'e' + else: + verse_def = 'o' + if not is_duplicate: # Only increment verse number if no duplicate + verse_count[verse_def] = verse_count.get(verse_def, 0) + 1 + verse_def = '%s%d' % (verse_def, verse_count[verse_def]) + if not is_duplicate: # Only add verse if no duplicate + self.add_verse(str(verse).strip(), verse_def) + verse_order_list.append(verse_def) + + self.verse_order_list = verse_order_list + if not self.finish(): + self.log_error(self.import_source) \ No newline at end of file diff --git a/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py b/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py new file mode 100644 index 000000000..34e49146e --- /dev/null +++ b/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2014 Raoul Snyman # +# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. # +# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, # +# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, # +# Frode Woldsund, Martin Zibricky, Patrick Zimmermann # +# --------------------------------------------------------------------------- # +# 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 PresentationManager song importer. +""" + +import os + +from tests.helpers.songfileimport import SongImportTestHelper + +TEST_PATH = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'presentationmanagersongs')) + + +class TestSongShowPlusFileImport(SongImportTestHelper): + + def __init__(self, *args, **kwargs): + self.importer_class_name = 'PresentationManagerImport' + self.importer_module_name = 'presentationmanagerimport' + super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs) + + def test_song_import(self): + """ + Test that loading a PresentationManager file works correctly + """ + self.file_import([os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.sng')], + self.load_external_result_data(os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.json'))) diff --git a/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json new file mode 100644 index 000000000..5a5c3ddaf --- /dev/null +++ b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json @@ -0,0 +1,25 @@ +{ + "title": "Great Is Thy Faithfulness", + "authors": [ + "Thomas O. Chisholm (1866-1960)" + ], + "verse_order_list": [], + "verses": [ + [ + "\"Great is Thy faithfulness\", O God my Father.\nThere is no shadow of turning with Thee;\nThou changest not, Thy compassions they fail not,\nAs Thou hast been Thou forever shall be.", + "v1" + ], + [ + "Great is Thy faithfulness!\nGreat is Thy faithfulness!\nMorning by morning new mercies I see!\nAll I have needed Thy hand hath provided -\n\"Great is Thy faithfulness\", Lord, unto me!", + "c1" + ], + [ + "Summer and winter, and springtime and harvest,\nSun, moon, and stars in their courses above,\nJoin with all nature in manifold witness,\nTo Thy great faithfulness, mercy and love.", + "v2" + ], + [ + "Pardon for sin and a peace that endureth,\nThine own dear presence to cheer and to guide,\nStrength for today and bright hope for tomorrow,\nBlessings all mine, with ten thousand beside!", + "v3" + ] + ] +} \ No newline at end of file diff --git a/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.sng b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.sng new file mode 100644 index 000000000..49b29c4c7 --- /dev/null +++ b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.sng @@ -0,0 +1,51 @@ + + + +Great Is Thy Faithfulness +Thomas O. Chisholm (1866-1960) + + + + + + +"Great is Thy faithfulness", O God my Father. +There is no shadow of turning with Thee; +Thou changest not, Thy compassions they fail not, +As Thou hast been Thou forever shall be. + + +Great is Thy faithfulness! +Great is Thy faithfulness! +Morning by morning new mercies I see! +All I have needed Thy hand hath provided - +"Great is Thy faithfulness", Lord, unto me! + + +Summer and winter, and springtime and harvest, +Sun, moon, and stars in their courses above, +Join with all nature in manifold witness, +To Thy great faithfulness, mercy and love. + + +Great is Thy faithfulness! +Great is Thy faithfulness! +Morning by morning new mercies I see! +All I have needed Thy hand hath provided - +"Great is Thy faithfulness", Lord, unto me! + + +Pardon for sin and a peace that endureth, +Thine own dear presence to cheer and to guide, +Strength for today and bright hope for tomorrow, +Blessings all mine, with ten thousand beside! + + +Great is Thy faithfulness! +Great is Thy faithfulness! +Morning by morning new mercies I see! +All I have needed Thy hand hath provided - +"Great is Thy faithfulness", Lord, unto me! + + + From 398508f49b019c01cc0828e747ffd6fc0803504b Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 7 Jul 2014 15:36:07 +0200 Subject: [PATCH 46/69] Gui entry --- openlp/plugins/songs/lib/importer.py | 33 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 6d01da309..19543575b 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -51,12 +51,11 @@ from .foilpresenterimport import FoilPresenterImport from .zionworximport import ZionWorxImport from .propresenterimport import ProPresenterImport from .worshipassistantimport import WorshipAssistantImport -# Imports that might fail - +from .presentationmanagerimport import PresentationManagerImport log = logging.getLogger(__name__) - +# Imports that might fail try: from .sofimport import SofImport HAS_SOF = True @@ -161,16 +160,17 @@ class SongFormat(object): MediaShout = 9 OpenSong = 10 PowerSong = 11 - ProPresenter = 12 - SongBeamer = 13 - SongPro = 14 - SongShowPlus = 15 - SongsOfFellowship = 16 - SundayPlus = 17 - WordsOfWorship = 18 - WorshipAssistant = 19 - WorshipCenterPro = 20 - ZionWorx = 21 + PresentationManager = 12 + ProPresenter = 13 + SongBeamer = 14 + SongPro = 15 + SongShowPlus = 16 + SongsOfFellowship = 17 + SundayPlus = 18 + WordsOfWorship = 19 + WorshipAssistant = 20 + WorshipCenterPro = 21 + ZionWorx = 22 # Set optional attribute defaults __defaults__ = { @@ -274,6 +274,12 @@ class SongFormat(object): 'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', 'You need to specify a valid PowerSong 1.0 ' 'database folder.') }, + PresentationManager: { + 'class': PresentationManagerImport, + 'name': 'PresentationManager', + 'prefix': 'presentationManager', + 'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'PresentationManager Song Files') + }, ProPresenter: { 'class': ProPresenterImport, 'name': 'ProPresenter', @@ -375,6 +381,7 @@ class SongFormat(object): SongFormat.MediaShout, SongFormat.OpenSong, SongFormat.PowerSong, + SongFormat.PresentationManager, SongFormat.ProPresenter, SongFormat.SongBeamer, SongFormat.SongPro, From df6669220a49aba2c141e2ac1375a33db400be54 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 7 Jul 2014 18:17:54 +0200 Subject: [PATCH 47/69] Space --- openlp/plugins/songs/lib/importer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 6e4aa1fc7..56e4ace01 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -34,7 +34,6 @@ import logging from openlp.core.common import translate, UiStrings from openlp.core.ui.wizard import WizardStrings - from .importers.opensong import OpenSongImport from .importers.easyslides import EasySlidesImport from .importers.openlp import OpenLPSongImport @@ -56,7 +55,6 @@ from .importers.presentationmanager import PresentationManagerImport log = logging.getLogger(__name__) - # Imports that might fail try: from .importers.songsoffellowship import SongsOfFellowshipImport From c1df88693dca0e7bc3fc8e0848b6fcf5a9e6cae1 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 9 Jul 2014 14:19:32 +0200 Subject: [PATCH 48/69] Revert changes --- openlp/plugins/songs/forms/editsongdialog.py | 8 ++++---- openlp/plugins/songs/forms/editsongform.py | 13 +++++++++++++ openlp/plugins/songs/lib/mediaitem.py | 3 +-- openlp/plugins/songs/lib/upgrade.py | 19 +++---------------- .../openlp_plugins/songs/test_mediaitem.py | 12 ++++++------ 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/openlp/plugins/songs/forms/editsongdialog.py b/openlp/plugins/songs/forms/editsongdialog.py index 6abdf5f4f..a9ca71946 100644 --- a/openlp/plugins/songs/forms/editsongdialog.py +++ b/openlp/plugins/songs/forms/editsongdialog.py @@ -218,12 +218,12 @@ class Ui_EditSongDialog(object): self.rights_layout.setObjectName('rights_layout') self.copyright_layout = QtGui.QHBoxLayout() self.copyright_layout.setObjectName('copyright_layout') - self.copyright_label = QtGui.QLabel(self.rights_group_box) - self.copyright_label.setObjectName('copyright_label') - self.copyright_layout.addWidget(self.copyright_label) self.copyright_edit = QtGui.QLineEdit(self.rights_group_box) self.copyright_edit.setObjectName('copyright_edit') self.copyright_layout.addWidget(self.copyright_edit) + self.copyright_insert_button = QtGui.QToolButton(self.rights_group_box) + self.copyright_insert_button.setObjectName('copyright_insert_button') + self.copyright_layout.addWidget(self.copyright_insert_button) self.rights_layout.addLayout(self.copyright_layout) self.ccli_layout = QtGui.QHBoxLayout() self.ccli_layout.setObjectName('ccli_layout') @@ -318,7 +318,7 @@ class Ui_EditSongDialog(object): self.theme_group_box.setTitle(UiStrings().Theme) self.theme_add_button.setText(translate('SongsPlugin.EditSongForm', 'New &Theme')) self.rights_group_box.setTitle(translate('SongsPlugin.EditSongForm', 'Copyright Information')) - self.copyright_label.setText(translate('SongsPlugin.EditSongForm', 'Copyright:')) + self.copyright_insert_button.setText(SongStrings.CopyrightSymbol) self.ccli_label.setText(UiStrings().CCLINumberLabel) self.comments_group_box.setTitle(translate('SongsPlugin.EditSongForm', 'Comments')) self.song_tab_widget.setTabText(self.song_tab_widget.indexOf(self.theme_tab), diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 3af7522d2..2125922fe 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -75,6 +75,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): self.topic_add_button.clicked.connect(self.on_topic_add_button_clicked) self.topic_remove_button.clicked.connect(self.on_topic_remove_button_clicked) self.topics_list_view.itemClicked.connect(self.on_topic_list_view_clicked) + self.copyright_insert_button.clicked.connect(self.on_copyright_insert_button_triggered) self.verse_add_button.clicked.connect(self.on_verse_add_button_clicked) self.verse_list_widget.doubleClicked.connect(self.on_verse_edit_button_clicked) self.verse_edit_button.clicked.connect(self.on_verse_edit_button_clicked) @@ -795,6 +796,18 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties): label_text = self.not_all_verses_used_warning self.warning_label.setText(label_text) + def on_copyright_insert_button_triggered(self): + """ + Copyright insert button pressed + """ + text = self.copyright_edit.text() + pos = self.copyright_edit.cursorPosition() + sign = SongStrings.CopyrightSymbol + text = text[:pos] + sign + text[pos:] + self.copyright_edit.setText(text) + self.copyright_edit.setFocus() + self.copyright_edit.setCursorPosition(pos + len(sign)) + def on_maintenance_button_clicked(self): """ Maintenance button pressed diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index c4eaa73e8..d57c8fbcc 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -506,8 +506,7 @@ class SongMediaItem(MediaManagerItem): if authors_translation: item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation], create_separated_list(authors_translation))) - if song.copyright: - item.raw_footer.append('%s %s' % (SongStrings.CopyrightSymbol, song.copyright)) + item.raw_footer.append(song.copyright) if self.display_songbook and song.book: item.raw_footer.append("%s #%s" % (song.book.name, song.song_number)) if Settings().value('core/ccli number'): diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index df841b39c..580ae767d 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -27,7 +27,8 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`upgrade` module provides a way for the database and schema that is the backend for the Songs plugin +The :mod:`upgrade` module provides a way for the database and schema that is the +backend for the Songs plugin """ import logging @@ -38,7 +39,7 @@ from sqlalchemy.sql.expression import func, false, null, text from openlp.core.lib.db import get_upgrade_op log = logging.getLogger(__name__) -__version__ = 5 +__version__ = 4 def upgrade_1(session, metadata): @@ -118,17 +119,3 @@ def upgrade_4(session, metadata): op.rename_table('authors_songs_tmp', 'authors_songs') except OperationalError: log.info('Upgrade 4 has already been run') - - -def upgrade_5(session, metadata): - """ - Version 5 upgrade - - This upgrade removes all hard-coded copyright symbols from the copyright field in the songs. - The copyright symbol is now being added directly in the footer. - """ - try: - op = get_upgrade_op(session) - op.execute('UPDATE songs SET copyright=TRIM(REPLACE(copyright, "©", ""))') - except OperationalError: - log.info('Upgrade 5 has already been run') diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index da6ae4b71..bc22a4577 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -58,7 +58,7 @@ class TestMediaItem(TestCase, TestMixin): author_list = self.media_item.generate_footer(service_item, mock_song) # THEN: I get the following Array returned - self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', '© My copyright'], + self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', 'My copyright'], 'The array should be returned correctly with a song, one author and copyright') self.assertEqual(author_list, ['my author'], 'The author list should be returned correctly with one author') @@ -97,7 +97,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: I get the following Array returned self.assertEqual(service_item.raw_footer, ['My Song', 'Words: another author', 'Music: my author', - 'Translation: translator', '© My copyright'], + 'Translation: translator', 'My copyright'], 'The array should be returned correctly with a song, two authors and copyright') self.assertEqual(author_list, ['another author', 'my author', 'translator'], 'The author list should be returned correctly with two authors') @@ -117,7 +117,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: I get the following Array returned - self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'CCLI License: 1234'], + self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 1234'], 'The array should be returned correctly with a song, an author, copyright and ccli') # WHEN: I amend the CCLI value @@ -125,7 +125,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: I would get an amended footer string - self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'CCLI License: 4321'], + self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 4321'], 'The array should be returned correctly with a song, an author, copyright and amended ccli') def build_song_footer_base_songbook_test(self): @@ -145,14 +145,14 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.generate_footer(service_item, mock_song) # THEN: The songbook should not be in the footer - self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright']) + self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright']) # WHEN: I activate the "display songbook" option self.media_item.display_songbook = True self.media_item.generate_footer(service_item, mock_song) # THEN: The songbook should be in the footer - self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright', 'My songbook #12']) + self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12']) def authors_match_test(self): """ From 383f7ef6e2128f74fb3d9a060e80dada09ebeb45 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 9 Jul 2014 14:33:26 +0200 Subject: [PATCH 49/69] Option for displaying copyright symbol --- openlp/plugins/songs/lib/mediaitem.py | 11 +++++++++-- openlp/plugins/songs/lib/songstab.py | 14 ++++++++++++++ openlp/plugins/songs/songsplugin.py | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index fde103c5f..0d4fe5908 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -36,7 +36,7 @@ from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_ from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate -from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItem, ServiceItemContext, \ +from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \ check_item_selected, create_separated_list from openlp.core.lib.ui import create_widget_action from openlp.plugins.songs.forms.editsongform import EditSongForm @@ -126,6 +126,7 @@ class SongMediaItem(MediaManagerItem): self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit') self.add_song_from_service = Settings().value(self.settings_section + '/add song from service') self.display_songbook = Settings().value(self.settings_section + '/display songbook') + self.display_copyright_symbol = Settings().value(self.settings_section + '/display copyright symbol') def retranslateUi(self): self.search_text_label.setText('%s:' % UiStrings().Search) @@ -506,7 +507,13 @@ class SongMediaItem(MediaManagerItem): if authors_translation: item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation], create_separated_list(authors_translation))) - item.raw_footer.append(song.copyright) + if song.copyright: + if self.display_copyright_symbol: + print("copyright") + item.raw_footer.append("%s %s" % (SongStrings.CopyrightSymbol, song.copyright)) + else: + print("no copyright") + item.raw_footer.append(song.copyright) if self.display_songbook and song.book: item.raw_footer.append("%s #%s" % (song.book.name, song.song_number)) if Settings().value('core/ccli number'): diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 1cf06d047..09d409c4a 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.common import Settings, translate from openlp.core.lib import SettingsTab +from openlp.plugins.songs.lib.ui import SongStrings class SongsTab(SettingsTab): @@ -62,6 +63,9 @@ class SongsTab(SettingsTab): self.display_songbook_check_box = QtGui.QCheckBox(self.mode_group_box) self.display_songbook_check_box.setObjectName('songbook_check_box') self.mode_layout.addWidget(self.display_songbook_check_box) + self.display_copyright_check_box = QtGui.QCheckBox(self.mode_group_box) + self.display_copyright_check_box.setObjectName('copyright_check_box') + self.mode_layout.addWidget(self.display_copyright_check_box) self.left_layout.addWidget(self.mode_group_box) self.left_layout.addStretch() self.right_layout.addStretch() @@ -70,6 +74,7 @@ class SongsTab(SettingsTab): self.update_on_edit_check_box.stateChanged.connect(self.on_update_on_edit_check_box_changed) self.add_from_service_check_box.stateChanged.connect(self.on_add_from_service_check_box_changed) self.display_songbook_check_box.stateChanged.connect(self.on_songbook_check_box_changed) + self.display_copyright_check_box.stateChanged.connect(self.on_copyright_check_box_changed) def retranslateUi(self): self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Songs Mode')) @@ -80,6 +85,9 @@ class SongsTab(SettingsTab): self.add_from_service_check_box.setText(translate('SongsPlugin.SongsTab', 'Import missing songs from service files')) self.display_songbook_check_box.setText(translate('SongsPlugin.SongsTab', 'Display songbook in footer')) + self.display_copyright_check_box.setText(translate('SongsPlugin.SongsTab', + 'Display "%s" symbol before copyright info' % + SongStrings.CopyrightSymbol)) def on_search_as_type_check_box_changed(self, check_state): self.song_search = (check_state == QtCore.Qt.Checked) @@ -96,6 +104,9 @@ class SongsTab(SettingsTab): def on_songbook_check_box_changed(self, check_state): self.display_songbook = (check_state == QtCore.Qt.Checked) + def on_copyright_check_box_changed(self, check_state): + self.display_copyright_symbol = (check_state == QtCore.Qt.Checked) + def load(self): settings = Settings() settings.beginGroup(self.settings_section) @@ -104,11 +115,13 @@ class SongsTab(SettingsTab): self.update_edit = settings.value('update service on edit') self.update_load = settings.value('add song from service') self.display_songbook = settings.value('display songbook') + self.display_copyright_symbol = settings.value('display copyright symbol') self.search_as_type_check_box.setChecked(self.song_search) self.tool_bar_active_check_box.setChecked(self.tool_bar) self.update_on_edit_check_box.setChecked(self.update_edit) self.add_from_service_check_box.setChecked(self.update_load) self.display_songbook_check_box.setChecked(self.display_songbook) + self.display_copyright_check_box.setChecked(self.display_copyright_symbol) settings.endGroup() def save(self): @@ -119,6 +132,7 @@ class SongsTab(SettingsTab): settings.setValue('update service on edit', self.update_edit) settings.setValue('add song from service', self.update_load) settings.setValue('display songbook', self.display_songbook) + settings.setValue('display copyright symbol', self.display_copyright_symbol) settings.endGroup() if self.tab_visited: self.settings_form.register_post_process('songs_config_updated') diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 5cbedc994..56834a6eb 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -64,6 +64,7 @@ __default_settings__ = { 'songs/add song from service': True, 'songs/display songbar': True, 'songs/display songbook': False, + 'songs/display copyright symbol': False, 'songs/last directory import': '', 'songs/last directory export': '', 'songs/songselect username': '', From 79009a1a7fce07d8fef5600ac9374696fb1373c7 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 9 Jul 2014 14:41:55 +0200 Subject: [PATCH 50/69] Add test --- .../openlp_plugins/songs/test_mediaitem.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index bc22a4577..f3ae511ea 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -28,6 +28,7 @@ class TestMediaItem(TestCase, TestMixin): patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'): self.media_item = SongMediaItem(None, MagicMock()) self.media_item.display_songbook = False + self.media_item.display_copyright_symbol = False self.get_application() self.build_settings() QtCore.QLocale.setDefault(QtCore.QLocale('en_GB')) @@ -154,6 +155,23 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The songbook should be in the footer self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12']) + def build_song_footer_copyright_test(self): + """ + Test building song footer with displaying the copyright symbol + """ + # GIVEN: A Song and a Service Item; displaying the copyright symbol is enabled + self.media_item.display_copyright_symbol = True + mock_song = MagicMock() + mock_song.title = 'My Song' + mock_song.copyright = 'My copyright' + service_item = ServiceItem(None) + + # WHEN: I generate the Footer with default settings + self.media_item.generate_footer(service_item, mock_song) + + # THEN: The copyright symbol should be in the footer + self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright']) + def authors_match_test(self): """ Test the author matching when importing a song from a service From 6d5e6f0fafb0e290123ecf4429ff572422c60e15 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Wed, 9 Jul 2014 14:45:54 +0200 Subject: [PATCH 51/69] Remove debug output --- openlp/plugins/songs/lib/mediaitem.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 0d4fe5908..33c4f2e53 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -509,10 +509,8 @@ class SongMediaItem(MediaManagerItem): create_separated_list(authors_translation))) if song.copyright: if self.display_copyright_symbol: - print("copyright") item.raw_footer.append("%s %s" % (SongStrings.CopyrightSymbol, song.copyright)) else: - print("no copyright") item.raw_footer.append(song.copyright) if self.display_songbook and song.book: item.raw_footer.append("%s #%s" % (song.book.name, song.song_number)) From 53cb11e03e5f3dacbffb3aaf8facacfa594d2af9 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Fri, 11 Jul 2014 16:19:53 +0200 Subject: [PATCH 52/69] EOF; verse order fixed --- openlp/plugins/songs/lib/importers/presentationmanager.py | 2 +- .../presentationmanagersongs/Great Is Thy Faithfulness.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index 4ea08076e..52a047a30 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -90,4 +90,4 @@ class PresentationManagerImport(SongImport): self.verse_order_list = verse_order_list if not self.finish(): - self.log_error(self.import_source) \ No newline at end of file + self.log_error(self.import_source) diff --git a/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json index 5a5c3ddaf..1e484b11b 100644 --- a/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json +++ b/tests/resources/presentationmanagersongs/Great Is Thy Faithfulness.json @@ -3,7 +3,7 @@ "authors": [ "Thomas O. Chisholm (1866-1960)" ], - "verse_order_list": [], + "verse_order_list": ["v1", "c1", "v2", "c1", "v3", "c1"], "verses": [ [ "\"Great is Thy faithfulness\", O God my Father.\nThere is no shadow of turning with Thee;\nThou changest not, Thy compassions they fail not,\nAs Thou hast been Thou forever shall be.", @@ -22,4 +22,4 @@ "v3" ] ] -} \ No newline at end of file +} From 79c5d61d9483f7cf0b63be3aeadc3afca1a72862 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Sat, 12 Jul 2014 22:00:58 +0200 Subject: [PATCH 53/69] Negative test --- .../openlp_plugins/songs/test_mediaitem.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index f3ae511ea..a473f8569 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -155,7 +155,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The songbook should be in the footer self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12']) - def build_song_footer_copyright_test(self): + def build_song_footer_copyright_enabled_test(self): """ Test building song footer with displaying the copyright symbol """ @@ -172,6 +172,22 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The copyright symbol should be in the footer self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright']) + def build_song_footer_copyright_disabled_test(self): + """ + Test building song footer without displaying the copyright symbol + """ + # GIVEN: A Song and a Service Item; displaying the copyright symbol should be disabled by default + mock_song = MagicMock() + mock_song.title = 'My Song' + mock_song.copyright = 'My copyright' + service_item = ServiceItem(None) + + # WHEN: I generate the Footer with default settings + self.media_item.generate_footer(service_item, mock_song) + + # THEN: The copyright symbol should not be in the footer + self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright']) + def authors_match_test(self): """ Test the author matching when importing a song from a service From f2d3bbee475d43e4f8c72499b7c887743cdb52bf Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 13 Jul 2014 01:47:53 +0200 Subject: [PATCH 54/69] Added the name of the current item to the service controller, and added some more tests --- openlp/core/ui/slidecontroller.py | 24 +- .../openlp_core_ui/test_slidecontroller.py | 504 +++++++++++++++++- 2 files changed, 512 insertions(+), 16 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index bf92e9d76..44c28deb6 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -96,6 +96,8 @@ class DisplayController(QtGui.QWidget): """ This is the generic function to send signal for control widgets, created from within other plugins This function is needed to catch the current controller + + :param args: Arguments to send to the plugins """ sender = self.sender().objectName() if self.sender().objectName() else self.sender().text() controller = self @@ -143,11 +145,19 @@ class SlideController(DisplayController, RegistryProperties): self.panel_layout = QtGui.QVBoxLayout(self.panel) self.panel_layout.setSpacing(0) self.panel_layout.setMargin(0) - # Type label for the top of the slide controller + # Type label at the top of the slide controller self.type_label = QtGui.QLabel(self.panel) self.type_label.setStyleSheet('font-weight: bold; font-size: 12pt;') self.type_label.setAlignment(QtCore.Qt.AlignCenter) + if self.is_live: + self.type_label.setText(UiStrings().Live) + else: + self.type_label.setText(UiStrings().Preview) self.panel_layout.addWidget(self.type_label) + # Info label for the title of the current item, at the top of the slide controller + self.info_label = QtGui.QLabel(self.panel) + self.info_label.setAlignment(QtCore.Qt.AlignCenter) + self.panel_layout.addWidget(self.info_label) # Splitter self.splitter = QtGui.QSplitter(self.panel) self.splitter.setOrientation(QtCore.Qt.Vertical) @@ -402,12 +412,17 @@ class SlideController(DisplayController, RegistryProperties): """ try: from openlp.plugins.songs.lib import VerseType - SONGS_PLUGIN_AVAILABLE = True + is_songs_plugin_available = True except ImportError: - SONGS_PLUGIN_AVAILABLE = False + class VerseType(object): + """ + This empty class is mostly just to satisfy Python, PEP8 and PyCharm + """ + pass + is_songs_plugin_available = False sender_name = self.sender().objectName() verse_type = sender_name[15:] if sender_name[:15] == 'shortcutAction_' else '' - if SONGS_PLUGIN_AVAILABLE: + if is_songs_plugin_available: if verse_type == 'V': self.current_shortcut = VerseType.translated_tags[VerseType.Verse] elif verse_type == 'C': @@ -777,6 +792,7 @@ class SlideController(DisplayController, RegistryProperties): if service_item.is_command(): Registry().execute( '%s_start' % service_item.name.lower(), [self.service_item, self.is_live, self.hide_mode(), slide_no]) + self.info_label.setText(self.service_item.title) self.slide_list = {} if self.is_live: self.song_menu.menu().clear() diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index 104c83750..3a1e754f8 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -30,10 +30,13 @@ Package to test the openlp.core.ui.slidecontroller package. """ from unittest import TestCase +from openlp.core import Registry +from openlp.core.lib import ServiceItemAction from openlp.core.ui import SlideController +from openlp.core.ui.slidecontroller import WIDE_MENU, NON_TEXT_MENU -from tests.interfaces import MagicMock +from tests.interfaces import MagicMock, patch class TestSlideController(TestCase): @@ -42,37 +45,514 @@ class TestSlideController(TestCase): """ Test the initial slide controller state . """ - # GIVEN: A new slideController instance. + # GIVEN: A new SlideController instance. slide_controller = SlideController(None) + # WHEN: the default controller is built. # THEN: The controller should not be a live controller. self.assertEqual(slide_controller.is_live, False, 'The base slide controller should not be a live controller') - def toggle_blank_test(self): + def text_service_item_blank_test(self): """ - Test the setting of the display blank icons by display type. + Test that loading a text-based service item into the slide controller sets the correct blank menu """ - # GIVEN: A new slideController instance. + # GIVEN: A new SlideController instance. slide_controller = SlideController(None) service_item = MagicMock() toolbar = MagicMock() - toolbar.set_widget_visible = self.dummy_widget_visible + toolbar.set_widget_visible = MagicMock() slide_controller.toolbar = toolbar slide_controller.service_item = service_item - # WHEN a text based service item is used + # WHEN: a text based service item is used slide_controller.service_item.is_text = MagicMock(return_value=True) slide_controller.set_blank_menu() - # THEN: then call set up the toolbar to blank the display screen. - self.assertEqual(len(self.test_widget), 3, 'There should be three icons to display on the screen') + # THEN: the call to set the visible items on the toolbar should be correct + toolbar.set_widget_visible.assert_called_with(WIDE_MENU, True) + + def non_text_service_item_blank_test(self): + """ + Test that loading a non-text service item into the slide controller sets the correct blank menu + """ + # GIVEN: A new SlideController instance. + slide_controller = SlideController(None) + service_item = MagicMock() + toolbar = MagicMock() + toolbar.set_widget_visible = MagicMock() + slide_controller.toolbar = toolbar + slide_controller.service_item = service_item # WHEN a non text based service item is used slide_controller.service_item.is_text = MagicMock(return_value=False) slide_controller.set_blank_menu() # THEN: then call set up the toolbar to blank the display screen. - self.assertEqual(len(self.test_widget), 2, 'There should be only two icons to display on the screen') + toolbar.set_widget_visible.assert_called_with(NON_TEXT_MENU, True) - def dummy_widget_visible(self, widget, visible=True): - self.test_widget = widget + def receive_spin_delay_test(self): + """ + Test that the spin box is updated accordingly after a call to receive_spin_delay() + """ + with patch('openlp.core.ui.slidecontroller.Settings') as MockedSettings: + # GIVEN: A new SlideController instance. + mocked_value = MagicMock(return_value=1) + MockedSettings.return_value = MagicMock(value=mocked_value) + mocked_delay_spin_box = MagicMock() + slide_controller = SlideController(None) + slide_controller.delay_spin_box = mocked_delay_spin_box + + # WHEN: The receive_spin_delay() method is called + slide_controller.receive_spin_delay() + + # THEN: The Settings()value() and delay_spin_box.setValue() methods should have been called correctly + mocked_value.assert_called_with('core/loop delay') + mocked_delay_spin_box.setValue.assert_called_with(1) + + def toggle_display_blank_test(self): + """ + Check that the toggle_display('blank') method calls the on_blank_display() method + """ + # GIVEN: A new SlideController instance. + mocked_on_blank_display = MagicMock() + mocked_on_theme_display = MagicMock() + mocked_on_hide_display = MagicMock() + slide_controller = SlideController(None) + slide_controller.on_blank_display = mocked_on_blank_display + slide_controller.on_theme_display = mocked_on_theme_display + slide_controller.on_hide_display = mocked_on_hide_display + + # WHEN: toggle_display() is called with an argument of "blank" + slide_controller.toggle_display('blank') + + # THEN: Only on_blank_display() should have been called with an argument of True + mocked_on_blank_display.assert_called_once_with(True) + self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') + self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') + + def toggle_display_hide_test(self): + """ + Check that the toggle_display('hide') method calls the on_blank_display() method + """ + # GIVEN: A new SlideController instance. + mocked_on_blank_display = MagicMock() + mocked_on_theme_display = MagicMock() + mocked_on_hide_display = MagicMock() + slide_controller = SlideController(None) + slide_controller.on_blank_display = mocked_on_blank_display + slide_controller.on_theme_display = mocked_on_theme_display + slide_controller.on_hide_display = mocked_on_hide_display + + # WHEN: toggle_display() is called with an argument of "hide" + slide_controller.toggle_display('hide') + + # THEN: Only on_blank_display() should have been called with an argument of True + mocked_on_blank_display.assert_called_once_with(True) + self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') + self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') + + def toggle_display_theme_test(self): + """ + Check that the toggle_display('theme') method calls the on_theme_display() method + """ + # GIVEN: A new SlideController instance. + mocked_on_blank_display = MagicMock() + mocked_on_theme_display = MagicMock() + mocked_on_hide_display = MagicMock() + slide_controller = SlideController(None) + slide_controller.on_blank_display = mocked_on_blank_display + slide_controller.on_theme_display = mocked_on_theme_display + slide_controller.on_hide_display = mocked_on_hide_display + + # WHEN: toggle_display() is called with an argument of "theme" + slide_controller.toggle_display('theme') + + # THEN: Only on_theme_display() should have been called with an argument of True + mocked_on_theme_display.assert_called_once_with(True) + self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called') + self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') + + def toggle_display_desktop_test(self): + """ + Check that the toggle_display('desktop') method calls the on_hide_display() method + """ + # GIVEN: A new SlideController instance. + mocked_on_blank_display = MagicMock() + mocked_on_theme_display = MagicMock() + mocked_on_hide_display = MagicMock() + slide_controller = SlideController(None) + slide_controller.on_blank_display = mocked_on_blank_display + slide_controller.on_theme_display = mocked_on_theme_display + slide_controller.on_hide_display = mocked_on_hide_display + + # WHEN: toggle_display() is called with an argument of "desktop" + slide_controller.toggle_display('desktop') + + # THEN: Only on_hide_display() should have been called with an argument of True + mocked_on_hide_display.assert_called_once_with(True) + self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called') + self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') + + def toggle_display_show_test(self): + """ + Check that the toggle_display('show') method calls all the on_X_display() methods + """ + # GIVEN: A new SlideController instance. + mocked_on_blank_display = MagicMock() + mocked_on_theme_display = MagicMock() + mocked_on_hide_display = MagicMock() + slide_controller = SlideController(None) + slide_controller.on_blank_display = mocked_on_blank_display + slide_controller.on_theme_display = mocked_on_theme_display + slide_controller.on_hide_display = mocked_on_hide_display + + # WHEN: toggle_display() is called with an argument of "show" + slide_controller.toggle_display('show') + + # THEN: All the on_X_display() methods should have been called with an argument of False + mocked_on_blank_display.assert_called_once_with(False) + mocked_on_theme_display.assert_called_once_with(False) + mocked_on_hide_display.assert_called_once_with(False) + + def live_escape_test(self): + """ + Test that when the live_escape() method is called, the display is set to invisible and any media is stopped + """ + # GIVEN: A new SlideController instance and mocked out display and media_controller + mocked_display = MagicMock() + mocked_media_controller = MagicMock() + Registry.create() + Registry().register('media_controller', mocked_media_controller) + slide_controller = SlideController(None) + slide_controller.display = mocked_display + + # WHEN: live_escape() is called + slide_controller.live_escape() + + # THEN: the display should be set to invisible and the media controller stopped + mocked_display.setVisible.assert_called_once_with(False) + mocked_media_controller.media_stop.assert_called_once_with(slide_controller) + + def service_previous_test(self): + """ + Check that calling the service_previous() method adds the previous key to the queue and processes the queue + """ + # GIVEN: A new SlideController instance. + mocked_keypress_queue = MagicMock() + mocked_process_queue = MagicMock() + slide_controller = SlideController(None) + slide_controller.keypress_queue = mocked_keypress_queue + slide_controller._process_queue = mocked_process_queue + + # WHEN: The service_previous() method is called + slide_controller.service_previous() + + # THEN: The keypress is added to the queue and the queue is processed + mocked_keypress_queue.append.assert_called_once_with(ServiceItemAction.Previous) + mocked_process_queue.assert_called_once_with() + + def service_next_test(self): + """ + Check that calling the service_next() method adds the next key to the queue and processes the queue + """ + # GIVEN: A new SlideController instance and mocked out methods + mocked_keypress_queue = MagicMock() + mocked_process_queue = MagicMock() + slide_controller = SlideController(None) + slide_controller.keypress_queue = mocked_keypress_queue + slide_controller._process_queue = mocked_process_queue + + # WHEN: The service_next() method is called + slide_controller.service_next() + + # THEN: The keypress is added to the queue and the queue is processed + mocked_keypress_queue.append.assert_called_once_with(ServiceItemAction.Next) + mocked_process_queue.assert_called_once_with() + + def update_slide_limits_test(self): + """ + Test that calling the update_slide_limits() method updates the slide limits + """ + # GIVEN: A mocked out Settings object, a new SlideController and a mocked out main_window + with patch('openlp.core.ui.slidecontroller.Settings') as MockedSettings: + mocked_value = MagicMock(return_value=10) + MockedSettings.return_value = MagicMock(value=mocked_value) + mocked_main_window = MagicMock(advanced_settings_section='advanced') + Registry.create() + Registry().register('main_window', mocked_main_window) + slide_controller = SlideController(None) + + # WHEN: update_slide_limits() is called + slide_controller.update_slide_limits() + + # THEN: The value of slide_limits should be 10 + mocked_value.assert_called_once_with('advanced/slide limits') + self.assertEqual(10, slide_controller.slide_limits, 'Slide limits should have been updated to 10') + + def enable_tool_bar_live_test(self): + """ + Check that when enable_tool_bar on a live slide controller is called, enable_live_tool_bar is called + """ + # GIVEN: Mocked out enable methods and a real slide controller which is set to live + mocked_enable_live_tool_bar = MagicMock() + mocked_enable_preview_tool_bar = MagicMock() + slide_controller = SlideController(None) + slide_controller.is_live = True + slide_controller.enable_live_tool_bar = mocked_enable_live_tool_bar + slide_controller.enable_preview_tool_bar = mocked_enable_preview_tool_bar + mocked_service_item = MagicMock() + + # WHEN: enable_tool_bar() is called + slide_controller.enable_tool_bar(mocked_service_item) + + # THEN: The enable_live_tool_bar() method is called, not enable_preview_tool_bar() + mocked_enable_live_tool_bar.assert_called_once_with(mocked_service_item) + self.assertEqual(0, mocked_enable_preview_tool_bar.call_count, 'The preview method should not have been called') + + def enable_tool_bar_preview_test(self): + """ + Check that when enable_tool_bar on a preview slide controller is called, enable_preview_tool_bar is called + """ + # GIVEN: Mocked out enable methods and a real slide controller which is set to live + mocked_enable_live_tool_bar = MagicMock() + mocked_enable_preview_tool_bar = MagicMock() + slide_controller = SlideController(None) + slide_controller.is_live = False + slide_controller.enable_live_tool_bar = mocked_enable_live_tool_bar + slide_controller.enable_preview_tool_bar = mocked_enable_preview_tool_bar + mocked_service_item = MagicMock() + + # WHEN: enable_tool_bar() is called + slide_controller.enable_tool_bar(mocked_service_item) + + # THEN: The enable_preview_tool_bar() method is called, not enable_live_tool_bar() + mocked_enable_preview_tool_bar.assert_called_once_with(mocked_service_item) + self.assertEqual(0, mocked_enable_live_tool_bar.call_count, 'The live method should not have been called') + + def refresh_service_item_text_test(self): + """ + Test that the refresh_service_item() method refreshes a text service item + """ + # GIVEN: A mock service item and a fresh slide controller + mocked_service_item = MagicMock() + mocked_service_item.is_text.return_value = True + mocked_service_item.is_image.return_value = False + mocked_process_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_service_item + slide_controller._process_item = mocked_process_item + slide_controller.selected_row = 5 + + # WHEN: The refresh_service_item method() is called + slide_controller.refresh_service_item() + + # THEN: The item should be re-processed + mocked_service_item.is_text.assert_called_once_with() + self.assertEqual(0, mocked_service_item.is_image.call_count, 'is_image should not have been called') + mocked_service_item.render.assert_called_once_with() + mocked_process_item.assert_called_once_with(mocked_service_item, 5) + + def refresh_service_item_image_test(self): + """ + Test that the refresh_service_item() method refreshes a image service item + """ + # GIVEN: A mock service item and a fresh slide controller + mocked_service_item = MagicMock() + mocked_service_item.is_text.return_value = False + mocked_service_item.is_image.return_value = True + mocked_process_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_service_item + slide_controller._process_item = mocked_process_item + slide_controller.selected_row = 5 + + # WHEN: The refresh_service_item method() is called + slide_controller.refresh_service_item() + + # THEN: The item should be re-processed + mocked_service_item.is_text.assert_called_once_with() + mocked_service_item.is_image.assert_called_once_with() + mocked_service_item.render.assert_called_once_with() + mocked_process_item.assert_called_once_with(mocked_service_item, 5) + + def refresh_service_item_not_image_or_text_test(self): + """ + Test that the refresh_service_item() method does not refresh a service item if it's neither text or an image + """ + # GIVEN: A mock service item and a fresh slide controller + mocked_service_item = MagicMock() + mocked_service_item.is_text.return_value = False + mocked_service_item.is_image.return_value = False + mocked_process_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_service_item + slide_controller._process_item = mocked_process_item + slide_controller.selected_row = 5 + + # WHEN: The refresh_service_item method() is called + slide_controller.refresh_service_item() + + # THEN: The item should be re-processed + mocked_service_item.is_text.assert_called_once_with() + mocked_service_item.is_image.assert_called_once_with() + self.assertEqual(0, mocked_service_item.render.call_count, 'The render() method should not have been called') + self.assertEqual(0, mocked_process_item.call_count, + 'The mocked_process_item() method should not have been called') + + def add_service_item_with_song_edit_test(self): + """ + Test the add_service_item() method when song_edit is True + """ + # GIVEN: A slide controller and a new item to add + mocked_item = MagicMock() + mocked_process_item =MagicMock() + slide_controller = SlideController(None) + slide_controller._process_item = mocked_process_item + slide_controller.song_edit = True + slide_controller.selected_row = 2 + + # WHEN: The item is added to the service + slide_controller.add_service_item(mocked_item) + + # THEN: The item is processed, the slide number is correct, and the song is not editable (or something) + mocked_item.render.assert_called_once_with() + self.assertFalse(slide_controller.song_edit, 'song_edit should be False') + mocked_process_item.assert_called_once_with(mocked_item, 2) + + def add_service_item_without_song_edit_test(self): + """ + Test the add_service_item() method when song_edit is False + """ + # GIVEN: A slide controller and a new item to add + mocked_item = MagicMock() + mocked_process_item =MagicMock() + slide_controller = SlideController(None) + slide_controller._process_item = mocked_process_item + slide_controller.song_edit = False + slide_controller.selected_row = 2 + + # WHEN: The item is added to the service + slide_controller.add_service_item(mocked_item) + + # THEN: The item is processed, the slide number is correct, and the song is not editable (or something) + mocked_item.render.assert_called_once_with() + self.assertFalse(slide_controller.song_edit, 'song_edit should be False') + mocked_process_item.assert_called_once_with(mocked_item, 0) + + def replace_service_manager_item_different_items_test(self): + """ + Test that when the service items are not the same, nothing happens + """ + # GIVEN: A slide controller and a new item to add + mocked_item = MagicMock() + mocked_preview_widget = MagicMock() + mocked_process_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.preview_widget = mocked_preview_widget + slide_controller._process_item = mocked_process_item + slide_controller.service_item = None + + # WHEN: The service item is replaced + slide_controller.replace_service_manager_item(mocked_item) + + # THEN: The service item should not be processed + self.assertEqual(0, mocked_process_item.call_count, 'The _process_item() method should not have been called') + self.assertEqual(0, mocked_preview_widget.current_slide_number.call_count, + 'The preview_widgetcurrent_slide_number.() method should not have been called') + + def replace_service_manager_item_same_item_test(self): + """ + Test that when the service item is the same, the service item is reprocessed + """ + # GIVEN: A slide controller and a new item to add + mocked_item = MagicMock() + mocked_preview_widget = MagicMock() + mocked_preview_widget.current_slide_number.return_value = 7 + mocked_process_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.preview_widget = mocked_preview_widget + slide_controller._process_item = mocked_process_item + slide_controller.service_item = mocked_item + + # WHEN: The service item is replaced + slide_controller.replace_service_manager_item(mocked_item) + + # THEN: The service item should not be processed + mocked_preview_widget.current_slide_number.assert_called_with() + mocked_process_item.assert_called_once_with(mocked_item, 7) + + def on_slide_selected_index_no_service_item_test(self): + """ + Test that when there is no service item, the on_slide_selected_index() method returns immediately + """ + # GIVEN: A mocked service item and a slide controller without a service item + mocked_item = MagicMock() + slide_controller = SlideController(None) + slide_controller.service_item = None + + # WHEN: The method is called + slide_controller.on_slide_selected_index([10]) + + # THEN: It should have exited early + self.assertEqual(0, mocked_item.is_command.call_count, 'The service item should have not been called') + + def on_slide_selected_index_service_item_command_test(self): + """ + Test that when there is a command service item, the command is executed + """ + # GIVEN: A mocked service item and a slide controller with a service item + mocked_item = MagicMock() + mocked_item.is_command.return_value = True + mocked_item.name = 'Mocked Item' + mocked_execute = MagicMock() + mocked_update_preview = MagicMock() + mocked_preview_widget = MagicMock() + mocked_slide_selected = MagicMock() + Registry.execute = mocked_execute + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + slide_controller.is_live = True + + # WHEN: The method is called + slide_controller.on_slide_selected_index([9]) + + # THEN: It should have sent a notification + mocked_item.is_command.assert_called_once_with() + mocked_execute.assert_called_once_with('mocked item_slide', [mocked_item, True, 9]) + mocked_update_preview.assert_called_once_with() + self.assertEqual(0, mocked_preview_widget.change_slide.call_count, 'Change slide should not have been called') + self.assertEqual(0, mocked_slide_selected.call_count, 'slide_selected should not have been called') + + def on_slide_selected_index_service_item_not_command_test(self): + """ + Test that when there is a service item but it's not a command, the preview widget is updated + """ + # GIVEN: A mocked service item and a slide controller with a service item + mocked_item = MagicMock() + mocked_item.is_command.return_value = False + mocked_item.name = 'Mocked Item' + mocked_execute = MagicMock() + mocked_update_preview = MagicMock() + mocked_preview_widget = MagicMock() + mocked_slide_selected = MagicMock() + Registry.execute = mocked_execute + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + + # WHEN: The method is called + slide_controller.on_slide_selected_index([7]) + + # THEN: It should have sent a notification + mocked_item.is_command.assert_called_once_with() + self.assertEqual(0, mocked_execute.call_count, 'Execute should not have been called') + self.assertEqual(0, mocked_update_preview.call_count, 'Update preview should not have been called') + mocked_preview_widget.change_slide.assert_called_once_with(7) + mocked_slide_selected.assert_called_once_with() From ba9ff89354eea616ea6e82c4744fc7ee8d25c9c0 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 13 Jul 2014 13:04:37 +0200 Subject: [PATCH 55/69] [fix] PEP8 error: no whitespace --- tests/functional/openlp_core_ui/test_slidecontroller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index 3a1e754f8..ed237d424 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -405,7 +405,7 @@ class TestSlideController(TestCase): """ # GIVEN: A slide controller and a new item to add mocked_item = MagicMock() - mocked_process_item =MagicMock() + mocked_process_item = MagicMock() slide_controller = SlideController(None) slide_controller._process_item = mocked_process_item slide_controller.song_edit = True @@ -425,7 +425,7 @@ class TestSlideController(TestCase): """ # GIVEN: A slide controller and a new item to add mocked_item = MagicMock() - mocked_process_item =MagicMock() + mocked_process_item = MagicMock() slide_controller = SlideController(None) slide_controller._process_item = mocked_process_item slide_controller.song_edit = False From 63350ab6eb9dc91743441b106fa58f2278d03e74 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 13 Jul 2014 15:10:58 +0200 Subject: [PATCH 56/69] Try to ignore the 2.0.x line of tags --- tests/utils/test_bzr_tags.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index acadbd8c4..bc5f4ade0 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -30,7 +30,7 @@ Package to test for proper bzr tags. """ import os - +import re from unittest import TestCase from subprocess import Popen, PIPE @@ -52,6 +52,7 @@ TAGS = [ ['2.0', '2118'], ['2.1.0', '2119'] ] +TAG_SEARCH = re.compile('2\.0\.\d') class TestBzrTags(TestCase): @@ -65,8 +66,9 @@ class TestBzrTags(TestCase): # WHEN getting the branches tags bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE) - stdout = bzr.communicate()[0] - tags = [line.decode('utf-8').split() for line in stdout.splitlines()] + std_out = bzr.communicate()[0] + tags = [line.decode('utf-8').split() for line in std_out.splitlines()] + tags = [t_r for t_r in tags if t_r[1] != '?' or not (t_r[1] == '?' and TAG_SEARCH.search(t_r[0]))] # THEN the tags should match the accepted tags self.assertEqual(TAGS, tags, 'List of tags should match') From 563fb794b5dab9907375cd450e68bb083fc83f33 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 13 Jul 2014 21:21:50 +0200 Subject: [PATCH 57/69] Added an explanatory comment --- tests/utils/test_bzr_tags.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index bc5f4ade0..14da67bc7 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -52,6 +52,9 @@ TAGS = [ ['2.0', '2118'], ['2.1.0', '2119'] ] +# Depending on the repository, we sometimes have the 2.0.x tags in the repo too. They come up with a revision number of +# "?", which I suspect is due to the fact that we're using shared repositories. This regular expression matches all +# 2.0.x tags. TAG_SEARCH = re.compile('2\.0\.\d') From 0ce859c2cd6b7b99bc068b759fe35e7cbddb71a3 Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 14 Jul 2014 13:36:33 +0200 Subject: [PATCH 58/69] Fix import --- openlp/plugins/songs/lib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index d03bdefd6..999f51fad 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -374,7 +374,7 @@ def clean_song(manager, song): :param manager: The song database manager object. :param song: The song object. """ - from .xml import SongXML + from .openlyricsxml import SongXML if song.title: song.title = clean_title(song.title) From 5e349c6c24e5a6278a56fae17f71d4403097493b Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Mon, 14 Jul 2014 18:50:50 +0200 Subject: [PATCH 59/69] Merge conflict --- openlp/plugins/songs/lib/importer.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index eb8c8b4d6..0084a74de 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -160,23 +160,19 @@ class SongFormat(object): FoilPresenter = 8 MediaShout = 9 OpenSong = 10 -<<<<<<< TREE - PowerSong = 11 - PresentationManager = 12 -======= PowerPraise = 11 PowerSong = 12 ->>>>>>> MERGE-SOURCE - ProPresenter = 13 - SongBeamer = 14 - SongPro = 15 - SongShowPlus = 16 - SongsOfFellowship = 17 - SundayPlus = 18 - WordsOfWorship = 19 - WorshipAssistant = 20 - WorshipCenterPro = 21 - ZionWorx = 22 + PresentationManager = 13 + ProPresenter = 14 + SongBeamer = 15 + SongPro = 16 + SongShowPlus = 17 + SongsOfFellowship = 18 + SundayPlus = 19 + WordsOfWorship = 20 + WorshipAssistant = 21 + WorshipCenterPro = 22 + ZionWorx = 23 # Set optional attribute defaults __defaults__ = { From 2613ad30766800c7547d4aa6e5bb466a44a51f4b Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 17 Jul 2014 23:04:58 +0200 Subject: [PATCH 60/69] Don't run upgrades on an up to date database --- openlp/core/lib/db.py | 5 +- openlp/plugins/songs/lib/upgrade.py | 65 ++++++++++--------------- openlp/plugins/songusage/lib/upgrade.py | 10 ++-- 3 files changed, 32 insertions(+), 48 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index d67c05c42..8e9380241 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -96,9 +96,10 @@ def upgrade_db(url, upgrade): mapper(Metadata, metadata_table) version_meta = session.query(Metadata).get('version') if version_meta is None: - version_meta = Metadata.populate(key='version', value='0') + # Tables have just been created - fill the version field with the most recent version + version = upgrade.__version__ + version_meta = Metadata.populate(key='version', value=version) session.add(version_meta) - version = 0 else: version = int(version_meta.value) if version > upgrade.__version__: diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 580ae767d..5b7255266 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -33,7 +33,6 @@ backend for the Songs plugin import logging from sqlalchemy import Column, ForeignKey, types -from sqlalchemy.exc import OperationalError from sqlalchemy.sql.expression import func, false, null, text from openlp.core.lib.db import get_upgrade_op @@ -57,16 +56,13 @@ def upgrade_1(session, metadata): :param session: :param metadata: """ - try: - op = get_upgrade_op(session) - op.drop_table('media_files_songs') - op.add_column('media_files', Column('song_id', types.Integer(), server_default=null())) - op.add_column('media_files', Column('weight', types.Integer(), server_default=text('0'))) - if metadata.bind.url.get_dialect().name != 'sqlite': - # SQLite doesn't support ALTER TABLE ADD CONSTRAINT - op.create_foreign_key('fk_media_files_song_id', 'media_files', 'songs', ['song_id', 'id']) - except OperationalError: - log.info('Upgrade 1 has already been run') + op = get_upgrade_op(session) + op.drop_table('media_files_songs') + op.add_column('media_files', Column('song_id', types.Integer(), server_default=null())) + op.add_column('media_files', Column('weight', types.Integer(), server_default=text('0'))) + if metadata.bind.url.get_dialect().name != 'sqlite': + # SQLite doesn't support ALTER TABLE ADD CONSTRAINT + op.create_foreign_key('fk_media_files_song_id', 'media_files', 'songs', ['song_id', 'id']) def upgrade_2(session, metadata): @@ -75,12 +71,9 @@ def upgrade_2(session, metadata): This upgrade adds a create_date and last_modified date to the songs table """ - try: - op = get_upgrade_op(session) - op.add_column('songs', Column('create_date', types.DateTime(), default=func.now())) - op.add_column('songs', Column('last_modified', types.DateTime(), default=func.now())) - except OperationalError: - log.info('Upgrade 2 has already been run') + op = get_upgrade_op(session) + op.add_column('songs', Column('create_date', types.DateTime(), default=func.now())) + op.add_column('songs', Column('last_modified', types.DateTime(), default=func.now())) def upgrade_3(session, metadata): @@ -89,14 +82,11 @@ def upgrade_3(session, metadata): This upgrade adds a temporary song flag to the songs table """ - try: - op = get_upgrade_op(session) - if metadata.bind.url.get_dialect().name == 'sqlite': - op.add_column('songs', Column('temporary', types.Boolean(create_constraint=False), server_default=false())) - else: - op.add_column('songs', Column('temporary', types.Boolean(), server_default=false())) - except OperationalError: - log.info('Upgrade 3 has already been run') + op = get_upgrade_op(session) + if metadata.bind.url.get_dialect().name == 'sqlite': + op.add_column('songs', Column('temporary', types.Boolean(create_constraint=False), server_default=false())) + else: + op.add_column('songs', Column('temporary', types.Boolean(), server_default=false())) def upgrade_4(session, metadata): @@ -105,17 +95,14 @@ def upgrade_4(session, metadata): This upgrade adds a column for author type to the authors_songs table """ - try: - # Since SQLite doesn't support changing the primary key of a table, we need to recreate the table - # and copy the old values - op = get_upgrade_op(session) - op.create_table('authors_songs_tmp', - Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True), - Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True), - Column('author_type', types.String(), primary_key=True, - nullable=False, server_default=text('""'))) - op.execute('INSERT INTO authors_songs_tmp SELECT author_id, song_id, "" FROM authors_songs') - op.drop_table('authors_songs') - op.rename_table('authors_songs_tmp', 'authors_songs') - except OperationalError: - log.info('Upgrade 4 has already been run') + # Since SQLite doesn't support changing the primary key of a table, we need to recreate the table + # and copy the old values + op = get_upgrade_op(session) + op.create_table('authors_songs_tmp', + Column('author_id', types.Integer(), ForeignKey('authors.id'), primary_key=True), + Column('song_id', types.Integer(), ForeignKey('songs.id'), primary_key=True), + Column('author_type', types.String(), primary_key=True, + nullable=False, server_default=text('""'))) + op.execute('INSERT INTO authors_songs_tmp SELECT author_id, song_id, "" FROM authors_songs') + op.drop_table('authors_songs') + op.rename_table('authors_songs_tmp', 'authors_songs') diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index 24f264824..b0f0f52f0 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -32,7 +32,6 @@ backend for the SongsUsage plugin """ import logging -from sqlalchemy.exc import OperationalError from sqlalchemy import Column, types from openlp.core.lib.db import get_upgrade_op @@ -50,9 +49,6 @@ def upgrade_1(session, metadata): :param session: SQLAlchemy Session object :param metadata: SQLAlchemy MetaData object """ - try: - op = get_upgrade_op(session) - op.add_column('songusage_data', Column('plugin_name', types.Unicode(20), server_default='')) - op.add_column('songusage_data', Column('source', types.Unicode(10), server_default='')) - except OperationalError: - log.info('Upgrade 1 has already taken place') + op = get_upgrade_op(session) + op.add_column('songusage_data', Column('plugin_name', types.Unicode(20), server_default='')) + op.add_column('songusage_data', Column('source', types.Unicode(10), server_default='')) From fa5787e5d86dede1bcb1a7e379746c77f5834cad Mon Sep 17 00:00:00 2001 From: Samuel Mehrbrodt Date: Thu, 17 Jul 2014 23:16:00 +0200 Subject: [PATCH 61/69] Add test --- .../openlp_plugins/songs/test_db.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/functional/openlp_plugins/songs/test_db.py b/tests/functional/openlp_plugins/songs/test_db.py index 53b98c045..e696ea94b 100644 --- a/tests/functional/openlp_plugins/songs/test_db.py +++ b/tests/functional/openlp_plugins/songs/test_db.py @@ -125,3 +125,31 @@ class TestDB(TestCase): # THEN: The type should be correct self.assertEqual(author_type, AuthorType.Words) + + def test_author_get_display_name(self): + """ + Test that the display name of an author is correct + """ + # GIVEN: An author + author = Author() + author.display_name = "John Doe" + + # WHEN: We call the get_display_name() function + display_name = author.get_display_name() + + # THEN: It should return only the name + self.assertEqual("John Doe", display_name) + + def test_author_get_display_name_with_type(self): + """ + Test that the display name of an author with a type is correct + """ + # GIVEN: An author + author = Author() + author.display_name = "John Doe" + + # WHEN: We call the get_display_name() function + display_name = author.get_display_name(AuthorType.Words) + + # THEN: It should return the name with the type in brackets + self.assertEqual("John Doe (Words)", display_name) From d4a94d0cd592caac8bc1673acdc3de3d33b776f5 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 17 Jul 2014 23:46:48 +0200 Subject: [PATCH 62/69] Fix the Windows tests --- scripts/jenkins_script.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index eeafbfe23..cd6a0c9cf 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -62,11 +62,12 @@ class OpenLPJobs(object): Branch_Pull = 'Branch-01-Pull' Branch_Functional = 'Branch-02-Functional-Tests' Branch_Interface = 'Branch-03-Interface-Tests' - Branch_Windows = 'Branch-04-Windows_Tests' + Branch_Windows_Functional = 'Branch-04a-Windows_Functional_Tests' + Branch_Windows_Interface = 'Branch-04b-Windows_Interface_Tests' Branch_PEP = 'Branch-05a-Code_Analysis' Branch_Coverage = 'Branch-05b-Test_Coverage' - Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows, Branch_PEP, Branch_Coverage] + Jobs = [Branch_Pull, Branch_Functional, Branch_Interface, Branch_Windows_Functional, Branch_Windows_Interface, Branch_PEP, Branch_Coverage] class Colour(object): From 2b1b8ac68615f2595266f0c7da202495e823dab2 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 17 Jul 2014 23:55:54 +0200 Subject: [PATCH 63/69] Make the script stop after a failure. --- scripts/jenkins_script.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index cd6a0c9cf..6c6fdac80 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -115,7 +115,9 @@ class JenkinsTrigger(object): print('%s (revision %s)' % (get_repo_name(), revno)) for job in OpenLPJobs.Jobs: - self.__print_build_info(job) + if not self.__print_build_info(job): + print('Stopping after failure') + break def open_browser(self): """ @@ -132,6 +134,7 @@ class JenkinsTrigger(object): :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class variables from the :class:`OpenLPJobs` class. """ + is_success = False job = self.jenkins_instance.job(job_name) while job.info['inQueue']: time.sleep(1) @@ -140,11 +143,13 @@ class JenkinsTrigger(object): if build.info['result'] == 'SUCCESS': # Make 'SUCCESS' green. result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END) + is_success = True else: # Make 'FAILURE' red. result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END) url = build.info['url'] print('[%s] %s' % (result_string, url)) + return is_success def get_repo_name(): From 73ec92ae13632028196eeef547228f7527593519 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 07:37:41 +0100 Subject: [PATCH 64/69] Added option to wrap footer text --- openlp/core/common/settings.py | 1 + openlp/core/lib/htmlbuilder.py | 6 ++++-- openlp/core/ui/themestab.py | 14 ++++++++++++++ openlp/plugins/songs/lib/__init__.py | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 3b7b31ca1..634bc5ced 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -286,6 +286,7 @@ class Settings(QtCore.QSettings): 'themes/last directory export': '', 'themes/last directory import': '', 'themes/theme level': ThemeLevel.Song, + 'themes/wrap footer': False, 'user interface/live panel': True, 'user interface/live splitter geometry': QtCore.QByteArray(), 'user interface/lock panel': False, diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 473aa9d7d..058e5a2a1 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -398,6 +398,7 @@ import logging from PyQt4 import QtWebKit +from openlp.core.common import Settings from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType log = logging.getLogger(__name__) @@ -750,12 +751,13 @@ def build_footer_css(item, height): font-size: %spt; color: %s; text-align: left; - white-space: nowrap; + white-space: %s; """ theme = item.theme_data if not theme or not item.footer: return '' bottom = height - int(item.footer.y()) - int(item.footer.height()) + whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap' lyrics_html = style % (item.footer.x(), bottom, item.footer.width(), - theme.font_footer_name, theme.font_footer_size, theme.font_footer_color) + theme.font_footer_name, theme.font_footer_size, theme.font_footer_color, whitespace) return lyrics_html diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 0478f0ed0..230439566 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -69,6 +69,14 @@ class ThemesTab(SettingsTab): self.default_list_view.setObjectName('default_list_view') self.global_group_box_layout.addWidget(self.default_list_view) self.left_layout.addWidget(self.global_group_box) + self.universal_group_box = QtGui.QGroupBox(self.left_column) + self.universal_group_box.setObjectName('universal_group_box') + self.universal_group_box_layout = QtGui.QVBoxLayout(self.universal_group_box) + self.universal_group_box_layout.setObjectName('universal_group_box_layout') + self.wrap_footer_check_box = QtGui.QCheckBox(self.universal_group_box) + self.wrap_footer_check_box.setObjectName('wrap_footer_check_box') + self.universal_group_box_layout.addWidget(self.wrap_footer_check_box) + self.left_layout.addWidget(self.universal_group_box) self.left_layout.addStretch() self.level_group_box = QtGui.QGroupBox(self.right_column) self.level_group_box.setObjectName('level_group_box') @@ -112,6 +120,8 @@ class ThemesTab(SettingsTab): """ self.tab_title_visible = UiStrings().Themes self.global_group_box.setTitle(translate('OpenLP.ThemesTab', 'Global Theme')) + self.universal_group_box.setTitle(translate('OpenLP.ThemesTab', 'Universal Settings')) + self.wrap_footer_check_box.setText(translate('OpenLP.ThemesTab', '&Wrap footer text')) self.level_group_box.setTitle(translate('OpenLP.ThemesTab', 'Theme Level')) self.song_level_radio_button.setText(translate('OpenLP.ThemesTab', 'S&ong Level')) self.song_level_label.setText( @@ -136,6 +146,7 @@ class ThemesTab(SettingsTab): settings.beginGroup(self.settings_section) self.theme_level = settings.value('theme level') self.global_theme = settings.value('global theme') + wrap_footer = settings.value('wrap footer') settings.endGroup() if self.theme_level == ThemeLevel.Global: self.global_level_radio_button.setChecked(True) @@ -143,15 +154,18 @@ class ThemesTab(SettingsTab): self.service_level_radio_button.setChecked(True) else: self.song_level_radio_button.setChecked(True) + self.wrap_footer_check_box.setChecked(wrap_footer) def save(self): """ Save the settings """ + wrap_footer = self.wrap_footer_check_box.isChecked() settings = Settings() settings.beginGroup(self.settings_section) settings.setValue('theme level', self.theme_level) settings.setValue('global theme', self.global_theme) + settings.setValue('wrap footer', wrap_footer) settings.endGroup() self.renderer.set_theme_level(self.theme_level) if self.tab_visited: diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index d03bdefd6..999f51fad 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -374,7 +374,7 @@ def clean_song(manager, song): :param manager: The song database manager object. :param song: The song object. """ - from .xml import SongXML + from .openlyricsxml import SongXML if song.title: song.title = clean_title(song.title) From 2555bc50d4ed202b13a5d0c60ead773b8a4e3b21 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 18:13:20 +0100 Subject: [PATCH 65/69] Add test for wrap footer setting --- .../openlp_core_lib/test_htmlbuilder.py | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index ef5ffdf43..a68e14061 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -6,10 +6,12 @@ from unittest import TestCase from PyQt4 import QtCore +from openlp.core.common import Settings from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \ build_lyrics_format_css, build_footer_css from openlp.core.lib.theme import HorizontalType, VerticalType from tests.functional import MagicMock, patch +from tests.helpers.testmixin import TestMixin HTML = """ @@ -184,7 +186,7 @@ LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-c LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \ 'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \ 'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; ' -FOOTER_CSS = """ +FOOTER_CSS_BASE = """ left: 10px; bottom: 0px; width: 1260px; @@ -192,11 +194,29 @@ FOOTER_CSS = """ font-size: 12pt; color: #FFFFFF; text-align: left; - white-space: nowrap; + white-space: %s; """ +FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap') +FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal') + + +class Htmbuilder(TestCase, TestMixin): + """ + Test the functions in the Htmlbuilder module + """ + def setUp(self): + """ + Create the UI + """ + self.build_settings() + + def tearDown(self): + """ + Delete all the C++ objects at the end so that we don't have a segfault + """ + self.destroy_settings() -class Htmbuilder(TestCase): def build_html_test(self): """ Test the build_html() function @@ -316,8 +336,15 @@ class Htmbuilder(TestCase): item.theme_data.font_footer_color = '#FFFFFF' height = 1024 - # WHEN: create the css. + # WHEN: create the css with default settings. css = build_footer_css(item, height) # THEN: THE css should be the same. assert FOOTER_CSS == css, 'The footer strings should be equal.' + + # WHEN: Settings say that footer should wrap + Settings().setValue('themes/wrap footer', True) + css = build_footer_css(item, height) + + # THEN: Footer should wrap + assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.' From 9a1ce000b7bfa79216d6aa6eb5ba767c9a7f6194 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 22:45:27 +0100 Subject: [PATCH 66/69] Patch Registry.execute so that it is undoen at end of test --- .../openlp_core_ui/test_slidecontroller.py | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index ed237d424..ea68b8ae9 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -508,18 +508,18 @@ class TestSlideController(TestCase): mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() - Registry.execute = mocked_execute - Registry.create() - slide_controller = SlideController(None) - slide_controller.service_item = mocked_item - slide_controller.update_preview = mocked_update_preview - slide_controller.preview_widget = mocked_preview_widget - slide_controller.slide_selected = mocked_slide_selected - slide_controller.is_live = True - - # WHEN: The method is called - slide_controller.on_slide_selected_index([9]) - + with patch.object(Registry, 'execute') as mocked_execute: + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + slide_controller.is_live = True + + # WHEN: The method is called + slide_controller.on_slide_selected_index([9]) + # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() mocked_execute.assert_called_once_with('mocked item_slide', [mocked_item, True, 9]) @@ -539,16 +539,16 @@ class TestSlideController(TestCase): mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() - Registry.execute = mocked_execute - Registry.create() - slide_controller = SlideController(None) - slide_controller.service_item = mocked_item - slide_controller.update_preview = mocked_update_preview - slide_controller.preview_widget = mocked_preview_widget - slide_controller.slide_selected = mocked_slide_selected - - # WHEN: The method is called - slide_controller.on_slide_selected_index([7]) + with patch.object(Registry, 'execute') as mocked_execute: + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + + # WHEN: The method is called + slide_controller.on_slide_selected_index([7]) # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() @@ -556,3 +556,5 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_update_preview.call_count, 'Update preview should not have been called') mocked_preview_widget.change_slide.assert_called_once_with(7) mocked_slide_selected.assert_called_once_with() + + From 668864c38d474ca3e56c7e984f0553f9a44d8027 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Tue, 22 Jul 2014 21:06:48 +0100 Subject: [PATCH 67/69] Tidy up tests and formatting --- .../functional/openlp_core_lib/test_htmlbuilder.py | 14 ++++++++++++-- .../openlp_core_ui/test_slidecontroller.py | 10 +++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index a68e14061..e98dfc687 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -13,7 +13,6 @@ from openlp.core.lib.theme import HorizontalType, VerticalType from tests.functional import MagicMock, patch from tests.helpers.testmixin import TestMixin - HTML = """ @@ -216,7 +215,6 @@ class Htmbuilder(TestCase, TestMixin): """ self.destroy_settings() - def build_html_test(self): """ Test the build_html() function @@ -342,6 +340,18 @@ class Htmbuilder(TestCase, TestMixin): # THEN: THE css should be the same. assert FOOTER_CSS == css, 'The footer strings should be equal.' + def build_footer_css_wrap_test(self): + """ + Test the build_footer_css() function + """ + # GIVEN: Create a theme. + item = MagicMock() + item.footer = QtCore.QRect(10, 921, 1260, 103) + item.theme_data.font_footer_name = 'Arial' + item.theme_data.font_footer_size = 12 + item.theme_data.font_footer_color = '#FFFFFF' + height = 1024 + # WHEN: Settings say that footer should wrap Settings().setValue('themes/wrap footer', True) css = build_footer_css(item, height) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index ea68b8ae9..1d241a317 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -504,7 +504,6 @@ class TestSlideController(TestCase): mocked_item = MagicMock() mocked_item.is_command.return_value = True mocked_item.name = 'Mocked Item' - mocked_execute = MagicMock() mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() @@ -516,10 +515,10 @@ class TestSlideController(TestCase): slide_controller.preview_widget = mocked_preview_widget slide_controller.slide_selected = mocked_slide_selected slide_controller.is_live = True - + # WHEN: The method is called slide_controller.on_slide_selected_index([9]) - + # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() mocked_execute.assert_called_once_with('mocked item_slide', [mocked_item, True, 9]) @@ -535,7 +534,6 @@ class TestSlideController(TestCase): mocked_item = MagicMock() mocked_item.is_command.return_value = False mocked_item.name = 'Mocked Item' - mocked_execute = MagicMock() mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() @@ -546,7 +544,7 @@ class TestSlideController(TestCase): slide_controller.update_preview = mocked_update_preview slide_controller.preview_widget = mocked_preview_widget slide_controller.slide_selected = mocked_slide_selected - + # WHEN: The method is called slide_controller.on_slide_selected_index([7]) @@ -556,5 +554,3 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_update_preview.call_count, 'Update preview should not have been called') mocked_preview_widget.change_slide.assert_called_once_with(7) mocked_slide_selected.assert_called_once_with() - - From d90fcface2853d0d6d0f4abc18168e20eb317f97 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Thu, 24 Jul 2014 20:28:57 +0100 Subject: [PATCH 68/69] Style fixes for Tim --- openlp/core/ui/themestab.py | 6 ++---- tests/functional/openlp_core_lib/test_htmlbuilder.py | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 230439566..4b3f8b6eb 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -146,7 +146,7 @@ class ThemesTab(SettingsTab): settings.beginGroup(self.settings_section) self.theme_level = settings.value('theme level') self.global_theme = settings.value('global theme') - wrap_footer = settings.value('wrap footer') + self.wrap_footer_check_box.setChecked(settings.value('wrap footer')) settings.endGroup() if self.theme_level == ThemeLevel.Global: self.global_level_radio_button.setChecked(True) @@ -154,18 +154,16 @@ class ThemesTab(SettingsTab): self.service_level_radio_button.setChecked(True) else: self.song_level_radio_button.setChecked(True) - self.wrap_footer_check_box.setChecked(wrap_footer) def save(self): """ Save the settings """ - wrap_footer = self.wrap_footer_check_box.isChecked() settings = Settings() settings.beginGroup(self.settings_section) settings.setValue('theme level', self.theme_level) settings.setValue('global theme', self.global_theme) - settings.setValue('wrap footer', wrap_footer) + settings.setValue('wrap footer', self.wrap_footer_check_box.isChecked()) settings.endGroup() self.renderer.set_theme_level(self.theme_level) if self.tab_visited: diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index e98dfc687..4563c98b4 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -320,7 +320,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_format_css(theme_data, width, height) # THEN: They should be equal. - assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.' + self.assertEqual(LYRICS_FORMAT_CSS, css, 'The lyrics format css should be equal.') def build_footer_css_test(self): """ @@ -357,4 +357,4 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: Footer should wrap - assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.' + self.assertEqual(FOOTER_CSS_WRAP, css, 'The footer strings should be equal.') From 2f984c45c48f7857ec57758dc6b32ee09a19ff51 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Thu, 24 Jul 2014 22:57:16 +0100 Subject: [PATCH 69/69] Style fixes for Tim --- tests/functional/openlp_core_lib/test_htmlbuilder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index 4563c98b4..7ba63a792 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -243,7 +243,7 @@ class Htmbuilder(TestCase, TestMixin): html = build_html(item, screen, is_live, background, plugins=plugins) # THEN: The returned html should match. - assert html == HTML + self.assertEqual(html, HTML, 'The returned html should match') def build_background_css_radial_test(self): """ @@ -259,7 +259,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_background_css(item, width) # THEN: The returned css should match. - assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.' + self.assertEqual(BACKGROUND_CSS_RADIAL, css, 'The background css should be equal.') def build_lyrics_css_test(self): """ @@ -280,7 +280,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_css(item) # THEN: The css should be equal. - assert LYRICS_CSS == css, 'The lyrics css should be equal.' + self.assertEqual(LYRICS_CSS, css, 'The lyrics css should be equal.') def build_lyrics_outline_css_test(self): """ @@ -297,7 +297,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_outline_css(theme_data) # THEN: The css should be equal. - assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.' + self.assertEqual(LYRICS_OUTLINE_CSS, css, 'The outline css should be equal.') def build_lyrics_format_css_test(self): """ @@ -338,7 +338,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: THE css should be the same. - assert FOOTER_CSS == css, 'The footer strings should be equal.' + self.assertEqual(FOOTER_CSS, css, 'The footer strings should be equal.') def build_footer_css_wrap_test(self): """