diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py
index b15178940..08cbfdb09 100644
--- a/openlp/core/lib/serviceitem.py
+++ b/openlp/core/lib/serviceitem.py
@@ -81,7 +81,8 @@ class ServiceItem(RegistryProperties):
self.items = []
self.icon = UiIcons().default
self.raw_footer = []
- self.foot_text = ''
+ # Plugins can set footer_html themselves. If they don't, it will be generated from raw_footer.
+ self.footer_html = ''
self.theme = None
self.service_item_type = None
self.unique_identifier = 0
@@ -165,7 +166,8 @@ class ServiceItem(RegistryProperties):
# the dict instead of rendering them again.
previous_pages = {}
index = 0
- self.foot_text = '
'.join([_f for _f in self.raw_footer if _f])
+ if not self.footer_html:
+ self.footer_html = '
'.join([_f for _f in self.raw_footer if _f])
for raw_slide in self.slides:
verse_tag = raw_slide['verse']
if verse_tag in previous_pages and previous_pages[verse_tag][0] == raw_slide:
@@ -178,7 +180,7 @@ class ServiceItem(RegistryProperties):
'title': raw_slide['title'],
'text': render_tags(page),
'verse': index,
- 'footer': self.foot_text,
+ 'footer': self.footer_html,
}
self._rendered_slides.append(rendered_slide)
display_slide = {
diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py
index 2db774222..68186c2ff 100644
--- a/openlp/core/ui/printserviceform.py
+++ b/openlp/core/ui/printserviceform.py
@@ -235,11 +235,11 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
for slide in range(len(item.get_frames())):
self._add_element('li', item.get_frame_title(slide), ol)
# add footer
- foot_text = item.foot_text
- foot_text = foot_text.partition('
')[2]
- if foot_text:
- foot_text = html.escape(foot_text.replace('
', '\n'))
- self._add_element('div', foot_text.replace('\n', '
'), parent=div, class_id='itemFooter')
+ footer_html = item.footer_html
+ footer_html = footer_html.partition('
')[2]
+ if footer_html:
+ footer_html = html.escape(footer_html.replace('
', '\n'))
+ self._add_element('div', footer_html.replace('\n', '
'), parent=div, classId='itemFooter')
# Add service items' notes.
if self.notes_check_box.isChecked():
if item.notes:
diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py
index 4b99f4a72..7176593d8 100644
--- a/openlp/plugins/songs/lib/mediaitem.py
+++ b/openlp/plugins/songs/lib/mediaitem.py
@@ -21,6 +21,7 @@
###############################################################################
import logging
import os
+import mako
from PyQt5 import QtCore, QtWidgets
from sqlalchemy.sql import and_, or_
@@ -35,7 +36,7 @@ from openlp.core.lib import ServiceItemContext, check_item_selected, create_sepa
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib.serviceitem import ItemCapabilities
-from openlp.core.lib.ui import create_widget_action
+from openlp.core.lib.ui import create_widget_action, critical_error_message_box
from openlp.core.ui.icons import UiIcons
from openlp.plugins.songs.forms.editsongform import EditSongForm
from openlp.plugins.songs.forms.songexportform import SongExportForm
@@ -131,9 +132,6 @@ class SongMediaItem(MediaManagerItem):
self.is_search_as_you_type_enabled = Settings().value('advanced/search as type')
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_written_by_text = Settings().value(self.settings_section + '/display written by')
- self.display_copyright_symbol = Settings().value(self.settings_section + '/display copyright symbol')
def retranslate_ui(self):
self.search_text_label.setText('{text}:'.format(text=UiStrings().Search))
@@ -677,12 +675,8 @@ class SongMediaItem(MediaManagerItem):
item.raw_footer = []
item.raw_footer.append(song.title)
if authors_none:
- # If the setting for showing "Written by:" is enabled, show it before unspecified authors.
- if Settings().value('songs/display written by'):
- item.raw_footer.append("{text}: {authors}".format(text=translate('OpenLP.Ui', 'Written by'),
- authors=create_separated_list(authors_none)))
- else:
- item.raw_footer.append("{authors}".format(authors=create_separated_list(authors_none)))
+ item.raw_footer.append("{text}: {authors}".format(text=translate('OpenLP.Ui', 'Written by'),
+ authors=create_separated_list(authors_none)))
if authors_words_music:
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.WordsAndMusic],
authors=create_separated_list(authors_words_music)))
@@ -696,34 +690,44 @@ class SongMediaItem(MediaManagerItem):
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Translation],
authors=create_separated_list(authors_translation)))
if song.copyright:
- if self.display_copyright_symbol:
- item.raw_footer.append("{symbol} {song}".format(symbol=SongStrings.CopyrightSymbol,
- song=song.copyright))
- else:
- item.raw_footer.append(song.copyright)
- if self.display_songbook and song.songbook_entries:
- songbooks = [str(songbook_entry) for songbook_entry in song.songbook_entries]
+ item.raw_footer.append("{symbol} {song}".format(symbol=SongStrings.CopyrightSymbol,
+ song=song.copyright))
+ songbooks = [str(songbook_entry) for songbook_entry in song.songbook_entries]
+ if song.songbook_entries:
item.raw_footer.append(", ".join(songbooks))
if Settings().value('core/ccli number'):
- item.raw_footer.append(translate('SongsPlugin.MediaItem',
- 'CCLI License: ') + Settings().value('core/ccli number'))
- item.metadata.append('{label}: {title}'.format(label=translate('SongsPlugin.MediaItem', 'Title'),
- title=song.title))
- if song.alternate_title:
- item.metadata.append('{label}: {title}'.
- format(label=translate('SongsPlugin.MediaItem', 'Alt Title'),
- title=song.alternate_title))
- if song.songbook_entries:
- for songbook_entry in song.songbook_entries:
- item.metadata.append('{label}: {book}/{num}/{pub}'.
- format(label=translate('SongsPlugin.MediaItem', 'Songbook'),
- book=songbook_entry.songbook.name,
- num=songbook_entry.entry,
- pub=songbook_entry.songbook.publisher))
- if song.topics:
- for topics in song.topics:
- item.metadata.append('{label}: {topic}'.
- format(label=translate('SongsPlugin.MediaItem', 'Topic'), topic=topics.name))
+ item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
+ Settings().value('core/ccli number'))
+ footer_template = Settings().value('songs/footer template')
+ # Keep this in sync with the list in songstab.py
+ vars = {
+ 'title': song.title,
+ 'alternate_title': song.alternate_title,
+ 'authors_none_label': translate('OpenLP.Ui', 'Written by'),
+ 'authors_none': authors_none,
+ 'authors_words_label': AuthorType.Types[AuthorType.Words],
+ 'authors_words': authors_words,
+ 'authors_music_label': AuthorType.Types[AuthorType.Music],
+ 'authors_music': authors_music,
+ 'authors_words_music_label': AuthorType.Types[AuthorType.WordsAndMusic],
+ 'authors_words_music': authors_words_music,
+ 'authors_translation_label': AuthorType.Types[AuthorType.Translation],
+ 'authors_translation': authors_translation,
+ 'authors_words_all': authors_words + authors_words_music,
+ 'authors_music_all': authors_music + authors_words_music,
+ 'copyright': song.copyright,
+ 'songbook_entries': songbooks,
+ 'ccli_license': Settings().value('core/ccli number'),
+ 'ccli_license_label': translate('SongsPlugin.MediaItem', 'CCLI License'),
+ 'ccli_number': song.ccli_number,
+ 'topics': [topic.name for topic in song.topics]
+ }
+ try:
+ item.footer_html = mako.template.Template(footer_template).render_unicode(**vars).replace('\n', '')
+ except mako.exceptions.SyntaxException:
+ log.error('Failed to render Song footer html:\n' + mako.exceptions.text_error_template().render())
+ critical_error_message_box(message=translate('SongsPlugin.MediaItem',
+ 'Failed to render Song footer html.\nSee log for details'))
return authors_all
def service_load(self, item):
diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py
index 0e6cfeca9..d08a1b470 100644
--- a/openlp/plugins/songs/lib/songstab.py
+++ b/openlp/plugins/songs/lib/songstab.py
@@ -25,7 +25,7 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings
from openlp.core.lib.settingstab import SettingsTab
-from openlp.plugins.songs.lib.ui import SongStrings
+from openlp.plugins.songs.lib.db import AuthorType
class SongsTab(SettingsTab):
@@ -54,15 +54,6 @@ class SongsTab(SettingsTab):
self.songbook_slide_check_box = QtWidgets.QCheckBox(self.mode_group_box)
self.songbook_slide_check_box.setObjectName('songbook_slide_check_box')
self.mode_layout.addWidget(self.songbook_slide_check_box)
- self.display_songbook_check_box = QtWidgets.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_written_by_check_box = QtWidgets.QCheckBox(self.mode_group_box)
- self.display_written_by_check_box.setObjectName('written_by_check_box')
- self.mode_layout.addWidget(self.display_written_by_check_box)
- self.display_copyright_check_box = QtWidgets.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)
# Chords group box
self.chords_group_box = QtWidgets.QGroupBox(self.left_column)
@@ -93,20 +84,34 @@ class SongsTab(SettingsTab):
self.neolatin_notation_radio_button.setObjectName('neolatin_notation_radio_button')
self.chords_layout.addWidget(self.neolatin_notation_radio_button)
self.left_layout.addWidget(self.chords_group_box)
+ # Footer group box
+ self.footer_group_box = QtWidgets.QGroupBox(self.left_column)
+ self.footer_group_box.setObjectName('footer_group_box')
+ self.footer_layout = QtWidgets.QVBoxLayout(self.footer_group_box)
+ self.footer_layout.setObjectName('chords_layout')
+ self.footer_info_label = QtWidgets.QLabel(self.footer_group_box)
+ self.footer_layout.addWidget(self.footer_info_label)
+ self.footer_placeholder_info = QtWidgets.QTextEdit(self.footer_group_box)
+ self.footer_layout.addWidget(self.footer_placeholder_info)
+ self.footer_desc_label = QtWidgets.QLabel(self.footer_group_box)
+ self.footer_layout.addWidget(self.footer_desc_label)
+ self.footer_edit_box = QtWidgets.QTextEdit(self.footer_group_box)
+ self.footer_layout.addWidget(self.footer_edit_box)
+ self.footer_reset_button = QtWidgets.QPushButton(self.footer_group_box)
+ 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)
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.songbook_slide_check_box.stateChanged.connect(self.on_songbook_slide_check_box_changed)
- self.display_songbook_check_box.stateChanged.connect(self.on_songbook_check_box_changed)
- self.display_written_by_check_box.stateChanged.connect(self.on_written_by_check_box_changed)
- self.display_copyright_check_box.stateChanged.connect(self.on_copyright_check_box_changed)
self.mainview_chords_check_box.stateChanged.connect(self.on_mainview_chords_check_box_changed)
self.disable_chords_import_check_box.stateChanged.connect(self.on_disable_chords_import_check_box_changed)
self.english_notation_radio_button.clicked.connect(self.on_english_notation_button_clicked)
self.german_notation_radio_button.clicked.connect(self.on_german_notation_button_clicked)
self.neolatin_notation_radio_button.clicked.connect(self.on_neolatin_notation_button_clicked)
+ self.footer_reset_button.clicked.connect(self.on_footer_reset_button_clicked)
def retranslate_ui(self):
self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Song related settings'))
@@ -117,12 +122,6 @@ class SongsTab(SettingsTab):
'Import missing songs from Service files'))
self.songbook_slide_check_box.setText(translate('SongsPlugin.SongsTab',
'Add Songbooks as first slide'))
- self.display_songbook_check_box.setText(translate('SongsPlugin.SongsTab', 'Display songbook in footer'))
- self.display_written_by_check_box.setText(translate(
- 'SongsPlugin.SongsTab', 'Show "Written by:" in footer for unspecified authors'))
- self.display_copyright_check_box.setText(translate('SongsPlugin.SongsTab',
- 'Display "{symbol}" symbol before copyright '
- 'info').format(symbol=SongStrings.CopyrightSymbol))
self.chords_info_label.setText(translate('SongsPlugin.SongsTab', 'If enabled all text between "[" and "]" will '
'be regarded as chords.'))
self.chords_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Chords'))
@@ -134,6 +133,53 @@ class SongsTab(SettingsTab):
self.german_notation_radio_button.setText(translate('SongsPlugin.SongsTab', 'German') + ' (C-D-E-F-G-A-H)')
self.neolatin_notation_radio_button.setText(
translate('SongsPlugin.SongsTab', 'Neo-Latin') + ' (Do-Re-Mi-Fa-Sol-La-Si)')
+ self.footer_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Footer'))
+ # Keep this in sync with the list in mediaitem.py
+ const = '"{}"
'
+ placeholders = [
+ # placeholder, description, can be empty, is a list
+ ['title', translate('SongsPlugin.SongsTab', 'Song Title'), False, False],
+ ['alternate_title', translate('SongsPlugin.SongsTab', 'Alternate Title'), True, False],
+ ['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_music_label', const.format(AuthorType.Types[AuthorType.Music]), False, False],
+ ['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_translation_label', const.format(AuthorType.Types[AuthorType.Translation]), False, False],
+ ['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],
+ ['ccli_license_label', const.format(translate('SongsPlugin.SongsTab', 'CCLI License')), False, False],
+ ['ccli_number', translate('SongsPlugin.SongsTab', 'Song CCLI Number'), True, False],
+ ['topics', translate('SongsPlugin.SongsTab', 'Topics'), False, True],
+ ]
+ placeholder_info = '
{ph} | {desc} |
---|---|
${{{pl}}} | {des}{opt} |