forked from openlp/openlp
HEAD
This commit is contained in:
commit
563347c8b8
@ -250,7 +250,13 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
|||||||
# Remove two or more option slide breaks next to each other (causing infinite loop).
|
# Remove two or more option slide breaks next to each other (causing infinite loop).
|
||||||
while '\n[---]\n[---]\n' in text:
|
while '\n[---]\n[---]\n' in text:
|
||||||
text = text.replace('\n[---]\n[---]\n', '\n[---]\n')
|
text = text.replace('\n[---]\n[---]\n', '\n[---]\n')
|
||||||
while True:
|
while ' [---]' in text:
|
||||||
|
text = text.replace(' [---]', '[---]')
|
||||||
|
while '[---] ' in text:
|
||||||
|
text = text.replace('[---] ', '[---]')
|
||||||
|
count = 0
|
||||||
|
# only loop 5 times as there will never be more than 5 incorrect logical splits on a single slide.
|
||||||
|
while True and count < 5:
|
||||||
slides = text.split('\n[---]\n', 2)
|
slides = text.split('\n[---]\n', 2)
|
||||||
# If there are (at least) two occurrences of [---] we use the first two slides (and neglect the last
|
# If there are (at least) two occurrences of [---] we use the first two slides (and neglect the last
|
||||||
# for now).
|
# for now).
|
||||||
@ -296,6 +302,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
|
|||||||
lines = text.strip('\n').split('\n')
|
lines = text.strip('\n').split('\n')
|
||||||
pages.extend(self._paginate_slide(lines, line_end))
|
pages.extend(self._paginate_slide(lines, line_end))
|
||||||
break
|
break
|
||||||
|
count =+ 1
|
||||||
else:
|
else:
|
||||||
# Clean up line endings.
|
# Clean up line endings.
|
||||||
pages = self._paginate_slide(text.split('\n'), line_end)
|
pages = self._paginate_slide(text.split('\n'), line_end)
|
||||||
|
@ -95,6 +95,17 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
if self.currentId() == FirstTimePage.Plugins:
|
if self.currentId() == FirstTimePage.Plugins:
|
||||||
|
if self.has_run_wizard:
|
||||||
|
self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active())
|
||||||
|
self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active())
|
||||||
|
self.presentation_check_box.setChecked(self.plugin_manager.get_plugin_by_name(
|
||||||
|
'presentations').is_active())
|
||||||
|
self.image_check_box.setChecked(self.plugin_manager.get_plugin_by_name('images').is_active())
|
||||||
|
self.media_check_box.setChecked(self.plugin_manager.get_plugin_by_name('media').is_active())
|
||||||
|
self.remote_check_box.setChecked(self.plugin_manager.get_plugin_by_name('remotes').is_active())
|
||||||
|
self.custom_check_box.setChecked(self.plugin_manager.get_plugin_by_name('custom').is_active())
|
||||||
|
self.song_usage_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songusage').is_active())
|
||||||
|
self.alert_check_box.setChecked(self.plugin_manager.get_plugin_by_name('alerts').is_active())
|
||||||
if not self.web_access:
|
if not self.web_access:
|
||||||
return FirstTimePage.NoInternet
|
return FirstTimePage.NoInternet
|
||||||
else:
|
else:
|
||||||
|
@ -978,7 +978,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
|||||||
# FIXME: We are conflicting with the standard "General" section.
|
# FIXME: We are conflicting with the standard "General" section.
|
||||||
if 'eneral' in section_key:
|
if 'eneral' in section_key:
|
||||||
section_key = section_key.lower()
|
section_key = section_key.lower()
|
||||||
|
try:
|
||||||
key_value = settings.value(section_key)
|
key_value = settings.value(section_key)
|
||||||
|
except KeyError:
|
||||||
|
QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
|
||||||
|
translate('OpenLP.MainWindow', 'The key "%s" does not have a default value '
|
||||||
|
'so it will be skipped in this export.') % section_key,
|
||||||
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
|
||||||
|
key_value = None
|
||||||
if key_value is not None:
|
if key_value is not None:
|
||||||
export_settings.setValue(section_key, key_value)
|
export_settings.setValue(section_key, key_value)
|
||||||
export_settings.sync()
|
export_settings.sync()
|
||||||
|
@ -494,7 +494,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
|||||||
service.append({'openlp_core': core})
|
service.append({'openlp_core': core})
|
||||||
return service
|
return service
|
||||||
|
|
||||||
def save_file(self):
|
def save_file(self, field=None):
|
||||||
"""
|
"""
|
||||||
Save the current service file.
|
Save the current service file.
|
||||||
|
|
||||||
@ -1427,9 +1427,10 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
|
|||||||
self.drop_position = -1
|
self.drop_position = -1
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def make_preview(self):
|
def make_preview(self, field=None):
|
||||||
"""
|
"""
|
||||||
Send the current item to the Preview slide controller
|
Send the current item to the Preview slide controller
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
|
@ -46,7 +46,7 @@ class Ui_SettingsDialog(object):
|
|||||||
"""
|
"""
|
||||||
settings_dialog.setObjectName('settings_dialog')
|
settings_dialog.setObjectName('settings_dialog')
|
||||||
settings_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
|
settings_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
|
||||||
settings_dialog.resize(800, 500)
|
settings_dialog.resize(800, 700)
|
||||||
self.dialog_layout = QtGui.QGridLayout(settings_dialog)
|
self.dialog_layout = QtGui.QGridLayout(settings_dialog)
|
||||||
self.dialog_layout.setObjectName('dialog_layout')
|
self.dialog_layout.setObjectName('dialog_layout')
|
||||||
self.dialog_layout.setMargin(8)
|
self.dialog_layout.setMargin(8)
|
||||||
|
@ -683,7 +683,8 @@ class SlideController(DisplayController, RegistryProperties):
|
|||||||
self.play_slides_loop.setChecked(False)
|
self.play_slides_loop.setChecked(False)
|
||||||
self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
|
self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
|
||||||
if item.is_text():
|
if item.is_text():
|
||||||
if Settings().value(self.main_window.songs_settings_section + '/display songbar') and self.slide_list:
|
if (Settings().value(self.main_window.songs_settings_section + '/display songbar')
|
||||||
|
and not self.song_menu.menu().isEmpty()):
|
||||||
self.toolbar.set_widget_visible(['song_menu'], True)
|
self.toolbar.set_widget_visible(['song_menu'], True)
|
||||||
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
|
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
|
||||||
self.toolbar.set_widget_visible(LOOP_LIST)
|
self.toolbar.set_widget_visible(LOOP_LIST)
|
||||||
@ -691,7 +692,8 @@ class SlideController(DisplayController, RegistryProperties):
|
|||||||
self.mediabar.show()
|
self.mediabar.show()
|
||||||
self.previous_item.setVisible(not item.is_media())
|
self.previous_item.setVisible(not item.is_media())
|
||||||
self.next_item.setVisible(not item.is_media())
|
self.next_item.setVisible(not item.is_media())
|
||||||
self.set_blank_menu()
|
# The layout of the toolbar is size dependent, so make sure it fits
|
||||||
|
self.on_controller_size_changed(self.controller.width())
|
||||||
# Work-around for OS X, hide and then show the toolbar
|
# Work-around for OS X, hide and then show the toolbar
|
||||||
# See bug #791050
|
# See bug #791050
|
||||||
self.toolbar.show()
|
self.toolbar.show()
|
||||||
|
@ -37,7 +37,7 @@ from xml.etree.ElementTree import ElementTree, XML
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
|
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
|
||||||
check_directory_exists, UiStrings, translate
|
check_directory_exists, UiStrings, translate, is_win
|
||||||
from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, get_text_file_string, build_icon, \
|
from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, get_text_file_string, build_icon, \
|
||||||
check_item_selected, create_thumb, validate_thumb
|
check_item_selected, create_thumb, validate_thumb
|
||||||
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
||||||
@ -662,8 +662,12 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R
|
|||||||
out_file.close()
|
out_file.close()
|
||||||
if image_from and os.path.abspath(image_from) != os.path.abspath(image_to):
|
if image_from and os.path.abspath(image_from) != os.path.abspath(image_to):
|
||||||
try:
|
try:
|
||||||
|
# Windows is always unicode, so no need to encode filenames
|
||||||
|
if is_win():
|
||||||
|
shutil.copyfile(image_from, image_to)
|
||||||
|
else:
|
||||||
encoding = get_filesystem_encoding()
|
encoding = get_filesystem_encoding()
|
||||||
shutil.copyfile(str(image_from).encode(encoding), str(image_to).encode(encoding))
|
shutil.copyfile(image_from.encode(encoding), image_to.encode(encoding))
|
||||||
except IOError as xxx_todo_changeme:
|
except IOError as xxx_todo_changeme:
|
||||||
shutil.Error = xxx_todo_changeme
|
shutil.Error = xxx_todo_changeme
|
||||||
self.log_exception('Failed to save theme image')
|
self.log_exception('Failed to save theme image')
|
||||||
|
@ -330,7 +330,10 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
|||||||
if not book_ref_id:
|
if not book_ref_id:
|
||||||
book_ref_id = bible.get_book_ref_id_by_localised_name(book, language_selection)
|
book_ref_id = bible.get_book_ref_id_by_localised_name(book, language_selection)
|
||||||
elif not bible.get_book_by_book_ref_id(book_ref_id):
|
elif not bible.get_book_by_book_ref_id(book_ref_id):
|
||||||
book_ref_id = False
|
return False
|
||||||
|
# We have not found the book so do not continue
|
||||||
|
if not book_ref_id:
|
||||||
|
return False
|
||||||
ranges = match.group('ranges')
|
ranges = match.group('ranges')
|
||||||
range_list = get_reference_match('range_separator').split(ranges)
|
range_list = get_reference_match('range_separator').split(ranges)
|
||||||
ref_list = []
|
ref_list = []
|
||||||
|
@ -93,7 +93,7 @@ class WorshipAssistantImport(SongImport):
|
|||||||
details = chardet.detect(detect_content)
|
details = chardet.detect(detect_content)
|
||||||
detect_file.close()
|
detect_file.close()
|
||||||
songs_file = open(self.import_source, 'r', encoding=details['encoding'])
|
songs_file = open(self.import_source, 'r', encoding=details['encoding'])
|
||||||
songs_reader = csv.DictReader(songs_file)
|
songs_reader = csv.DictReader(songs_file, escapechar='\\')
|
||||||
try:
|
try:
|
||||||
records = list(songs_reader)
|
records = list(songs_reader)
|
||||||
except csv.Error as e:
|
except csv.Error as e:
|
||||||
@ -104,6 +104,8 @@ class WorshipAssistantImport(SongImport):
|
|||||||
num_records = len(records)
|
num_records = len(records)
|
||||||
log.info('%s records found in CSV file' % num_records)
|
log.info('%s records found in CSV file' % num_records)
|
||||||
self.import_wizard.progress_bar.setMaximum(num_records)
|
self.import_wizard.progress_bar.setMaximum(num_records)
|
||||||
|
# Create regex to strip html tags
|
||||||
|
re_html_strip = re.compile(r'<[^>]+>')
|
||||||
for index, record in enumerate(records, 1):
|
for index, record in enumerate(records, 1):
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
return
|
return
|
||||||
@ -119,13 +121,12 @@ class WorshipAssistantImport(SongImport):
|
|||||||
self.title = record['TITLE']
|
self.title = record['TITLE']
|
||||||
if record['AUTHOR'] != EMPTY_STR:
|
if record['AUTHOR'] != EMPTY_STR:
|
||||||
self.parse_author(record['AUTHOR'])
|
self.parse_author(record['AUTHOR'])
|
||||||
print(record['AUTHOR'])
|
|
||||||
if record['COPYRIGHT'] != EMPTY_STR:
|
if record['COPYRIGHT'] != EMPTY_STR:
|
||||||
self.add_copyright(record['COPYRIGHT'])
|
self.add_copyright(record['COPYRIGHT'])
|
||||||
if record['CCLINR'] != EMPTY_STR:
|
if record['CCLINR'] != EMPTY_STR:
|
||||||
self.ccli_number = record['CCLINR']
|
self.ccli_number = record['CCLINR']
|
||||||
if record['ROADMAP'] != EMPTY_STR:
|
if record['ROADMAP'] != EMPTY_STR:
|
||||||
verse_order_list = record['ROADMAP'].split(',')
|
verse_order_list = [x.strip() for x in record['ROADMAP'].split(',')]
|
||||||
lyrics = record['LYRICS2']
|
lyrics = record['LYRICS2']
|
||||||
except UnicodeDecodeError as e:
|
except UnicodeDecodeError as e:
|
||||||
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index),
|
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index),
|
||||||
@ -136,8 +137,15 @@ class WorshipAssistantImport(SongImport):
|
|||||||
'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e)
|
'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e)
|
||||||
return
|
return
|
||||||
verse = ''
|
verse = ''
|
||||||
|
used_verses = []
|
||||||
for line in lyrics.splitlines():
|
for line in lyrics.splitlines():
|
||||||
if line.startswith('['): # verse marker
|
if line.startswith('['): # verse marker
|
||||||
|
# Add previous verse
|
||||||
|
if verse:
|
||||||
|
# remove trailing linebreak, part of the WA syntax
|
||||||
|
self.add_verse(verse[:-1], verse_id)
|
||||||
|
used_verses.append(verse_id)
|
||||||
|
verse = ''
|
||||||
# drop the square brackets
|
# drop the square brackets
|
||||||
right_bracket = line.find(']')
|
right_bracket = line.find(']')
|
||||||
content = line[1:right_bracket].lower()
|
content = line[1:right_bracket].lower()
|
||||||
@ -152,19 +160,31 @@ class WorshipAssistantImport(SongImport):
|
|||||||
verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
|
verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
|
||||||
verse_tag = VerseType.tags[verse_index]
|
verse_tag = VerseType.tags[verse_index]
|
||||||
# Update verse order when the verse name has changed
|
# Update verse order when the verse name has changed
|
||||||
if content != verse_tag + verse_num:
|
verse_id = verse_tag + verse_num
|
||||||
|
# Make sure we've not choosen an id already used
|
||||||
|
while verse_id in verse_order_list and content in verse_order_list:
|
||||||
|
verse_num = str(int(verse_num) + 1)
|
||||||
|
verse_id = verse_tag + verse_num
|
||||||
|
if content != verse_id:
|
||||||
for i in range(len(verse_order_list)):
|
for i in range(len(verse_order_list)):
|
||||||
if verse_order_list[i].lower() == content.lower():
|
if verse_order_list[i].lower() == content.lower():
|
||||||
verse_order_list[i] = verse_tag + verse_num
|
verse_order_list[i] = verse_id
|
||||||
elif line and not line.isspace():
|
else:
|
||||||
verse += line + '\n'
|
# add line text to verse. Strip out html
|
||||||
elif verse:
|
verse += re_html_strip.sub('', line) + '\n'
|
||||||
self.add_verse(verse, verse_tag+verse_num)
|
|
||||||
verse = ''
|
|
||||||
if verse:
|
if verse:
|
||||||
self.add_verse(verse, verse_tag+verse_num)
|
# remove trailing linebreak, part of the WA syntax
|
||||||
|
if verse.endswith('\n\n'):
|
||||||
|
verse = verse[:-1]
|
||||||
|
self.add_verse(verse, verse_id)
|
||||||
|
used_verses.append(verse_id)
|
||||||
if verse_order_list:
|
if verse_order_list:
|
||||||
self.verse_order_list = verse_order_list
|
# Use the verse order in the import, but remove entries that doesn't have a text
|
||||||
|
cleaned_verse_order_list = []
|
||||||
|
for verse in verse_order_list:
|
||||||
|
if verse in used_verses:
|
||||||
|
cleaned_verse_order_list.append(verse)
|
||||||
|
self.verse_order_list = cleaned_verse_order_list
|
||||||
if not self.finish():
|
if not self.finish():
|
||||||
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index
|
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index
|
||||||
+ (': "' + self.title + '"' if self.title else ''))
|
+ (': "' + self.title + '"' if self.title else ''))
|
||||||
|
@ -339,6 +339,9 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.remote_song = -1
|
self.remote_song = -1
|
||||||
self.remote_triggered = None
|
self.remote_triggered = None
|
||||||
if item:
|
if item:
|
||||||
|
if preview:
|
||||||
|
# A song can only be edited if it comes from plugin, so we set it again for the new item.
|
||||||
|
item.from_plugin = True
|
||||||
return item
|
return item
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -75,9 +75,14 @@ class OpenLyricsExport(RegistryProperties):
|
|||||||
filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors]))
|
filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors]))
|
||||||
filename = clean_filename(filename)
|
filename = clean_filename(filename)
|
||||||
# Ensure the filename isn't too long for some filesystems
|
# Ensure the filename isn't too long for some filesystems
|
||||||
filename = '%s.xml' % filename[0:250 - len(self.save_path)]
|
filename_with_ext = '%s.xml' % filename[0:250 - len(self.save_path)]
|
||||||
|
# Make sure we're not overwriting an existing file
|
||||||
|
conflicts = 0
|
||||||
|
while os.path.exists(os.path.join(self.save_path, filename_with_ext)):
|
||||||
|
conflicts += 1
|
||||||
|
filename_with_ext = '%s-%d.xml' % (filename[0:247 - len(self.save_path)], conflicts)
|
||||||
# Pass a file object, because lxml does not cope with some special
|
# Pass a file object, because lxml does not cope with some special
|
||||||
# characters in the path (see lp:757673 and lp:744337).
|
# characters in the path (see lp:757673 and lp:744337).
|
||||||
tree.write(open(os.path.join(self.save_path, filename), 'wb'), encoding='utf-8', xml_declaration=True,
|
tree.write(open(os.path.join(self.save_path, filename_with_ext), 'wb'), encoding='utf-8',
|
||||||
pretty_print=True)
|
xml_declaration=True, pretty_print=True)
|
||||||
return True
|
return True
|
||||||
|
@ -99,7 +99,7 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog, RegistryPrope
|
|||||||
report_file_name = os.path.join(path, file_name)
|
report_file_name = os.path.join(path, file_name)
|
||||||
file_handle = None
|
file_handle = None
|
||||||
try:
|
try:
|
||||||
file_handle = open(report_file_name, 'w')
|
file_handle = open(report_file_name, 'wb')
|
||||||
for instance in usage:
|
for instance in usage:
|
||||||
record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
|
record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
|
||||||
'\"%s\",\"%s\"\n' % \
|
'\"%s\",\"%s\"\n' % \
|
||||||
|
@ -115,3 +115,15 @@ class TestSettings(TestCase, TestMixin):
|
|||||||
|
|
||||||
# THEN the new value is returned when re-read
|
# THEN the new value is returned when re-read
|
||||||
self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned')
|
self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned')
|
||||||
|
|
||||||
|
def settings_nonexisting_test(self):
|
||||||
|
"""
|
||||||
|
Test the Settings on query for non-existing value
|
||||||
|
"""
|
||||||
|
# GIVEN: A new Settings setup
|
||||||
|
with self.assertRaises(KeyError) as cm:
|
||||||
|
# WHEN reading a setting that doesn't exists
|
||||||
|
does_not_exist_value = Settings().value('core/does not exists')
|
||||||
|
|
||||||
|
# THEN: An exception with the non-existing key should be thrown
|
||||||
|
self.assertEqual(str(cm.exception), "'core/does not exists'", 'We should get an exception')
|
||||||
|
@ -34,7 +34,7 @@ from unittest import TestCase
|
|||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
from openlp.core.common import Registry
|
from openlp.core.common import Registry
|
||||||
from openlp.core.lib import Renderer, ScreenList
|
from openlp.core.lib import Renderer, ScreenList, ServiceItem
|
||||||
|
|
||||||
from tests.interfaces import MagicMock
|
from tests.interfaces import MagicMock
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ class TestRenderer(TestCase):
|
|||||||
expected_tuple = ('{st}{r}Text text text{/r}{/st}', '{st}{r}',
|
expected_tuple = ('{st}{r}Text text text{/r}{/st}', '{st}{r}',
|
||||||
'<strong><span style="-webkit-text-fill-color:red">')
|
'<strong><span style="-webkit-text-fill-color:red">')
|
||||||
|
|
||||||
# WHEN:
|
# WHEN: The renderer converts the start tags
|
||||||
result = renderer._get_start_tags(given_raw_text)
|
result = renderer._get_start_tags(given_raw_text)
|
||||||
|
|
||||||
# THEN: Check if the correct tuple is returned.
|
# THEN: Check if the correct tuple is returned.
|
||||||
@ -104,8 +104,59 @@ class TestRenderer(TestCase):
|
|||||||
given_line = 'beginning asdf \n end asdf'
|
given_line = 'beginning asdf \n end asdf'
|
||||||
expected_words = ['beginning', 'asdf', 'end', 'asdf']
|
expected_words = ['beginning', 'asdf', 'end', 'asdf']
|
||||||
|
|
||||||
# WHEN: Split the line
|
# WHEN: Split the line based on word split rules
|
||||||
result_words = renderer._words_split(given_line)
|
result_words = renderer._words_split(given_line)
|
||||||
|
|
||||||
# THEN: The word lists should be the same.
|
# THEN: The word lists should be the same.
|
||||||
self.assertListEqual(result_words, expected_words)
|
self.assertListEqual(result_words, expected_words)
|
||||||
|
|
||||||
|
def format_slide_logical_split_test(self):
|
||||||
|
"""
|
||||||
|
Test that a line with text and a logic break does not break the renderer just returns the input
|
||||||
|
"""
|
||||||
|
# GIVEN: A line of with a space text and the logical split
|
||||||
|
renderer = Renderer()
|
||||||
|
renderer.empty_height = 25
|
||||||
|
given_line = 'a\n[---]\nb'
|
||||||
|
expected_words = ['a<br>[---]<br>b']
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: Split the line based on word split rules
|
||||||
|
result_words = renderer.format_slide(given_line, service_item)
|
||||||
|
|
||||||
|
# THEN: The word lists should be the same.
|
||||||
|
self.assertListEqual(result_words, expected_words)
|
||||||
|
|
||||||
|
def format_slide_blank_before_split_test(self):
|
||||||
|
"""
|
||||||
|
Test that a line with blanks before the logical split at handled
|
||||||
|
"""
|
||||||
|
# GIVEN: A line of with a space before the logical split
|
||||||
|
renderer = Renderer()
|
||||||
|
renderer.empty_height = 25
|
||||||
|
given_line = '\n [---]\n'
|
||||||
|
expected_words = ['<br> [---]']
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: Split the line based on word split rules
|
||||||
|
result_words = renderer.format_slide(given_line, service_item)
|
||||||
|
|
||||||
|
# THEN: The blanks have been removed.
|
||||||
|
self.assertListEqual(result_words, expected_words)
|
||||||
|
|
||||||
|
def format_slide_blank_after_split_test(self):
|
||||||
|
"""
|
||||||
|
Test that a line with blanks before the logical split at handled
|
||||||
|
"""
|
||||||
|
# GIVEN: A line of with a space after the logical split
|
||||||
|
renderer = Renderer()
|
||||||
|
renderer.empty_height = 25
|
||||||
|
given_line = '\n[---] \n'
|
||||||
|
expected_words = ['<br>[---] ']
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: Split the line based on word split rules
|
||||||
|
result_words = renderer.format_slide(given_line, service_item)
|
||||||
|
|
||||||
|
# THEN: The blanks have been removed.
|
||||||
|
self.assertListEqual(result_words, expected_words)
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
# -*- 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 OpenLyrics song importer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from unittest import TestCase
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
|
||||||
|
from tests.functional import MagicMock, patch
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
|
||||||
|
from openlp.core.common import Registry
|
||||||
|
|
||||||
|
|
||||||
|
class TestOpenLyricsExport(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
Test the functions in the :mod:`openlyricsexport` module.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the registry
|
||||||
|
"""
|
||||||
|
Registry.create()
|
||||||
|
self.temp_folder = mkdtemp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Cleanup
|
||||||
|
"""
|
||||||
|
shutil.rmtree(self.temp_folder)
|
||||||
|
|
||||||
|
def export_same_filename_test(self):
|
||||||
|
"""
|
||||||
|
Test that files is not overwritten if songs has same title and author
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked song_to_xml, 2 mocked songs, a mocked application and an OpenLyricsExport instance
|
||||||
|
with patch('openlp.plugins.songs.lib.openlyricsexport.OpenLyrics.song_to_xml') as mocked_song_to_xml:
|
||||||
|
mocked_song_to_xml.return_value = '<?xml version="1.0" encoding="UTF-8"?>\n<empty/>'
|
||||||
|
author = MagicMock()
|
||||||
|
author.display_name = 'Test Author'
|
||||||
|
song = MagicMock()
|
||||||
|
song.authors = [author]
|
||||||
|
song.title = 'Test Title'
|
||||||
|
parent = MagicMock()
|
||||||
|
parent.stop_export_flag = False
|
||||||
|
mocked_application_object = MagicMock()
|
||||||
|
Registry().register('application', mocked_application_object)
|
||||||
|
ol_export = OpenLyricsExport(parent, [song, song], self.temp_folder)
|
||||||
|
|
||||||
|
# WHEN: Doing the export
|
||||||
|
ol_export.do_export()
|
||||||
|
|
||||||
|
# THEN: The exporter should have created 2 files
|
||||||
|
self.assertTrue(os.path.exists(os.path.join(self.temp_folder,
|
||||||
|
'%s (%s).xml' % (song.title, author.display_name))))
|
||||||
|
self.assertTrue(os.path.exists(os.path.join(self.temp_folder,
|
||||||
|
'%s (%s)-1.xml' % (song.title, author.display_name))))
|
@ -54,3 +54,5 @@ class TestWorshipAssistantFileImport(SongImportTestHelper):
|
|||||||
self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json')))
|
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.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')))
|
self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
|
||||||
|
self.file_import(os.path.join(TEST_PATH, 'would_you_be_free2.csv'),
|
||||||
|
self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
|
||||||
|
@ -105,3 +105,13 @@ class TestBibleManager(TestCase, TestMixin):
|
|||||||
# THEN a verse array should be returned
|
# THEN a verse array should be returned
|
||||||
self.assertEqual([(54, 1, 1, -1), (54, 2, 1, 1)], results,
|
self.assertEqual([(54, 1, 1, -1), (54, 2, 1, 1)], results,
|
||||||
"The bible verses should match the expected results")
|
"The bible verses should match the expected results")
|
||||||
|
|
||||||
|
def parse_reference_four_test(self):
|
||||||
|
"""
|
||||||
|
Test the parse_reference method with non existence book
|
||||||
|
"""
|
||||||
|
# GIVEN given a bible in the bible manager
|
||||||
|
# WHEN asking to parse the bible reference
|
||||||
|
results = parse_reference('Raoul 1', self.manager.db_cache['tests'], MagicMock())
|
||||||
|
# THEN a verse array should be returned
|
||||||
|
self.assertEqual(False, results, "The bible Search should return False")
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"copyright": "Public Domain",
|
"copyright": "Public Domain",
|
||||||
"verses": [
|
"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",
|
"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"
|
"v1"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
31
tests/resources/worshipassistantsongs/would_you_be_free2.csv
Normal file
31
tests/resources/worshipassistantsongs/would_you_be_free2.csv
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
[x]",""
|
|
Loading…
Reference in New Issue
Block a user