diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 97a1a7a12..f9bda3100 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -667,14 +667,23 @@ def transpose_chord(chord, transpose_value, notation): def make_list(array): - if len(array) > 0: - result = [] - for i in range(len(array)): - result.append({'entry': array[i]}) - if i == 0: - result[i]['first'] = True - if i == len(array) - 1: - result[i]['last'] = True - return result - else: + """ + converts an ordinary list into a mustache ready dict construct augmented with some information to enable special + formatting features with the first, second to last and last element. + + :param array: input list + :return: mustache ready and augmented dict + """ + if len(array) < 0: return False + + result = [] + for i in range(len(array)): + result.append({'entry': array[i]}) + if i == 0: + result[i]['first'] = True + if i == len(array) - 1: + result[i]['last'] = True + if i == len(array) - 1 or i == len(array) - 2: + result[i]['last_or_penultimate'] = True + return result diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 799681fc7..3943f0a3e 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -678,6 +678,8 @@ class SongMediaItem(MediaManagerItem): 'authors_words_music': make_list(authors_words_music), 'authors_translation_label': AuthorType.Types[AuthorType.Translation], 'authors_translation': make_list(authors_translation), + 'authors_words_all': make_list(authors_words + authors_words_music), + 'authors_music_all': make_list(authors_music + authors_words_music), 'copyright': song.copyright, 'songbook_entries': make_list(songbooks), 'ccli_license': Settings().value('core/ccli number'), diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index fc31101d4..fb7a820cc 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -98,7 +98,6 @@ class SongsTab(SettingsTab): self.footer_layout.addWidget(self.footer_reset_button, alignment=QtCore.Qt.AlignRight) self.right_layout.addWidget(self.footer_group_box) - self.left_layout.addStretch() self.right_layout.addStretch() self.tool_bar_active_check_box.stateChanged.connect(self.on_tool_bar_active_check_box_changed) @@ -140,13 +139,17 @@ class SongsTab(SettingsTab): ['written_by', const.format(translate('SongsPlugin.SongsTab', 'Written By')), True, False], ['authors_none', translate('SongsPlugin.SongsTab', 'Authors when type is not set'), False, True], ['authors_words_label', const.format(AuthorType.Types[AuthorType.Words]), False, False], - ['authors_words', translate('SongsPlugin.SongsTab', 'Authors (Type Words)'), False, True], + ['authors_words', translate('SongsPlugin.SongsTab', 'Authors (Type "Words")'), False, True], ['authors_music_label', const.format(AuthorType.Types[AuthorType.Music]), False, False], - ['authors_music', translate('SongsPlugin.SongsTab', 'Authors (Type Music)'), False, True], + ['authors_music', translate('SongsPlugin.SongsTab', 'Authors (Type "Music")'), False, True], ['authors_words_music_label', const.format(AuthorType.Types[AuthorType.WordsAndMusic]), False, False], - ['authors_words_music', translate('SongsPlugin.SongsTab', 'Authors (Type Words and Music)'), False, True], + ['authors_words_music', translate('SongsPlugin.SongsTab', 'Authors (Type "Words and Music")'), False, True], ['authors_translation_label', const.format(AuthorType.Types[AuthorType.Translation]), False, False], - ['authors_translation', translate('SongsPlugin.SongsTab', 'Authors (Type Translation)'), False, True], + ['authors_translation', translate('SongsPlugin.SongsTab', 'Authors (Type "Translation")'), False, True], + ['authors_words_all', translate('SongsPlugin.SongsTab', 'Authors (Type "Words" & "Words and Music")'), + False, True], + ['authors_music_all', translate('SongsPlugin.SongsTab', 'Authors (Type "Music" & "Words and Music")'), + False, True], ['copyright', translate('SongsPlugin.SongsTab', 'Copyright information'), True, False], ['songbook_entries', translate('SongsPlugin.SongsTab', 'Songbook Entries'), False, True], ['ccli_license', translate('SongsPlugin.SongsTab', 'CCLI License'), True, False], @@ -166,16 +169,19 @@ class SongsTab(SettingsTab): placeholder_info += '' placeholder_info += '\n
¹ {}'.format(translate('SongsPlugin.SongsTab', 'can be empty')) placeholder_info += '\n
² {}:
{{#first}} True {}
{{entry}} {}
' \ - '{{#last}} True {}
'\ + '{{#last}} True {}
{{#last_or_penultimate}} True {}'\ .format(translate('SongsPlugin.SongsTab', 'list of entries, can be empty'), translate('SongsPlugin.SongsTab', 'for first element of list'), translate('SongsPlugin.SongsTab', 'iterates over all entries'), - translate('SongsPlugin.SongsTab', 'for last element')) + translate('SongsPlugin.SongsTab', 'for last element'), + translate('SongsPlugin.SongsTab', 'for last and second to last element')) self.footer_placeholder_info.setHtml(placeholder_info) self.footer_placeholder_info.setReadOnly(True) - + self.footer_info_label.setText(translate('SongsPlugin.SongsTab', 'How to use Footers:')) - self.footer_desc_label.setText(translate('SongsPlugin.SongsTab', 'Footer Template (Mustache Syntax):')) + self.footer_desc_label.setText('{} ({}):' + .format(translate('SongsPlugin.SongsTab', 'Footer Template'), + translate('SongsPlugin.SongsTab', 'Mustache Syntax'))) self.footer_reset_button.setText(translate('SongsPlugin.SongsTab', 'Reset Template')) def on_search_as_type_check_box_changed(self, check_state): @@ -206,7 +212,7 @@ class SongsTab(SettingsTab): self.chord_notation = 'neo-latin' def on_footer_reset_button_clicked(self): - self.footer_edit_box.setPlainText(Settings().get_default_value('songs/footer template')); + self.footer_edit_box.setPlainText(Settings().get_default_value('songs/footer template')) def load(self): settings = Settings() diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index f2e6ebde2..7dcb45840 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -93,7 +93,8 @@ MODULES = [ 'bs4', 'mako', 'uno', - 'six' + 'six', + 'pystache' ] diff --git a/setup.cfg b/setup.cfg index 0ecc03ae8..1291f1b6a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,4 @@ -[pep8] +[pycodestyle] exclude=resources.py,vlc.py max-line-length = 120 ignore = E402,E722 diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index 557891c71..9b88a96ad 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -354,6 +354,8 @@ class TestMediaItem(TestCase, TestMixin): with patch('pystache.Renderer.render') as MockedRenderer: mock_song = MagicMock() mock_song.title = 'My Song' + mock_song.alternate_title = '' + mock_song.ccli_number = '' mock_song.authors_songs = [] mock_author = MagicMock() mock_author.display_name = 'my author' @@ -372,17 +374,18 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(service_item.footer_html, "", 'pystache isnt in scope') # AND: The psytache function was called with the following arguments - MockedRenderer.assert_called_once_with('', {'authors_music_label': 'Music', - 'authors_none': [{'first': True, 'entry': 'my author', - 'last': True}], 'authors_words_music': False, - 'authors_words': False, 'authors_music': False, - 'authors_translation_label': 'Translation', + MockedRenderer.assert_called_once_with('', {'authors_translation': [], 'authors_music_label': 'Music', + 'copyright': 'My copyright', 'songbook_entries': [], + 'alternate_title': '', 'topics': [], 'authors_music_all': [], + 'authors_words_label': 'Words', 'authors_music': [], + 'authors_words_music': [], 'ccli_number': '', + 'authors_none_label': 'Written by', 'title': 'My Song', 'authors_words_music_label': 'Words and Music', - 'title': 'My Song', 'ccli_license': "0", - 'copyright': 'My copyright', 'authors_none_label': 'Written by', - 'ccli_license_label': 'CCLI License', - 'authors_translation': False, 'authors_words_label': 'Words', - 'songbook_entries': False}) + 'authors_none': [{'last_or_penultimate': True, 'last': True, + 'entry': 'my author', 'first': True}], + 'ccli_license_label': 'CCLI License', 'authors_words': [], + 'ccli_license': '0', 'authors_translation_label': 'Translation', + 'authors_words_all': []}) self.assertEqual(author_list, ['my author'], 'The author list should be returned correctly with one author') @@ -463,6 +466,8 @@ class TestMediaItem(TestCase, TestMixin): song.copyright = 'My copyright' song.authors_songs = [] song.songbook_entries = [] + song.alternate_title = '' + song.topics = [] song.ccli_number = '' book1 = MagicMock() book1.name = "My songbook"