mirror of https://gitlab.com/openlp/openlp.git
Adding Footer Content as Extra First Slide
This commit is contained in:
parent
9e34f9eca1
commit
d9911790d4
|
@ -146,3 +146,13 @@ class SongSearch(IntEnum):
|
|||
Themes = 7
|
||||
Copyright = 8
|
||||
CCLInumber = 9
|
||||
|
||||
|
||||
@unique
|
||||
class SongFirstSlideMode(IntEnum):
|
||||
"""
|
||||
An enumeration for song first slide types.
|
||||
"""
|
||||
Default = 0 # No cover
|
||||
Songbook = 1
|
||||
Footer = 2
|
||||
|
|
|
@ -33,7 +33,7 @@ from PyQt5 import QtCore, QtGui
|
|||
|
||||
from openlp.core.common import SlideLimits, ThemeLevel
|
||||
from openlp.core.common.enum import AlertLocation, BibleSearch, CustomSearch, ImageThemeMode, LayoutStyle, \
|
||||
DisplayStyle, LanguageSelection, SongSearch, PluginStatus
|
||||
DisplayStyle, LanguageSelection, SongFirstSlideMode, SongSearch, PluginStatus
|
||||
from openlp.core.common.json import OpenLPJSONDecoder, OpenLPJSONEncoder, is_serializable
|
||||
from openlp.core.common.path import files_to_paths, str_to_path
|
||||
from openlp.core.common.platform import is_linux, is_win
|
||||
|
@ -42,7 +42,7 @@ from openlp.core.ui.style import UiThemes
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__version__ = 2
|
||||
__version__ = 3
|
||||
|
||||
|
||||
class ProxyMode(IntEnum):
|
||||
|
@ -116,6 +116,16 @@ def upgrade_dark_theme_to_ui_theme(value):
|
|||
return UiThemes.QDarkStyle if value else UiThemes.Automatic
|
||||
|
||||
|
||||
def upgrade_add_first_songbook_slide_config(value):
|
||||
"""
|
||||
Upgrade the "songs/add songbook slide" property to "songs/add first slide".
|
||||
|
||||
:param bool value: the old "add_songbook_slide" value
|
||||
:returns SongFirstSlideMode: new SongFirstSlideMode value
|
||||
"""
|
||||
return SongFirstSlideMode.Songbook if value is True else SongFirstSlideMode.Default
|
||||
|
||||
|
||||
class Settings(QtCore.QSettings):
|
||||
"""
|
||||
Class to wrap QSettings.
|
||||
|
@ -338,7 +348,7 @@ class Settings(QtCore.QSettings):
|
|||
'songs/last import type': 0,
|
||||
'songs/update service on edit': False,
|
||||
'songs/add song from service': True,
|
||||
'songs/add songbook slide': False,
|
||||
'songs/first slide mode': SongFirstSlideMode.Default,
|
||||
'songs/display songbar': True,
|
||||
'songs/last directory import': None,
|
||||
'songs/last directory export': None,
|
||||
|
@ -472,6 +482,10 @@ class Settings(QtCore.QSettings):
|
|||
('themes/last directory', 'themes/last directory', [(str_to_path, None)]),
|
||||
('themes/wrap footer', '', []),
|
||||
]
|
||||
# Settings upgrades for 3.1
|
||||
__setting_upgrade_3__ = [
|
||||
('songs/add songbook slide', 'songs/first slide mode', [(upgrade_add_first_songbook_slide_config, False)])
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def extend_default_settings(default_values):
|
||||
|
|
|
@ -683,7 +683,13 @@ var Display = {
|
|||
var footerSlide = document.createElement('div');
|
||||
footerSlide.classList.add('footer-item');
|
||||
footerSlide.setAttribute('data-slide', index);
|
||||
if (index == 0) {
|
||||
var currentSlide = Reveal.getIndices();
|
||||
if (currentSlide) {
|
||||
currentSlide = currentSlide.v;
|
||||
} else {
|
||||
currentSlide = 0;
|
||||
}
|
||||
if (index == currentSlide) {
|
||||
footerSlide.classList.add('active');
|
||||
}
|
||||
footerSlide.innerHTML = slide.footer;
|
||||
|
|
|
@ -144,6 +144,22 @@ def remove_chords(text):
|
|||
return _get_chord_match().sub(r'', text)
|
||||
|
||||
|
||||
RE_HTML_STRIP = re.compile(r'<[^>]+>')
|
||||
|
||||
|
||||
def remove_html_and_strip(text):
|
||||
"""
|
||||
Removes all HTML from the text and strips the whitespace from the remaining lines.
|
||||
"""
|
||||
lines = map(__clean_html_line, text.split('\n'))
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def __clean_html_line(line):
|
||||
line = RE_HTML_STRIP.sub('', line)
|
||||
return line.strip()
|
||||
|
||||
|
||||
def remove_tags(text, can_remove_chords=False):
|
||||
"""
|
||||
Remove Tags from text for display
|
||||
|
@ -152,6 +168,8 @@ def remove_tags(text, can_remove_chords=False):
|
|||
:param can_remove_chords: Can we remove the chords too?
|
||||
"""
|
||||
text = text.replace('<br>', '\n')
|
||||
text = text.replace('<br/>', '\n')
|
||||
text = text.replace('<br />', '\n')
|
||||
text = text.replace('{br}', '\n')
|
||||
text = text.replace(' ', ' ')
|
||||
text = text.replace('<sup>', '')
|
||||
|
|
|
@ -39,7 +39,7 @@ from openlp.core.common.i18n import translate
|
|||
from openlp.core.common.mixins import RegistryProperties
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.utils import wait_for
|
||||
from openlp.core.display.render import remove_tags, render_tags, render_chords_for_printing
|
||||
from openlp.core.display.render import remove_html_and_strip, remove_tags, render_tags, render_chords_for_printing
|
||||
from openlp.core.lib import create_thumb, image_to_data_uri, ItemCapabilities
|
||||
from openlp.core.lib.theme import BackgroundType, TransitionSpeed
|
||||
from openlp.core.state import State
|
||||
|
@ -237,13 +237,20 @@ class ServiceItem(RegistryProperties):
|
|||
self._rendered_slides.append(rendered_slide)
|
||||
display_slide = {
|
||||
'title': raw_slide['title'],
|
||||
'text': remove_tags(page, can_remove_chords=True),
|
||||
'text': remove_html_and_strip(remove_tags(page, can_remove_chords=True)),
|
||||
'verse': verse_tag,
|
||||
}
|
||||
self._display_slides.append(display_slide)
|
||||
index += 1
|
||||
self._creating_slides = False
|
||||
|
||||
def _clear_slides_cache(self):
|
||||
"""
|
||||
Clears the internal representation/cache of slides (display_slides and rendered_slides).
|
||||
"""
|
||||
self._display_slides = None
|
||||
self._rendered_slides = None
|
||||
|
||||
@property
|
||||
def rendered_slides(self):
|
||||
"""
|
||||
|
@ -309,13 +316,41 @@ class ServiceItem(RegistryProperties):
|
|||
self.slides.append(slide)
|
||||
self._new_item()
|
||||
|
||||
def add_from_text(self, text, verse_tag=None, footer_html=None):
|
||||
def add_from_text(self, text, verse_tag=None, footer_html=None, metadata=None):
|
||||
"""
|
||||
Add a text slide to the service item.
|
||||
|
||||
:param text: The raw text of the slide.
|
||||
:param verse_tag:
|
||||
:param footer_html: Custom HTML footer for current slide
|
||||
:param metadata: Additional metadata to add to service item
|
||||
"""
|
||||
slide = self._create_slide_from_text(text, verse_tag, footer_html, metadata)
|
||||
self.slides.append(slide)
|
||||
self._new_item()
|
||||
|
||||
def replace_slide_from_text(self, index, text, verse_tag=None, footer_html=None, metadata=None):
|
||||
"""
|
||||
Replace a text slide on the service item.
|
||||
|
||||
:param index: The index of slide to replace
|
||||
:param text: The raw text of the slide.
|
||||
:param verse_tag:
|
||||
:param footer_html: Custom HTML footer for current slide
|
||||
:param metadata: Additional metadata to add to service item
|
||||
"""
|
||||
slide = self._create_slide_from_text(text, verse_tag, footer_html, metadata)
|
||||
self.slides[index] = slide
|
||||
self._clear_slides_cache()
|
||||
|
||||
def _create_slide_from_text(self, text, verse_tag=None, footer_html=None, metadata=None):
|
||||
"""
|
||||
Creates a text slide.
|
||||
|
||||
:param text: The raw text of the slide.
|
||||
:param verse_tag:
|
||||
:param footer_html: Custom HTML footer for current slide
|
||||
:param metadata: Additional metadata to add to service item
|
||||
"""
|
||||
if verse_tag:
|
||||
verse_tag = verse_tag.upper()
|
||||
|
@ -327,8 +362,9 @@ class ServiceItem(RegistryProperties):
|
|||
slide = {'title': title, 'text': text, 'verse': verse_tag}
|
||||
if footer_html is not None:
|
||||
slide['footer_html'] = footer_html
|
||||
self.slides.append(slide)
|
||||
self._new_item()
|
||||
if isinstance(metadata, dict):
|
||||
slide['metadata'] = metadata
|
||||
return slide
|
||||
|
||||
def add_from_command(self, path, file_name, image, display_title=None, notes=None, file_hash=None):
|
||||
"""
|
||||
|
@ -517,7 +553,8 @@ class ServiceItem(RegistryProperties):
|
|||
if self.service_item_type == ServiceItemType.Text:
|
||||
for slide in service_item['serviceitem']['data']:
|
||||
footer_html = slide['footer_html'] if 'footer_html' in slide else None
|
||||
self.add_from_text(slide['raw_slide'], slide['verseTag'], footer_html)
|
||||
metadata = slide['metadata'] if 'metadata' in slide and isinstance(slide['metadata'], dict) else None
|
||||
self.add_from_text(slide['raw_slide'], slide['verseTag'], footer_html, metadata)
|
||||
self._create_slides()
|
||||
elif self.service_item_type == ServiceItemType.Image:
|
||||
if path:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import mako
|
||||
import os
|
||||
|
@ -28,7 +29,7 @@ from sqlalchemy.sql import and_, or_
|
|||
|
||||
from openlp.core.state import State
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.enum import SongSearch
|
||||
from openlp.core.common.enum import SongFirstSlideMode, SongSearch
|
||||
from openlp.core.common.i18n import UiStrings, get_natural_key, translate
|
||||
from openlp.core.common.path import create_paths
|
||||
from openlp.core.common.registry import Registry
|
||||
|
@ -565,19 +566,11 @@ class SongMediaItem(MediaManagerItem):
|
|||
service_item.theme = song.theme_name
|
||||
service_item.edit_id = item_id
|
||||
verse_list = SongXML().get_verses(song.lyrics)
|
||||
if self.settings.value('songs/add songbook slide') and song.songbook_entries:
|
||||
first_slide = '\n'
|
||||
for songbook_entry in song.songbook_entries:
|
||||
if songbook_entry.entry:
|
||||
first_slide += '{book} #{num}'.format(book=songbook_entry.songbook.name,
|
||||
num=songbook_entry.entry)
|
||||
else:
|
||||
first_slide += songbook_entry.songbook.name
|
||||
if songbook_entry.songbook.publisher:
|
||||
first_slide += ' ({pub})'.format(pub=songbook_entry.songbook.publisher)
|
||||
first_slide += '\n\n'
|
||||
|
||||
service_item.add_from_text(first_slide, 'O1')
|
||||
authors = self._get_music_authors(song)
|
||||
songbooks_str = [str(songbook_entry) for songbook_entry in song.songbook_entries]
|
||||
mako_vars = self._get_mako_vars(song, authors, songbooks_str)
|
||||
service_item.title = song.title
|
||||
author_list = self.generate_first_slide_and_footer(service_item, song, authors, songbooks_str, mako_vars)
|
||||
# no verse list or only 1 space (in error)
|
||||
verse_tags_translated = False
|
||||
if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None:
|
||||
|
@ -616,8 +609,6 @@ class SongMediaItem(MediaManagerItem):
|
|||
force_verse = verse[1].split('[--}{--]\n')
|
||||
for split_verse in force_verse:
|
||||
service_item.add_from_text(split_verse, verse_def)
|
||||
service_item.title = song.title
|
||||
author_list = self.generate_footer(service_item, song)
|
||||
service_item.data_string = {
|
||||
'title': song.search_title,
|
||||
'alternate_title': song.alternate_title,
|
||||
|
@ -643,14 +634,48 @@ class SongMediaItem(MediaManagerItem):
|
|||
service_item.will_auto_start = bool(self.settings.value('songs/auto play audio'))
|
||||
return True
|
||||
|
||||
def generate_footer(self, item, song):
|
||||
def generate_footer(self, item, song, authors, songbooks, mako_vars):
|
||||
"""
|
||||
Generates the song footer based on a song and adds details to a service item.
|
||||
|
||||
:param item: The service item to be amended
|
||||
:param song: The song to be used to generate the footer
|
||||
:param authors: The authors of the song
|
||||
:return: List of all authors (only required for initial song generation)
|
||||
"""
|
||||
item.audit = [
|
||||
song.title, authors.all, song.copyright, str(song.ccli_number)
|
||||
]
|
||||
item.raw_footer = []
|
||||
item.raw_footer.append(song.title)
|
||||
if 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)))
|
||||
if authors.words:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Words],
|
||||
authors=create_separated_list(authors.words)))
|
||||
if authors.music:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Music],
|
||||
authors=create_separated_list(authors.music)))
|
||||
if authors.translation:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Translation],
|
||||
authors=create_separated_list(authors.translation)))
|
||||
if song.copyright:
|
||||
item.raw_footer.append("{symbol} {song}".format(symbol=SongStrings.CopyrightSymbol,
|
||||
song=song.copyright))
|
||||
if song.songbook_entries:
|
||||
item.raw_footer.append(", ".join(songbooks))
|
||||
if self.settings.value('core/ccli number'):
|
||||
item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
||||
self.settings.value('core/ccli number'))
|
||||
item.footer_html = self._generate_mako_footer(mako_vars)
|
||||
return authors.all
|
||||
|
||||
def _get_music_authors(self, song):
|
||||
authors_tuple = namedtuple('AuthorsTuple', ['words', 'music', 'words_music', 'translation', 'none', 'all'])
|
||||
authors_words = []
|
||||
authors_music = []
|
||||
authors_words_music = []
|
||||
|
@ -668,66 +693,45 @@ class SongMediaItem(MediaManagerItem):
|
|||
else:
|
||||
authors_none.append(author_song.author.display_name)
|
||||
authors_all = authors_words_music + authors_words + authors_music + authors_translation + authors_none
|
||||
item.audit = [
|
||||
song.title, authors_all, song.copyright, str(song.ccli_number)
|
||||
]
|
||||
item.raw_footer = []
|
||||
item.raw_footer.append(song.title)
|
||||
if 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)))
|
||||
if authors_words:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Words],
|
||||
authors=create_separated_list(authors_words)))
|
||||
if authors_music:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Music],
|
||||
authors=create_separated_list(authors_music)))
|
||||
if authors_translation:
|
||||
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Translation],
|
||||
authors=create_separated_list(authors_translation)))
|
||||
if song.copyright:
|
||||
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 self.settings.value('core/ccli number'):
|
||||
item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
||||
self.settings.value('core/ccli number'))
|
||||
footer_template = self.settings.value('songs/footer template')
|
||||
return authors_tuple(authors_words, authors_music, authors_words_music, authors_translation, authors_none,
|
||||
authors_all)
|
||||
|
||||
def _get_mako_vars(self, song, authors, songbooks):
|
||||
# Keep this in sync with the list in songstab.py
|
||||
vars = {
|
||||
return {
|
||||
'title': song.title,
|
||||
'alternate_title': song.alternate_title,
|
||||
'authors_none_label': translate('OpenLP.Ui', 'Written by'),
|
||||
'authors_none': authors_none,
|
||||
'authors_none': authors.none,
|
||||
'authors_words_label': AuthorType.Types[AuthorType.Words],
|
||||
'authors_words': authors_words,
|
||||
'authors_words': authors.words,
|
||||
'authors_music_label': AuthorType.Types[AuthorType.Music],
|
||||
'authors_music': authors_music,
|
||||
'authors_music': authors.music,
|
||||
'authors_words_music_label': AuthorType.Types[AuthorType.WordsAndMusic],
|
||||
'authors_words_music': authors_words_music,
|
||||
'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,
|
||||
'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': self.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]
|
||||
'topics': [topic.name for topic in song.topics],
|
||||
'first_slide': False
|
||||
}
|
||||
|
||||
def _generate_mako_footer(self, vars, show_error=True):
|
||||
footer_template = self.settings.value('songs/footer template')
|
||||
try:
|
||||
item.footer_html = mako.template.Template(footer_template).render_unicode(**vars).replace('\n', '')
|
||||
return 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
|
||||
if show_error:
|
||||
critical_error_message_box(message=translate('SongsPlugin.MediaItem',
|
||||
'Failed to render Song footer html.\nSee log for details'))
|
||||
return None
|
||||
|
||||
def service_load(self, item):
|
||||
"""
|
||||
|
@ -765,10 +769,56 @@ class SongMediaItem(MediaManagerItem):
|
|||
self._update_background_audio(song, item)
|
||||
edit_id = song.id
|
||||
# Update service with correct song id and return it to caller.
|
||||
authors = self._get_music_authors(song)
|
||||
songbooks_str = [str(songbook_entry) for songbook_entry in song.songbook_entries]
|
||||
mako_vars = self._get_mako_vars(song, authors, songbooks_str)
|
||||
self.generate_footer(item, song, authors, songbooks_str, mako_vars)
|
||||
if len(item.slides):
|
||||
first_slide = item.slides[0]
|
||||
if 'metadata' in first_slide and 'songs_first_slide_type' in first_slide['metadata']:
|
||||
try:
|
||||
slide_mode = SongFirstSlideMode(first_slide['metadata']['songs_first_slide_type'])
|
||||
if slide_mode == SongFirstSlideMode.Footer:
|
||||
# For now only the footer needs to be regenerated on import, as it's dependent on what
|
||||
# user defined on each OpenLP instance settings.
|
||||
self.generate_first_slide_and_footer(item, song, authors, songbooks_str, mako_vars, True)
|
||||
except ValueError:
|
||||
# Maybe it's a new slide mode generated in a greater OpenLP version, better leave it as-is.
|
||||
pass
|
||||
item.edit_id = edit_id
|
||||
self.generate_footer(item, song)
|
||||
return item
|
||||
|
||||
def generate_first_slide_and_footer(self, service_item, song, authors, songbooks_str, mako_vars, replace=False):
|
||||
song_first_slide = self.settings.value('songs/first slide mode')
|
||||
service_item.title = song.title
|
||||
author_list = self.generate_footer(service_item, song, authors, songbooks_str, mako_vars)
|
||||
slide_metadata = {'songs_first_slide_type': song_first_slide}
|
||||
if song_first_slide == SongFirstSlideMode.Songbook and song.songbook_entries:
|
||||
first_slide = '\n'
|
||||
for songbook_entry in song.songbook_entries:
|
||||
if songbook_entry.entry:
|
||||
first_slide += '{book} #{num}'.format(book=songbook_entry.songbook.name,
|
||||
num=songbook_entry.entry)
|
||||
else:
|
||||
first_slide += songbook_entry.songbook.name
|
||||
if songbook_entry.songbook.publisher:
|
||||
first_slide += ' ({pub})'.format(pub=songbook_entry.songbook.publisher)
|
||||
first_slide += '\n\n'
|
||||
if replace:
|
||||
service_item.replace_slide_from_text(0, first_slide, 'O1', metadata=slide_metadata)
|
||||
else:
|
||||
service_item.add_from_text(first_slide, 'O1', metadata=slide_metadata)
|
||||
elif song_first_slide == SongFirstSlideMode.Footer:
|
||||
mako_vars['first_slide'] = True
|
||||
first_slide = self._generate_mako_footer(mako_vars, False) # Avoiding show message error box twice
|
||||
first_slide = first_slide if first_slide is not None else '\n'.join(service_item.raw_footer)
|
||||
if replace:
|
||||
service_item.replace_slide_from_text(0, first_slide, 'O2', footer_html='', metadata=slide_metadata)
|
||||
else:
|
||||
service_item.add_from_text(first_slide, 'O2', footer_html='', metadata=slide_metadata)
|
||||
mako_vars['first_slide'] = False
|
||||
return author_list
|
||||
|
||||
@staticmethod
|
||||
def _authors_match(song, authors):
|
||||
"""
|
||||
|
|
|
@ -132,7 +132,7 @@ class SongXML(object):
|
|||
if self.song_xml is not None:
|
||||
xml_iter = self.song_xml.getiterator()
|
||||
for element in xml_iter:
|
||||
if element.tag == 'verse':
|
||||
if etree.QName(element).localname == 'verse':
|
||||
if element.text is None:
|
||||
element.text = ''
|
||||
verse_list.append([element.attrib, str(element.text)])
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core.common.i18n import translate
|
||||
from openlp.core.common.enum import SongFirstSlideMode
|
||||
from openlp.core.lib.settingstab import SettingsTab
|
||||
from openlp.plugins.songs.lib.db import AuthorType
|
||||
|
||||
|
@ -50,12 +51,20 @@ class SongsTab(SettingsTab):
|
|||
self.add_from_service_check_box = QtWidgets.QCheckBox(self.mode_group_box)
|
||||
self.add_from_service_check_box.setObjectName('add_from_service_check_box')
|
||||
self.mode_layout.addWidget(self.add_from_service_check_box)
|
||||
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.auto_play_check_box = QtWidgets.QCheckBox(self.mode_group_box)
|
||||
self.auto_play_check_box.setObjectName('auto_play_check_box')
|
||||
self.mode_layout.addWidget(self.auto_play_check_box)
|
||||
# First Slide Mode
|
||||
self.first_slide_mode_widget = QtWidgets.QWidget(self.mode_group_box)
|
||||
self.first_slide_mode_layout = QtWidgets.QHBoxLayout(self.first_slide_mode_widget)
|
||||
self.first_slide_mode_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.first_slide_mode_label = QtWidgets.QLabel(self.first_slide_mode_widget)
|
||||
self.first_slide_mode_combobox = QtWidgets.QComboBox(self.first_slide_mode_widget)
|
||||
self.first_slide_mode_combobox.addItems(['', '', ''])
|
||||
self.first_slide_mode_layout.addWidget(self.first_slide_mode_label)
|
||||
self.first_slide_mode_layout.addWidget(self.first_slide_mode_combobox)
|
||||
self.first_slide_mode_widget.setLayout(self.first_slide_mode_layout)
|
||||
self.mode_layout.addWidget(self.first_slide_mode_widget)
|
||||
self.left_layout.addWidget(self.mode_group_box)
|
||||
|
||||
# Chords group box
|
||||
|
@ -141,7 +150,7 @@ class SongsTab(SettingsTab):
|
|||
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.first_slide_mode_combobox.currentIndexChanged.connect(self.on_first_slide_mode_combo_box_changed)
|
||||
self.auto_play_check_box.stateChanged.connect(self.on_auto_play_check_box_changed)
|
||||
self.disable_chords_import_check_box.stateChanged.connect(self.on_disable_chords_import_check_box_changed)
|
||||
self.song_key_warning_check_box.stateChanged.connect(self.on_song_key_warning_check_box_changed)
|
||||
|
@ -157,8 +166,10 @@ class SongsTab(SettingsTab):
|
|||
self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit'))
|
||||
self.add_from_service_check_box.setText(translate('SongsPlugin.SongsTab',
|
||||
'Import missing songs from Service files'))
|
||||
self.songbook_slide_check_box.setText(translate('SongsPlugin.SongsTab',
|
||||
'Add Songbooks as first slide'))
|
||||
self.first_slide_mode_label.setText(translate('SongsPlugin.SongsTab', 'Add first slide:'))
|
||||
self.first_slide_mode_combobox.setItemText(0, translate('SongsPlugin.SongsTab', 'None'))
|
||||
self.first_slide_mode_combobox.setItemText(1, translate('SongsPlugin.SongsTab', 'Songbook'))
|
||||
self.first_slide_mode_combobox.setItemText(2, translate('SongsPlugin.SongsTab', 'Same as Footer'))
|
||||
self.auto_play_check_box.setText(translate('SongsPlugin.SongsTab', 'Auto-play background audio'))
|
||||
self.chords_info_label.setText(translate('SongsPlugin.SongsTab', 'If enabled all text between "[" and "]" will '
|
||||
'be regarded as chords.'))
|
||||
|
@ -201,6 +212,7 @@ class SongsTab(SettingsTab):
|
|||
['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],
|
||||
['first_slide', translate('SongsPlugin.SongsTab', 'Where rendering on first (cover) slide'), False, False],
|
||||
]
|
||||
placeholder_info = '<table><tr><th><b>{ph}</b></th><th><b>{desc}</b></th></tr>'.format(
|
||||
ph=translate('SongsPlugin.SongsTab', 'Placeholder'), desc=translate('SongsPlugin.SongsTab', 'Description'))
|
||||
|
@ -233,8 +245,8 @@ class SongsTab(SettingsTab):
|
|||
def on_add_from_service_check_box_changed(self, check_state):
|
||||
self.update_load = (check_state == QtCore.Qt.Checked)
|
||||
|
||||
def on_songbook_slide_check_box_changed(self, check_state):
|
||||
self.songbook_slide = (check_state == QtCore.Qt.Checked)
|
||||
def on_first_slide_mode_combo_box_changed(self, index):
|
||||
self.first_slide_mode = SongFirstSlideMode(index)
|
||||
|
||||
def on_auto_play_check_box_changed(self, check_state):
|
||||
self.auto_play = (check_state == QtCore.Qt.Checked)
|
||||
|
@ -264,7 +276,7 @@ class SongsTab(SettingsTab):
|
|||
self.tool_bar = self.settings.value('songs/display songbar')
|
||||
self.update_edit = self.settings.value('songs/update service on edit')
|
||||
self.update_load = self.settings.value('songs/add song from service')
|
||||
self.songbook_slide = self.settings.value('songs/add songbook slide')
|
||||
self.first_slide_mode = self.settings.value('songs/first slide mode')
|
||||
self.auto_play = self.settings.value('songs/auto play audio')
|
||||
self.enable_chords = self.settings.value('songs/enable chords')
|
||||
self.chord_notation = self.settings.value('songs/chord notation')
|
||||
|
@ -286,6 +298,8 @@ class SongsTab(SettingsTab):
|
|||
self.ccli_username.setText(self.settings.value('songs/songselect username'))
|
||||
self.ccli_password.setText(self.settings.value('songs/songselect password'))
|
||||
self.footer_edit_box.setPlainText(self.settings.value('songs/footer template'))
|
||||
if self.first_slide_mode > 0:
|
||||
self.first_slide_mode_combobox.setCurrentIndex(self.first_slide_mode)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
|
@ -315,7 +329,7 @@ class SongsTab(SettingsTab):
|
|||
# Only save footer template if it has been changed. This allows future updates
|
||||
if self.footer_edit_box.toPlainText() != self.settings.value('songs/footer template'):
|
||||
self.settings.setValue('songs/footer template', self.footer_edit_box.toPlainText())
|
||||
self.settings.setValue('songs/add songbook slide', self.songbook_slide)
|
||||
self.settings.setValue('songs/first slide mode', self.first_slide_mode)
|
||||
if self.tab_visited:
|
||||
self.settings_form.register_post_process('songs_config_updated')
|
||||
self.tab_visited = False
|
||||
|
|
|
@ -781,6 +781,8 @@ describe("Display.setTextSlide", function () {
|
|||
});
|
||||
|
||||
describe("Display.setTextSlides", function () {
|
||||
var textSlides;
|
||||
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
|
@ -788,10 +790,7 @@ describe("Display.setTextSlides", function () {
|
|||
Display._slidesContainer = slides_container;
|
||||
Display._footerContainer = footer_container;
|
||||
Display._slides = {};
|
||||
});
|
||||
|
||||
it("should add a list of slides", function () {
|
||||
var slides = [
|
||||
textSlides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
|
@ -805,6 +804,10 @@ describe("Display.setTextSlides", function () {
|
|||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
it("should add a list of slides", function () {
|
||||
var slides = textSlides;
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
@ -819,14 +822,7 @@ describe("Display.setTextSlides", function () {
|
|||
});
|
||||
|
||||
it("should correctly set outline width", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
const slides = [textSlides[0]];
|
||||
const theme = {
|
||||
'font_main_color': 'yellow',
|
||||
'font_main_outline': true,
|
||||
|
@ -845,14 +841,7 @@ describe("Display.setTextSlides", function () {
|
|||
|
||||
it("should correctly set text alignment,\
|
||||
(check the order of alignments in the emuns are the same in both js and python)", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
const slides = [textSlides[0]];
|
||||
//
|
||||
const theme = {
|
||||
'display_horizontal_align': 3,
|
||||
|
@ -870,14 +859,7 @@ describe("Display.setTextSlides", function () {
|
|||
})
|
||||
|
||||
it("should enable shadows", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
const slides = [textSlides[0]];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_shadow': true,
|
||||
|
@ -895,14 +877,7 @@ describe("Display.setTextSlides", function () {
|
|||
})
|
||||
|
||||
it("should not enable shadows", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
const slides = [textSlides[0]];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_shadow': false,
|
||||
|
@ -920,14 +895,7 @@ describe("Display.setTextSlides", function () {
|
|||
})
|
||||
|
||||
it("should correctly set slide size position to theme size when adding a text slide", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
const slides = [textSlides[0]];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_y': 789,
|
||||
|
@ -949,20 +917,7 @@ describe("Display.setTextSlides", function () {
|
|||
})
|
||||
|
||||
it("should work correctly with different footer contents per slide", function () {
|
||||
var slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
},
|
||||
{
|
||||
"verse": "v2",
|
||||
"text": "'twas Grace that taught, my heart to fear\nAnd grace, my fears relieved.\n" +
|
||||
"How precious did that grace appear,\nthe hour I first believed.",
|
||||
"footer": "Public Domain, Second Test"
|
||||
}
|
||||
];
|
||||
var slides = textSlides;
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
|
@ -974,6 +929,19 @@ describe("Display.setTextSlides", function () {
|
|||
expect(document.querySelectorAll(".footer > .footer-item")[0].innerHTML).toEqual(slides[0].footer);
|
||||
expect(document.querySelectorAll(".footer > .footer-item")[1].innerHTML).toEqual(slides[1].footer);
|
||||
});
|
||||
|
||||
it("should select correct footer index when resetting text", function () {
|
||||
var slides = textSlides;
|
||||
slides[1]['footer'] = 'Public Domain, Second Test';
|
||||
|
||||
Display.init({isDisplay: false});
|
||||
Display.setTextSlides(slides);
|
||||
spyOn(Reveal, 'getIndices').and.returnValue({v: 1, h: 0});
|
||||
slides[1]['footer'] = 'Second Slide';
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
expect(document.querySelectorAll(".footer > .footer-item")[1].classList.contains('active')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Display.setImageSlides", function () {
|
||||
|
@ -1250,4 +1218,4 @@ describe("Reveal slidechanged event", function () {
|
|||
currentSlide.id = '1';
|
||||
Display._onSlideChanged({currentSlide: currentSlide});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -985,10 +985,8 @@ def test_add_from_text_adds_per_slide_footer_html():
|
|||
|
||||
# THEN: Slides should be added with correctly numbered verse tags (Should start at 1)
|
||||
assert service_item.slides == [
|
||||
{'text': 'This is the first slide', 'title': 'This is the first slide', 'verse': '1',
|
||||
'footer_html': slide1FooterHtml},
|
||||
{'text': 'This is the second slide', 'title': 'This is the second slide', 'verse': '2',
|
||||
'footer_html': slide2FooterHtml}
|
||||
{'text': slide1, 'title': slide1, 'verse': '1', 'footer_html': slide1FooterHtml},
|
||||
{'text': slide2, 'title': slide2, 'verse': '2', 'footer_html': slide2FooterHtml}
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -26,10 +26,13 @@ from unittest.mock import MagicMock, patch
|
|||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common.enum import SongFirstSlideMode
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib.serviceitem import ServiceItem
|
||||
from openlp.plugins.songs.lib.db import AuthorType, Song
|
||||
from openlp.plugins.songs.lib.mediaitem import SongMediaItem
|
||||
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
|
||||
|
||||
|
||||
__default_settings__ = {
|
||||
'songs/footer template': """
|
||||
|
@ -88,6 +91,10 @@ ${title}<br/>
|
|||
}
|
||||
|
||||
|
||||
SONG_VERSES_TEST_LYRICS = [[{'type': 'v', 'label': '1'}, 'Test text']]
|
||||
SONG_VERSES_TEST_VERSE_ORDER = 'v1'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def media_item(settings):
|
||||
Registry().register('service_list', MagicMock())
|
||||
|
@ -370,9 +377,12 @@ def test_build_song_footer_two_authors(media_item):
|
|||
mock_song.copyright = 'My copyright'
|
||||
mock_song.songbook_entries = []
|
||||
service_item = ServiceItem(None)
|
||||
songbooks_str = []
|
||||
authors = media_item._get_music_authors(mock_song)
|
||||
mako_vars = media_item._get_mako_vars(mock_song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
author_list = media_item.generate_footer(service_item, mock_song)
|
||||
author_list = media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: I get the following Array returned
|
||||
assert service_item.raw_footer == ['My Song', 'Words: another author', 'Music: my author',
|
||||
|
@ -393,9 +403,12 @@ def test_build_song_footer_base_ccli(media_item):
|
|||
mock_song.songbook_entries = []
|
||||
service_item = ServiceItem(None)
|
||||
media_item.settings.setValue('core/ccli number', '1234')
|
||||
songbooks_str = []
|
||||
authors = media_item._get_music_authors(mock_song)
|
||||
mako_vars = media_item._get_mako_vars(mock_song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
media_item.generate_footer(service_item, mock_song)
|
||||
media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: I get the following Array returned
|
||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 1234'], \
|
||||
|
@ -403,7 +416,7 @@ def test_build_song_footer_base_ccli(media_item):
|
|||
|
||||
# WHEN: I amend the CCLI value
|
||||
media_item.settings.setValue('core/ccli number', '4321')
|
||||
media_item.generate_footer(service_item, mock_song)
|
||||
media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: I would get an amended footer string
|
||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 4321'], \
|
||||
|
@ -428,13 +441,16 @@ def test_build_song_footer_base_songbook(media_item):
|
|||
book1.name = 'My songbook'
|
||||
book2 = MagicMock()
|
||||
book2.name = 'Thy songbook'
|
||||
song.songbookentries = []
|
||||
song.songbook_entries = []
|
||||
song.add_songbook_entry(book1, '12')
|
||||
song.add_songbook_entry(book2, '502A')
|
||||
service_item = ServiceItem(None)
|
||||
songbooks_str = [str(songbook) for songbook in song.songbook_entries]
|
||||
authors = media_item._get_music_authors(song)
|
||||
mako_vars = media_item._get_mako_vars(song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
media_item.generate_footer(service_item, song)
|
||||
media_item.generate_footer(service_item, song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: The songbook should be in the footer
|
||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'My songbook #12, Thy songbook #502A']
|
||||
|
@ -451,9 +467,12 @@ def test_build_song_footer_copyright_enabled(media_item):
|
|||
mock_song.copyright = 'My copyright'
|
||||
mock_song.songbook_entries = []
|
||||
service_item = ServiceItem(None)
|
||||
songbooks_str = []
|
||||
authors = media_item._get_music_authors(mock_song)
|
||||
mako_vars = media_item._get_mako_vars(mock_song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
media_item.generate_footer(service_item, mock_song)
|
||||
media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: The copyright symbol should be in the footer
|
||||
assert service_item.raw_footer == ['My Song', '© My copyright']
|
||||
|
@ -469,9 +488,12 @@ def test_build_song_footer_copyright_disabled(media_item):
|
|||
mock_song.copyright = 'My copyright'
|
||||
mock_song.songbook_entries = []
|
||||
service_item = ServiceItem(None)
|
||||
songbooks_str = []
|
||||
authors = media_item._get_music_authors(mock_song)
|
||||
mako_vars = media_item._get_mako_vars(mock_song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
media_item.generate_footer(service_item, mock_song)
|
||||
media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: The copyright symbol should not be in the footer
|
||||
assert service_item.raw_footer == ['My Song', '© My copyright']
|
||||
|
@ -601,9 +623,12 @@ def test_build_song_footer_one_author_show_written_by(media_item):
|
|||
mock_song.copyright = 'My copyright'
|
||||
mock_song.songbook_entries = []
|
||||
service_item = ServiceItem(None)
|
||||
songbooks_str = []
|
||||
authors = media_item._get_music_authors(mock_song)
|
||||
mako_vars = media_item._get_mako_vars(mock_song, authors, songbooks_str)
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
author_list = media_item.generate_footer(service_item, mock_song)
|
||||
author_list = media_item.generate_footer(service_item, mock_song, authors, songbooks_str, mako_vars)
|
||||
|
||||
# THEN: The mako function was called with the following arguments
|
||||
args = {'authors_translation': [], 'authors_music_label': 'Music',
|
||||
|
@ -616,6 +641,66 @@ def test_build_song_footer_one_author_show_written_by(media_item):
|
|||
'authors_none': ['my author'],
|
||||
'ccli_license_label': 'CCLI License', 'authors_words': [],
|
||||
'ccli_license': '0', 'authors_translation_label': 'Translation',
|
||||
'authors_words_all': []}
|
||||
'authors_words_all': [], 'first_slide': False}
|
||||
MockedRenderer.assert_called_once_with(**args)
|
||||
assert author_list == ['my author'], 'The author list should be returned correctly with one author'
|
||||
|
||||
|
||||
@patch('openlp.plugins.songs.lib.mediaitem.SongMediaItem._get_id_of_item_to_generate')
|
||||
@patch('openlp.plugins.songs.lib.mediaitem.SongXML.get_verses')
|
||||
@pytest.mark.parametrize('first_slide_mode', SongFirstSlideMode)
|
||||
def test_song_first_slide_creation_works(mocked_get_verses, mocked__get_id_of_item_to_generate, media_item,
|
||||
first_slide_mode, settings):
|
||||
"""
|
||||
Test building song with SongFirstSlideMode = Songbook works
|
||||
"""
|
||||
# GIVEN: A Song and a Service Item
|
||||
mocked__get_id_of_item_to_generate.return_value = '00000000-0000-0000-0000-000000000000'
|
||||
settings.setValue('songs/first slide mode', first_slide_mode)
|
||||
mocked_get_verses.return_value = SONG_VERSES_TEST_LYRICS
|
||||
media_item.plugin = MagicMock()
|
||||
media_item.open_lyrics = OpenLyrics(media_item.plugin.manager)
|
||||
song = Song()
|
||||
song.title = 'My Song'
|
||||
song.alternate_title = ''
|
||||
song.copyright = 'My copyright'
|
||||
song.authors_songs = []
|
||||
song.songbook_entries = []
|
||||
song.alternate_title = ''
|
||||
song.lyrics = 'Teste'
|
||||
song.theme_name = 'Default'
|
||||
song.topics = []
|
||||
song.ccli_number = ''
|
||||
song.lyrics = '<fake xml>' # Mocked by mocked_get_verses
|
||||
song.verse_order = SONG_VERSES_TEST_VERSE_ORDER
|
||||
song.search_title = 'my song@'
|
||||
song.last_modified = '2023-02-20T00:00:00Z'
|
||||
song.media_files = []
|
||||
song.comments = ''
|
||||
book1 = MagicMock()
|
||||
book1.name = 'My songbook'
|
||||
book1.publisher = None
|
||||
book2 = MagicMock()
|
||||
book2.name = 'Thy songbook'
|
||||
book2.publisher = 'Publisher'
|
||||
song.songbook_entries = []
|
||||
song.add_songbook_entry(book1, '12')
|
||||
song.add_songbook_entry(book2, '502A')
|
||||
service_item = ServiceItem(None)
|
||||
media_item.plugin.manager.get_object.return_value = song
|
||||
|
||||
# WHEN: I generate the Footer with default settings
|
||||
media_item.generate_slide_data(service_item, item=song)
|
||||
|
||||
# THEN: The copyright symbol should not be in the footer
|
||||
if first_slide_mode == SongFirstSlideMode.Default:
|
||||
# No metadata is needed on default slide mode (at least for now)
|
||||
assert 'metadata' not in service_item.slides[0]
|
||||
else:
|
||||
assert service_item.slides[0]['metadata']['songs_first_slide_type'] == first_slide_mode
|
||||
if first_slide_mode == SongFirstSlideMode.Songbook:
|
||||
assert service_item.slides[0]['text'] == '\nMy songbook #12\n\nThy songbook #502A (Publisher)\n\n'
|
||||
if first_slide_mode == SongFirstSlideMode.Footer:
|
||||
assert service_item.slides[0]['text'] == service_item.footer_html
|
||||
# It needs to have empty footer as it's already shown on text
|
||||
assert service_item.slides[0]['footer_html'] == ''
|
||||
|
|
|
@ -25,6 +25,7 @@ import pytest
|
|||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
from openlp.core.common.enum import SongFirstSlideMode
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.plugins.songs.lib.songstab import SongsTab
|
||||
|
@ -89,7 +90,6 @@ def test_save_check_box_settings(form):
|
|||
form.on_tool_bar_active_check_box_changed(QtCore.Qt.Checked)
|
||||
form.on_update_on_edit_check_box_changed(QtCore.Qt.Unchecked)
|
||||
form.on_add_from_service_check_box_changed(QtCore.Qt.Checked)
|
||||
form.on_songbook_slide_check_box_changed(QtCore.Qt.Unchecked)
|
||||
form.on_disable_chords_import_check_box_changed(QtCore.Qt.Unchecked)
|
||||
form.on_auto_play_check_box_changed(QtCore.Qt.Checked)
|
||||
# WHEN: Save is invoked
|
||||
|
@ -99,7 +99,6 @@ def test_save_check_box_settings(form):
|
|||
assert form.settings.value('songs/display songbar') is True
|
||||
assert form.settings.value('songs/update service on edit') is False
|
||||
assert form.settings.value('songs/add song from service') is True
|
||||
assert form.settings.value('songs/add songbook slide') is False
|
||||
assert form.settings.value('songs/disable chords import') is False
|
||||
assert form.settings.value('songs/auto play audio') is True
|
||||
|
||||
|
@ -245,3 +244,17 @@ def test_save_tab_change(form):
|
|||
# THEN: the post process should be requested
|
||||
assert 1 == form.settings_form.register_post_process.call_count, \
|
||||
'Songs Post processing should have been requested'
|
||||
|
||||
|
||||
def test_save_first_slide_settings(form):
|
||||
"""
|
||||
Tests that "Add First Slide" setting is saved correctly.
|
||||
"""
|
||||
# GIVEN: "Add First Slide" has been changed
|
||||
form.on_first_slide_mode_combo_box_changed(2)
|
||||
|
||||
# WHEN: save() is invoked
|
||||
form.save()
|
||||
|
||||
# THEN: The correct values should be stored in the settings
|
||||
assert form.settings.value('songs/first slide mode') is SongFirstSlideMode.Footer.value
|
||||
|
|
Loading…
Reference in New Issue