diff --git a/openlp/core/lib/filedialog.py b/openlp/core/lib/filedialog.py index 5bf012ee5..3d1970dd5 100644 --- a/openlp/core/lib/filedialog.py +++ b/openlp/core/lib/filedialog.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 ############################################################################### # OpenLP - Open Source Lyrics Projection # diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index ed32a43ee..7ce637285 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -49,6 +49,7 @@ from .songproimport import SongProImport from .sundayplusimport import SundayPlusImport from .foilpresenterimport import FoilPresenterImport from .zionworximport import ZionWorxImport +from .propresenterimport import ProPresenterImport # Imports that might fail @@ -159,14 +160,15 @@ class SongFormat(object): MediaShout = 9 OpenSong = 10 PowerSong = 11 - SongBeamer = 12 - SongPro = 13 - SongShowPlus = 14 - SongsOfFellowship = 15 - SundayPlus = 16 - WordsOfWorship = 17 - WorshipCenterPro = 18 - ZionWorx = 19 + ProPresenter = 12 + SongBeamer = 13 + SongPro = 14 + SongShowPlus = 15 + SongsOfFellowship = 16 + SundayPlus = 17 + WordsOfWorship = 18 + WorshipCenterPro = 19 + ZionWorx = 20 # Set optional attribute defaults __defaults__ = { @@ -270,6 +272,12 @@ class SongFormat(object): 'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', 'You need to specify a valid PowerSong 1.0 ' 'database folder.') }, + ProPresenter: { + 'class': ProPresenterImport, + 'name': 'ProPresenter', + 'prefix': 'proPresenter', + 'filter': '%s (*.pro4)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter Song Files') + }, SongBeamer: { 'class': SongBeamerImport, 'name': 'SongBeamer', @@ -355,6 +363,7 @@ class SongFormat(object): SongFormat.MediaShout, SongFormat.OpenSong, SongFormat.PowerSong, + SongFormat.ProPresenter, SongFormat.SongBeamer, SongFormat.SongPro, SongFormat.SongShowPlus, diff --git a/openlp/plugins/songs/lib/propresenterimport.py b/openlp/plugins/songs/lib/propresenterimport.py new file mode 100644 index 000000000..6ce3c0819 --- /dev/null +++ b/openlp/plugins/songs/lib/propresenterimport.py @@ -0,0 +1,75 @@ +# -*- 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:`propresenterimport` module provides the functionality for importing +ProPresenter song files into the current installation 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 ProPresenterImport(SongImport): + """ + The :class:`ProPresenterImport` class provides OpenLP with the + ability to import ProPresenter 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.get('CCLISongTitle') + self.copyright = root.get('CCLICopyrightInfo') + self.comments = root.get('notes') + self.ccli_number = root.get('CCLILicenseNumber') + for author_key in ['author', 'artist', 'CCLIArtistCredits']: + author = root.get(author_key) + if len(author) > 0: + self.parse_author(author) + count = 0 + for slide in root.slides.RVDisplaySlide: + count += 1 + RTFData = slide.displayElements.RVTextElement.get('RTFData') + rtf = base64.standard_b64decode(RTFData) + words, encoding = strip_rtf(rtf.decode()) + self.add_verse(words, "v%d" % count) + if not self.finish(): + self.log_error(self.import_source) diff --git a/tests/functional/openlp_plugins/songs/test_propresenterimport.py b/tests/functional/openlp_plugins/songs/test_propresenterimport.py new file mode 100644 index 000000000..971ddbdf6 --- /dev/null +++ b/tests/functional/openlp_plugins/songs/test_propresenterimport.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:`propresenterimport` 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', 'propresentersongs')) + + +class TestProPresenterFileImport(SongImportTestHelper): + + def __init__(self, *args, **kwargs): + self.importer_class_name = 'ProPresenterImport' + self.importer_module_name = 'propresenterimport' + super(TestProPresenterFileImport, self).__init__(*args, **kwargs) + + def test_song_import(self): + """ + Test that loading an 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/functional/openlp_plugins/songs/test_zionworximport.py b/tests/functional/openlp_plugins/songs/test_zionworximport.py index 2edc071c7..c5669e9c8 100644 --- a/tests/functional/openlp_plugins/songs/test_zionworximport.py +++ b/tests/functional/openlp_plugins/songs/test_zionworximport.py @@ -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.songbeamerimport.SongImport'): + with patch('openlp.plugins.songs.lib.zionworximport.SongImport'): mocked_manager = MagicMock() # WHEN: An importer object is created diff --git a/tests/resources/propresentersongs/Amazing Grace.json b/tests/resources/propresentersongs/Amazing Grace.json new file mode 100644 index 000000000..1746b7696 --- /dev/null +++ b/tests/resources/propresentersongs/Amazing Grace.json @@ -0,0 +1,121 @@ +{ + "authors": [ + "John Newton" + ], + "title": "Amazing Grace", + "verse_order_list": [], + "verses": [ + [ + "Amazing grace! How sweet the sound\n", + "v1" + ], + [ + "That saved a wretch like me!\n", + "v2" + ], + [ + "I once was lost, but now am found;\n", + "v3" + ], + [ + "Was blind, but now I see.\n", + "v4" + ], + [ + "'Twas grace that taught my heart to fear,\n", + "v5" + ], + [ + "And grace my fears relieved;\n", + "v6" + ], + [ + "How precious did that grace appear\n", + "v7" + ], + [ + "The hour I first believed.\n", + "v8" + ], + [ + "Through many dangers, toils and snares,\n", + "v9" + ], + [ + "I have already come;\n", + "v10" + ], + [ + "'Tis grace hath brought me safe thus far,\n", + "v11" + ], + [ + "And grace will lead me home.\n", + "v12" + ], + [ + "The Lord has promised good to me,\n", + "v13" + ], + [ + "His Word my hope secures;\n", + "v14" + ], + [ + "He will my Shield and Portion be,\n", + "v15" + ], + [ + "As long as life endures.\n", + "v16" + ], + [ + "Yea, when this flesh and heart shall fail,\n", + "v17" + ], + [ + "And mortal life shall cease,\n", + "v18" + ], + [ + "I shall possess, within the veil,\n", + "v19" + ], + [ + "A life of joy and peace.\n", + "v20" + ], + [ + "The earth shall soon dissolve like snow,\n", + "v21" + ], + [ + "The sun forbear to shine;\n", + "v22" + ], + [ + "But God, Who called me here below,\n", + "v23" + ], + [ + "Shall be forever mine.\n", + "v24" + ], + [ + "When we've been there ten thousand years,\n", + "v25" + ], + [ + "Bright shining as the sun,\n", + "v26" + ], + [ + "We've no less days to sing God's praise\n", + "v27" + ], + [ + "Than when we'd first begun.\n", + "v28" + ] + ] +} \ No newline at end of file diff --git a/tests/resources/propresentersongs/Amazing Grace.pro4 b/tests/resources/propresentersongs/Amazing Grace.pro4 new file mode 100644 index 000000000..dbe114a88 --- /dev/null +++ b/tests/resources/propresentersongs/Amazing Grace.pro4 @@ -0,0 +1,486 @@ + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + <_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" /> + <_-D-_serializedShadow containerClass="NSMutableDictionary"> + + + + + + + + + + + + + + + + + + \ No newline at end of file