forked from openlp/openlp
Head
This commit is contained in:
commit
8720ed1b72
@ -39,11 +39,12 @@ import sys
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
from traceback import format_exception
|
||||
|
||||
import shutil
|
||||
import time
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.common import Registry, OpenLPMixin, AppLocation, Settings, UiStrings, check_directory_exists, \
|
||||
is_macosx, is_win
|
||||
is_macosx, is_win, translate
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.resources import qInitResources
|
||||
from openlp.core.ui.mainwindow import MainWindow
|
||||
@ -117,7 +118,9 @@ class OpenLP(OpenLPMixin, QtGui.QApplication):
|
||||
# First time checks in settings
|
||||
has_run_wizard = Settings().value('core/has run wizard')
|
||||
if not has_run_wizard:
|
||||
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
|
||||
ftw = FirstTimeForm()
|
||||
ftw.initialize(screens)
|
||||
if ftw.exec_() == QtGui.QDialog.Accepted:
|
||||
Settings().setValue('core/has run wizard', True)
|
||||
# Correct stylesheet bugs
|
||||
application_stylesheet = ''
|
||||
@ -136,6 +139,8 @@ class OpenLP(OpenLPMixin, QtGui.QApplication):
|
||||
self.splash.show()
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
# Check if OpenLP has been upgrade and if a backup of data should be created
|
||||
self.backup_on_upgrade(has_run_wizard)
|
||||
# start the main app window
|
||||
self.main_window = MainWindow()
|
||||
Registry().execute('bootstrap_initialise')
|
||||
@ -193,6 +198,40 @@ class OpenLP(OpenLPMixin, QtGui.QApplication):
|
||||
self.set_normal_cursor()
|
||||
self.exception_form.exec_()
|
||||
|
||||
def backup_on_upgrade(self, has_run_wizard):
|
||||
"""
|
||||
Check if OpenLP has been upgraded, and ask if a backup of data should be made
|
||||
|
||||
:param has_run_wizard: OpenLP has been run before
|
||||
"""
|
||||
data_version = Settings().value('core/application version')
|
||||
openlp_version = get_application_version()['version']
|
||||
# New installation, no need to create backup
|
||||
if not has_run_wizard:
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
# If data_version is different from the current version ask if we should backup the data folder
|
||||
elif data_version != openlp_version:
|
||||
if QtGui.QMessageBox.question(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'OpenLP has been upgraded, '
|
||||
'do you want to create a backup of OpenLPs data folder?'),
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
|
||||
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
|
||||
# Create copy of data folder
|
||||
data_folder_path = AppLocation.get_data_path()
|
||||
timestamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
data_folder_backup_path = data_folder_path + '-' + timestamp
|
||||
try:
|
||||
shutil.copytree(data_folder_path, data_folder_backup_path)
|
||||
except OSError:
|
||||
QtGui.QMessageBox.warning(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'Backup of the data folder failed!'))
|
||||
return
|
||||
QtGui.QMessageBox.information(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'A backup of the data folder has been created at %s')
|
||||
% data_folder_backup_path)
|
||||
# Update the version in the settings
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
|
||||
def process_events(self):
|
||||
"""
|
||||
Wrapper to make ProcessEvents visible and named correctly
|
||||
|
@ -137,6 +137,7 @@ class Settings(QtCore.QSettings):
|
||||
# circular dependency.
|
||||
'core/display on monitor': True,
|
||||
'core/override position': False,
|
||||
'core/application version': '0.0',
|
||||
'images/background color': '#000000',
|
||||
'media/players': 'webkit',
|
||||
'media/override player': QtCore.Qt.Unchecked,
|
||||
|
@ -44,7 +44,7 @@ from PyQt4 import QtCore, QtGui
|
||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, translate
|
||||
from openlp.core.lib import PluginStatus, build_icon
|
||||
from openlp.core.utils import get_web_page
|
||||
from .firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
|
||||
from .firsttimewizard import UiFirstTimeWizard, FirstTimePage
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -75,18 +75,58 @@ class ThemeScreenshotThread(QtCore.QThread):
|
||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
|
||||
|
||||
|
||||
class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
||||
"""
|
||||
This is the Theme Import Wizard, which allows easy creation and editing of OpenLP themes.
|
||||
"""
|
||||
log.info('ThemeWizardForm loaded')
|
||||
|
||||
def __init__(self, screens, parent=None):
|
||||
def __init__(self, parent=None):
|
||||
"""
|
||||
Create and set up the first time wizard.
|
||||
"""
|
||||
super(FirstTimeForm, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setup_ui(self)
|
||||
|
||||
def nextId(self):
|
||||
"""
|
||||
Determine the next page in the Wizard to go to.
|
||||
"""
|
||||
self.application.process_events()
|
||||
if self.currentId() == FirstTimePage.Plugins:
|
||||
if not self.web_access:
|
||||
return FirstTimePage.NoInternet
|
||||
else:
|
||||
return FirstTimePage.Songs
|
||||
elif self.currentId() == FirstTimePage.Progress:
|
||||
return -1
|
||||
elif self.currentId() == FirstTimePage.NoInternet:
|
||||
return FirstTimePage.Progress
|
||||
elif self.currentId() == FirstTimePage.Themes:
|
||||
self.application.set_busy_cursor()
|
||||
while not self.theme_screenshot_thread.isFinished():
|
||||
time.sleep(0.1)
|
||||
self.application.process_events()
|
||||
# Build the screenshot icons, as this can not be done in the thread.
|
||||
self._build_theme_screenshots()
|
||||
self.application.set_normal_cursor()
|
||||
return FirstTimePage.Defaults
|
||||
else:
|
||||
return self.currentId() + 1
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
Run the wizard.
|
||||
"""
|
||||
self.set_defaults()
|
||||
return QtGui.QWizard.exec_(self)
|
||||
|
||||
def initialize(self, screens):
|
||||
"""
|
||||
Set up the First Time Wizard
|
||||
|
||||
:param screens: The screens detected by OpenLP
|
||||
"""
|
||||
self.screens = screens
|
||||
# check to see if we have web access
|
||||
self.web = 'http://openlp.org/files/frw/'
|
||||
@ -110,13 +150,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
self.currentIdChanged.connect(self.on_current_id_changed)
|
||||
Registry().register_function('config_screen_changed', self.update_screen_list_combo)
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
Run the wizard.
|
||||
"""
|
||||
self.set_defaults()
|
||||
return QtGui.QWizard.exec_(self)
|
||||
|
||||
def set_defaults(self):
|
||||
"""
|
||||
Set up display at start of theme edit.
|
||||
@ -157,31 +190,14 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
self.theme_screenshot_thread.start()
|
||||
self.application.set_normal_cursor()
|
||||
|
||||
def nextId(self):
|
||||
def update_screen_list_combo(self):
|
||||
"""
|
||||
Determine the next page in the Wizard to go to.
|
||||
The user changed screen resolution or enabled/disabled more screens, so
|
||||
we need to update the combo box.
|
||||
"""
|
||||
self.application.process_events()
|
||||
if self.currentId() == FirstTimePage.Plugins:
|
||||
if not self.web_access:
|
||||
return FirstTimePage.NoInternet
|
||||
else:
|
||||
return FirstTimePage.Songs
|
||||
elif self.currentId() == FirstTimePage.Progress:
|
||||
return -1
|
||||
elif self.currentId() == FirstTimePage.NoInternet:
|
||||
return FirstTimePage.Progress
|
||||
elif self.currentId() == FirstTimePage.Themes:
|
||||
self.application.set_busy_cursor()
|
||||
while not self.theme_screenshot_thread.isFinished():
|
||||
time.sleep(0.1)
|
||||
self.application.process_events()
|
||||
# Build the screenshot icons, as this can not be done in the thread.
|
||||
self._build_theme_screenshots()
|
||||
self.application.set_normal_cursor()
|
||||
return FirstTimePage.Defaults
|
||||
else:
|
||||
return self.currentId() + 1
|
||||
self.display_combo_box.clear()
|
||||
self.display_combo_box.addItems(self.screens.get_screen_list())
|
||||
self.display_combo_box.setCurrentIndex(self.display_combo_box.count() - 1)
|
||||
|
||||
def on_current_id_changed(self, page_id):
|
||||
"""
|
||||
@ -196,7 +212,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
if self.has_run_wizard:
|
||||
self.no_internet_label.setText(self.no_internet_text)
|
||||
else:
|
||||
self.no_internet_label.setText(self.no_internet_text + self.cancelWizardText)
|
||||
self.no_internet_label.setText(self.no_internet_text + self.cancel_wizard_text)
|
||||
elif page_id == FirstTimePage.Defaults:
|
||||
self.theme_combo_box.clear()
|
||||
for index in range(self.themes_list_widget.count()):
|
||||
@ -230,15 +246,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard, RegistryProperties):
|
||||
self._post_wizard()
|
||||
self.application.set_normal_cursor()
|
||||
|
||||
def update_screen_list_combo(self):
|
||||
"""
|
||||
The user changed screen resolution or enabled/disabled more screens, so
|
||||
we need to update the combo box.
|
||||
"""
|
||||
self.display_combo_box.clear()
|
||||
self.display_combo_box.addItems(self.screens.get_screen_list())
|
||||
self.display_combo_box.setCurrentIndex(self.display_combo_box.count() - 1)
|
||||
|
||||
def on_cancel_button_clicked(self):
|
||||
"""
|
||||
Process the triggering of the cancel button.
|
||||
|
@ -50,13 +50,15 @@ class FirstTimePage(object):
|
||||
Progress = 7
|
||||
|
||||
|
||||
class Ui_FirstTimeWizard(object):
|
||||
class UiFirstTimeWizard(object):
|
||||
"""
|
||||
The UI widgets for the first time wizard.
|
||||
"""
|
||||
def setupUi(self, first_time_wizard):
|
||||
def setup_ui(self, first_time_wizard):
|
||||
"""
|
||||
Set up the UI.
|
||||
|
||||
:param first_time_wizard: The wizard form
|
||||
"""
|
||||
first_time_wizard.setObjectName('first_time_wizard')
|
||||
first_time_wizard.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
|
||||
@ -68,6 +70,8 @@ class Ui_FirstTimeWizard(object):
|
||||
first_time_wizard.setPixmap(QtGui.QWizard.BackgroundPixmap,
|
||||
QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
|
||||
first_time_wizard.resize(634, 386)
|
||||
else:
|
||||
first_time_wizard.setWizardStyle(QtGui.QWizard.ModernStyle)
|
||||
self.finish_button = self.button(QtGui.QWizard.FinishButton)
|
||||
self.no_internet_finish_button = self.button(QtGui.QWizard.CustomButton1)
|
||||
self.cancel_button = self.button(QtGui.QWizard.CancelButton)
|
||||
@ -202,19 +206,21 @@ class Ui_FirstTimeWizard(object):
|
||||
self.progress_bar.setObjectName('progress_bar')
|
||||
self.progress_layout.addWidget(self.progress_bar)
|
||||
first_time_wizard.setPage(FirstTimePage.Progress, self.progress_page)
|
||||
self.retranslateUi(first_time_wizard)
|
||||
self.retranslate_ui(first_time_wizard)
|
||||
|
||||
def retranslateUi(self, first_time_wizard):
|
||||
def retranslate_ui(self, first_time_wizard):
|
||||
"""
|
||||
Translate the UI on the fly
|
||||
|
||||
:param first_time_wizard: The wizard form
|
||||
"""
|
||||
first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
|
||||
self.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' %
|
||||
first_time_wizard.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' %
|
||||
translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard'))
|
||||
self.information_label.setText(
|
||||
first_time_wizard.information_label.setText(
|
||||
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
|
||||
'Click the %s button below to start.') %
|
||||
self.buttonText(QtGui.QWizard.NextButton))
|
||||
first_time_wizard.buttonText(QtGui.QWizard.NextButton))
|
||||
self.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Activate required Plugins'))
|
||||
self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select the Plugins you wish to use. '))
|
||||
self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
|
||||
@ -236,9 +242,10 @@ class Ui_FirstTimeWizard(object):
|
||||
'no sample data.\n\nTo re-run the First Time Wizard and import this sample '
|
||||
'data at a later time, check your Internet connection and re-run this '
|
||||
'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.')
|
||||
self.cancelWizardText = translate('OpenLP.FirstTimeWizard',
|
||||
self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard',
|
||||
'\n\nTo cancel the First Time Wizard completely (and not start OpenLP), '
|
||||
'click the %s button now.') % self.buttonText(QtGui.QWizard.CancelButton)
|
||||
'click the %s button now.') % \
|
||||
first_time_wizard.buttonText(QtGui.QWizard.CancelButton)
|
||||
self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
|
||||
self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
|
||||
self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles'))
|
||||
|
@ -38,17 +38,30 @@ from openlp.core.lib import ImageSource, ServiceItem
|
||||
|
||||
|
||||
class ListPreviewWidget(QtGui.QTableWidget, RegistryProperties):
|
||||
"""
|
||||
A special type of QTableWidget which lists the slides in the slide controller
|
||||
|
||||
:param parent:
|
||||
:param screen_ratio:
|
||||
"""
|
||||
|
||||
def __init__(self, parent, screen_ratio):
|
||||
"""
|
||||
Initializes the widget to default state.
|
||||
An empty ServiceItem is used per default.
|
||||
One needs to call replace_service_manager_item() to make this widget display something.
|
||||
|
||||
An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this
|
||||
widget display something.
|
||||
"""
|
||||
super(QtGui.QTableWidget, self).__init__(parent)
|
||||
# Set up the widget.
|
||||
self._setup(screen_ratio)
|
||||
|
||||
def _setup(self, screen_ratio):
|
||||
"""
|
||||
Set up the widget
|
||||
"""
|
||||
self.setColumnCount(1)
|
||||
self.horizontalHeader().setVisible(False)
|
||||
self.setColumnWidth(0, parent.width())
|
||||
self.setColumnWidth(0, self.parent().width())
|
||||
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
||||
self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
|
||||
@ -58,7 +71,7 @@ class ListPreviewWidget(QtGui.QTableWidget, RegistryProperties):
|
||||
self.service_item = ServiceItem()
|
||||
self.screen_ratio = screen_ratio
|
||||
|
||||
def resizeEvent(self, QResizeEvent):
|
||||
def resizeEvent(self, event):
|
||||
"""
|
||||
Overloaded method from QTableWidget. Will recalculate the layout.
|
||||
"""
|
||||
@ -82,16 +95,20 @@ class ListPreviewWidget(QtGui.QTableWidget, RegistryProperties):
|
||||
|
||||
def screen_size_changed(self, screen_ratio):
|
||||
"""
|
||||
To be called whenever the live screen size changes.
|
||||
Because this makes a layout recalculation necessary.
|
||||
This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
|
||||
|
||||
:param screen_ratio: The new screen ratio
|
||||
"""
|
||||
self.screen_ratio = screen_ratio
|
||||
self.__recalculate_layout()
|
||||
|
||||
def replace_service_item(self, service_item, width, slide_number):
|
||||
"""
|
||||
Replaces the current preview items with the ones in service_item.
|
||||
Displays the given slide.
|
||||
Replace the current preview items with the ones in service_item and display the given slide
|
||||
|
||||
:param service_item: The service item to insert
|
||||
:param width: The width of the column
|
||||
:param slide_number: The slide number to pre-select
|
||||
"""
|
||||
self.service_item = service_item
|
||||
self.setRowCount(0)
|
||||
|
@ -656,8 +656,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
|
||||
QtGui.QMessageBox.No)
|
||||
if answer == QtGui.QMessageBox.No:
|
||||
return
|
||||
screens = ScreenList()
|
||||
first_run_wizard = FirstTimeForm(screens, self)
|
||||
first_run_wizard = FirstTimeForm(self)
|
||||
first_run_wizard.initialize(ScreenList())
|
||||
first_run_wizard.exec_()
|
||||
if first_run_wizard.was_download_cancelled:
|
||||
return
|
||||
|
@ -62,7 +62,6 @@ class Ui_SettingsDialog(object):
|
||||
self.button_box = create_button_box(settings_dialog, 'button_box', ['cancel', 'ok'])
|
||||
self.dialog_layout.addWidget(self.button_box, 1, 1, 1, 1)
|
||||
self.retranslateUi(settings_dialog)
|
||||
self.setting_list_widget.currentRowChanged.connect(self.tab_changed)
|
||||
|
||||
def retranslateUi(self, settings_dialog):
|
||||
"""
|
||||
|
@ -31,10 +31,10 @@ The :mod:`settingsform` provides a user interface for the OpenLP settings
|
||||
"""
|
||||
import logging
|
||||
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.common import Registry, RegistryProperties
|
||||
from openlp.core.lib import PluginStatus, build_icon
|
||||
from openlp.core.lib import build_icon
|
||||
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
|
||||
from openlp.core.ui.media import PlayerTab
|
||||
from .settingsdialog import Ui_SettingsDialog
|
||||
@ -55,6 +55,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
|
||||
super(SettingsForm, self).__init__(parent)
|
||||
self.processes = []
|
||||
self.setupUi(self)
|
||||
self.setting_list_widget.currentRowChanged.connect(self.list_item_changed)
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
@ -65,33 +66,30 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
|
||||
while self.stacked_layout.count():
|
||||
# take at 0 and the rest shuffle up.
|
||||
self.stacked_layout.takeAt(0)
|
||||
self.insert_tab(self.general_tab, 0, PluginStatus.Active)
|
||||
self.insert_tab(self.themes_tab, 1, PluginStatus.Active)
|
||||
self.insert_tab(self.advanced_tab, 2, PluginStatus.Active)
|
||||
self.insert_tab(self.player_tab, 3, PluginStatus.Active)
|
||||
count = 4
|
||||
self.insert_tab(self.general_tab)
|
||||
self.insert_tab(self.themes_tab)
|
||||
self.insert_tab(self.advanced_tab)
|
||||
self.insert_tab(self.player_tab)
|
||||
for plugin in self.plugin_manager.plugins:
|
||||
if plugin.settings_tab:
|
||||
self.insert_tab(plugin.settings_tab, count, plugin.status)
|
||||
count += 1
|
||||
self.insert_tab(plugin.settings_tab, plugin.is_active())
|
||||
self.setting_list_widget.setCurrentRow(0)
|
||||
return QtGui.QDialog.exec_(self)
|
||||
|
||||
def insert_tab(self, tab, location, is_active):
|
||||
def insert_tab(self, tab_widget, is_visible=True):
|
||||
"""
|
||||
Add a tab to the form at a specific location
|
||||
|
||||
:param tab_widget: The widget to add
|
||||
:param is_visible: If this tab should be visible
|
||||
"""
|
||||
log.debug('Inserting %s tab' % tab.tab_title)
|
||||
log.debug('Inserting %s tab' % tab_widget.tab_title)
|
||||
# add the tab to get it to display in the correct part of the screen
|
||||
pos = self.stacked_layout.addWidget(tab)
|
||||
if is_active:
|
||||
item_name = QtGui.QListWidgetItem(tab.tab_title_visible)
|
||||
icon = build_icon(tab.icon_path)
|
||||
item_name.setIcon(icon)
|
||||
self.setting_list_widget.insertItem(location, item_name)
|
||||
else:
|
||||
# then remove tab to stop the UI displaying it even if it is not required.
|
||||
self.stacked_layout.takeAt(pos)
|
||||
self.stacked_layout.addWidget(tab_widget)
|
||||
if is_visible:
|
||||
list_item = QtGui.QListWidgetItem(build_icon(tab_widget.icon_path), tab_widget.tab_title_visible)
|
||||
list_item.setData(QtCore.Qt.UserRole, tab_widget.tab_title)
|
||||
self.setting_list_widget.addItem(list_item)
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
@ -137,10 +135,21 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
|
||||
if plugin.settings_tab:
|
||||
plugin.settings_tab.post_set_up()
|
||||
|
||||
def tab_changed(self, tab_index):
|
||||
def list_item_changed(self, item_index):
|
||||
"""
|
||||
A different settings tab is selected
|
||||
|
||||
:param item_index: The index of the item that was selected
|
||||
"""
|
||||
# Get the item we clicked on
|
||||
list_item = self.setting_list_widget.item(item_index)
|
||||
# Loop through the list of tabs in the stacked layout
|
||||
for tab_index in range(self.stacked_layout.count()):
|
||||
# Get the widget
|
||||
tab_widget = self.stacked_layout.itemAt(tab_index).widget()
|
||||
# Check that the title of the tab (i.e. plugin name) is the same as the data in the list item
|
||||
if tab_widget.tab_title == list_item.data(QtCore.Qt.UserRole):
|
||||
# Make the matching tab visible
|
||||
self.stacked_layout.setCurrentIndex(tab_index)
|
||||
self.stacked_layout.currentWidget().tab_visible()
|
||||
|
||||
|
@ -374,7 +374,8 @@ class SlideController(DisplayController, RegistryProperties):
|
||||
triggers=self._slide_shortcut_activated) for s in shortcuts])
|
||||
self.shortcut_timer.timeout.connect(self._slide_shortcut_activated)
|
||||
# Signals
|
||||
self.preview_widget.itemSelectionChanged.connect(self.on_slide_selected)
|
||||
self.preview_widget.clicked.connect(self.on_slide_selected)
|
||||
self.preview_widget.verticalHeader().sectionClicked.connect(self.on_slide_selected)
|
||||
if self.is_live:
|
||||
# Need to use event as called across threads and UI is updated
|
||||
QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_toggle_display'), self.toggle_display)
|
||||
|
@ -53,6 +53,8 @@ class Ui_ThemeWizard(object):
|
||||
if is_macosx():
|
||||
theme_wizard.setPixmap(QtGui.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
|
||||
theme_wizard.resize(646, 400)
|
||||
else:
|
||||
theme_wizard.setWizardStyle(QtGui.QWizard.ModernStyle)
|
||||
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
|
||||
# Welcome Page
|
||||
add_welcome_page(theme_wizard, ':/wizards/wizard_createtheme.bmp')
|
||||
|
@ -125,6 +125,8 @@ class OpenLPWizard(QtGui.QWizard, RegistryProperties):
|
||||
QtGui.QWizard.NoBackButtonOnStartPage | QtGui.QWizard.NoBackButtonOnLastPage)
|
||||
if is_macosx():
|
||||
self.setPixmap(QtGui.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
|
||||
else:
|
||||
self.setWizardStyle(QtGui.QWizard.ModernStyle)
|
||||
add_welcome_page(self, image)
|
||||
self.add_custom_pages()
|
||||
if self.with_progress_page:
|
||||
|
@ -52,6 +52,7 @@ if not is_win() and not is_macosx():
|
||||
from xdg import BaseDirectory
|
||||
XDG_BASE_AVAILABLE = True
|
||||
except ImportError:
|
||||
BaseDirectory = None
|
||||
XDG_BASE_AVAILABLE = False
|
||||
|
||||
from openlp.core.common import translate
|
||||
@ -125,14 +126,25 @@ class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler):
|
||||
Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248
|
||||
(Redirecting to urls with special chars)
|
||||
"""
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
# Test if the newurl can be decoded to ascii
|
||||
def redirect_request(self, req, fp, code, msg, headers, new_url):
|
||||
#
|
||||
"""
|
||||
Test if the new_url can be decoded to ascii
|
||||
|
||||
:param req:
|
||||
:param fp:
|
||||
:param code:
|
||||
:param msg:
|
||||
:param headers:
|
||||
:param new_url:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
test_url = newurl.encode('latin1').decode('ascii')
|
||||
fixed_url = newurl
|
||||
new_url.encode('latin1').decode('ascii')
|
||||
fixed_url = new_url
|
||||
except Exception:
|
||||
# The url could not be decoded to ascii, so we do some url encoding
|
||||
fixed_url = urllib.parse.quote(newurl.encode('latin1').decode('utf-8', 'replace'), safe='/:')
|
||||
fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:')
|
||||
return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url)
|
||||
|
||||
|
||||
@ -181,18 +193,18 @@ def get_application_version():
|
||||
full_version = '%s-bzr%s' % (tag_version.decode('utf-8'), tree_revision.decode('utf-8'))
|
||||
else:
|
||||
# We're not running the development version, let's use the file.
|
||||
filepath = AppLocation.get_directory(AppLocation.VersionDir)
|
||||
filepath = os.path.join(filepath, '.version')
|
||||
fversion = None
|
||||
file_path = AppLocation.get_directory(AppLocation.VersionDir)
|
||||
file_path = os.path.join(file_path, '.version')
|
||||
version_file = None
|
||||
try:
|
||||
fversion = open(filepath, 'r')
|
||||
full_version = str(fversion.read()).rstrip()
|
||||
version_file = open(file_path, 'r')
|
||||
full_version = str(version_file.read()).rstrip()
|
||||
except IOError:
|
||||
log.exception('Error in version file.')
|
||||
full_version = '0.0.0-bzr000'
|
||||
finally:
|
||||
if fversion:
|
||||
fversion.close()
|
||||
if version_file:
|
||||
version_file.close()
|
||||
bits = full_version.split('-')
|
||||
APPLICATION_VERSION = {
|
||||
'full': full_version,
|
||||
@ -211,13 +223,13 @@ def check_latest_version(current_version):
|
||||
Check the latest version of OpenLP against the version file on the OpenLP
|
||||
site.
|
||||
|
||||
:param current_version: The current version of OpenLP.
|
||||
|
||||
**Rules around versions and version files:**
|
||||
|
||||
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
|
||||
* If a version number's minor version is an odd number, it is a development release.
|
||||
* If a version number's minor version is an even number, it is a stable release.
|
||||
|
||||
:param current_version: The current version of OpenLP.
|
||||
"""
|
||||
version_string = current_version['full']
|
||||
# set to prod in the distribution config file.
|
||||
|
@ -38,7 +38,7 @@ from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemConte
|
||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||
from openlp.core.utils import get_locale_key
|
||||
from openlp.plugins.presentations.lib import MessageListener
|
||||
|
||||
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -145,7 +145,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
if self.controllers[item].enabled():
|
||||
self.display_type_combo_box.addItem(item)
|
||||
if self.display_type_combo_box.count() > 1:
|
||||
self.display_type_combo_box.insertItem(0, self.automatic)
|
||||
self.display_type_combo_box.insertItem(0, self.automatic, userData='automatic')
|
||||
self.display_type_combo_box.setCurrentIndex(0)
|
||||
if Settings().value(self.settings_section + '/override app') == QtCore.Qt.Checked:
|
||||
self.presentation_widget.show()
|
||||
@ -260,11 +260,11 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
filename = presentation_file
|
||||
if filename is None:
|
||||
filename = items[0].data(QtCore.Qt.UserRole)
|
||||
file_type = os.path.splitext(filename)[1][1:]
|
||||
file_type = os.path.splitext(filename.lower())[1][1:]
|
||||
if not self.display_type_combo_box.currentText():
|
||||
return False
|
||||
service_item.add_capability(ItemCapabilities.CanEditTitle)
|
||||
if (file_type == 'pdf' or file_type == 'xps') and context != ServiceItemContext.Service:
|
||||
if file_type in PDF_CONTROLLER_FILETYPES and context != ServiceItemContext.Service:
|
||||
service_item.add_capability(ItemCapabilities.CanMaintain)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
@ -313,7 +313,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
(path, name) = os.path.split(filename)
|
||||
service_item.title = name
|
||||
if os.path.exists(filename):
|
||||
if service_item.processor == self.automatic:
|
||||
if self.display_type_combo_box.itemData(self.display_type_combo_box.currentIndex()) == 'automatic':
|
||||
service_item.processor = self.find_controller_by_type(filename)
|
||||
if not service_item.processor:
|
||||
return False
|
||||
|
@ -29,12 +29,14 @@
|
||||
|
||||
import logging
|
||||
import copy
|
||||
import os
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.ui import HideMode
|
||||
from openlp.core.lib import ServiceItemContext, ServiceItem
|
||||
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -320,10 +322,11 @@ class MessageListener(object):
|
||||
file = item.get_frame_path()
|
||||
self.handler = item.processor
|
||||
# When starting presentation from the servicemanager we convert
|
||||
# PDF/XPS-serviceitems into image-serviceitems. When started from the mediamanager
|
||||
# PDF/XPS/OXPS-serviceitems into image-serviceitems. When started from the mediamanager
|
||||
# the conversion has already been done at this point.
|
||||
if file.endswith('.pdf') or file.endswith('.xps'):
|
||||
log.debug('Converting from pdf/xps to images for serviceitem with file %s', file)
|
||||
file_type = os.path.splitext(file.lower())[1][1:]
|
||||
if file_type in PDF_CONTROLLER_FILETYPES:
|
||||
log.debug('Converting from pdf/xps/oxps to images for serviceitem with file %s', file)
|
||||
# Create a copy of the original item, and then clear the original item so it can be filled with images
|
||||
item_cpy = copy.copy(item)
|
||||
item.__init__(None)
|
||||
@ -338,7 +341,7 @@ class MessageListener(object):
|
||||
item.image_border = item_cpy.image_border
|
||||
item.main = item_cpy.main
|
||||
item.theme_data = item_cpy.theme_data
|
||||
# When presenting PDF or XPS, we are using the image presentation code,
|
||||
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
|
||||
# so handler & processor is set to None, and we skip adding the handler.
|
||||
self.handler = None
|
||||
if self.handler == self.media_item.automatic:
|
||||
@ -349,7 +352,7 @@ class MessageListener(object):
|
||||
controller = self.live_handler
|
||||
else:
|
||||
controller = self.preview_handler
|
||||
# When presenting PDF or XPS, we are using the image presentation code,
|
||||
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
|
||||
# so handler & processor is set to None, and we skip adding the handler.
|
||||
if self.handler is None:
|
||||
self.controller = controller
|
||||
|
@ -34,12 +34,17 @@ import re
|
||||
from subprocess import check_output, CalledProcessError, STDOUT
|
||||
|
||||
from openlp.core.utils import AppLocation
|
||||
from openlp.core.common import Settings, is_win
|
||||
from openlp.core.common import Settings, is_win, trace_error_handler
|
||||
from openlp.core.lib import ScreenList
|
||||
from .presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
if is_win():
|
||||
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
PDF_CONTROLLER_FILETYPES = ['pdf', 'xps', 'oxps']
|
||||
|
||||
|
||||
class PdfController(PresentationController):
|
||||
"""
|
||||
@ -74,11 +79,19 @@ class PdfController(PresentationController):
|
||||
runlog = ''
|
||||
log.debug('testing program_path: %s', program_path)
|
||||
try:
|
||||
runlog = check_output([program_path, '--help'], stderr=STDOUT)
|
||||
# Setup startupinfo options for check_output to avoid console popping up on windows
|
||||
if is_win():
|
||||
startupinfo = STARTUPINFO()
|
||||
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
|
||||
else:
|
||||
startupinfo = None
|
||||
runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo)
|
||||
except CalledProcessError as e:
|
||||
runlog = e.output
|
||||
except Exception:
|
||||
trace_error_handler(log)
|
||||
runlog = ''
|
||||
log.debug('check_output returned: %s' % runlog)
|
||||
# Analyse the output to see it the program is mudraw, ghostscript or neither
|
||||
for line in runlog.splitlines():
|
||||
decoded_line = line.decode()
|
||||
@ -148,7 +161,7 @@ class PdfController(PresentationController):
|
||||
if os.path.isfile(os.path.join(application_path, 'mudraw')):
|
||||
self.mudrawbin = os.path.join(application_path, 'mudraw')
|
||||
if self.mudrawbin:
|
||||
self.also_supports = ['xps']
|
||||
self.also_supports = ['xps', 'oxps']
|
||||
return True
|
||||
elif self.gsbin:
|
||||
return True
|
||||
@ -182,6 +195,12 @@ class PdfDocument(PresentationDocument):
|
||||
self.hidden = False
|
||||
self.image_files = []
|
||||
self.num_pages = -1
|
||||
# Setup startupinfo options for check_output to avoid console popping up on windows
|
||||
if is_win():
|
||||
self.startupinfo = STARTUPINFO()
|
||||
self.startupinfo.dwFlags |= STARTF_USESHOWWINDOW
|
||||
else:
|
||||
self.startupinfo = None
|
||||
|
||||
def gs_get_resolution(self, size):
|
||||
"""
|
||||
@ -199,7 +218,8 @@ class PdfDocument(PresentationDocument):
|
||||
runlog = []
|
||||
try:
|
||||
runlog = check_output([self.controller.gsbin, '-dNOPAUSE', '-dNODISPLAY', '-dBATCH',
|
||||
'-sFile=' + self.file_path, gs_resolution_script])
|
||||
'-sFile=' + self.file_path, gs_resolution_script],
|
||||
startupinfo=self.startupinfo)
|
||||
except CalledProcessError as e:
|
||||
log.debug(' '.join(e.cmd))
|
||||
log.debug(e.output)
|
||||
@ -248,13 +268,14 @@ class PdfDocument(PresentationDocument):
|
||||
os.makedirs(self.get_temp_folder())
|
||||
if self.controller.mudrawbin:
|
||||
runlog = check_output([self.controller.mudrawbin, '-w', str(size.right()), '-h', str(size.bottom()),
|
||||
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path])
|
||||
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path],
|
||||
startupinfo=self.startupinfo)
|
||||
elif self.controller.gsbin:
|
||||
resolution = self.gs_get_resolution(size)
|
||||
runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m',
|
||||
'-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
|
||||
'-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'),
|
||||
self.file_path])
|
||||
self.file_path], startupinfo=self.startupinfo)
|
||||
created_files = sorted(os.listdir(self.get_temp_folder()))
|
||||
for fn in created_files:
|
||||
if os.path.isfile(os.path.join(self.get_temp_folder(), fn)):
|
||||
|
@ -31,12 +31,12 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1" />
|
||||
<title>${app_title}</title>
|
||||
<link rel="stylesheet" href="/files/jquery.mobile.css" />
|
||||
<link rel="stylesheet" href="/files/jquery.mobile.min.css" />
|
||||
<link rel="stylesheet" href="/files/openlp.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
||||
<script type="text/javascript" src="/files/jquery.js"></script>
|
||||
<script type="text/javascript" src="/files/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/files/openlp.js"></script>
|
||||
<script type="text/javascript" src="/files/jquery.mobile.js"></script>
|
||||
<script type="text/javascript" src="/files/jquery.mobile.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
translationStrings = {
|
||||
"go_live": "${go_live}",
|
||||
|
9404
openlp/plugins/remotes/html/jquery.js
vendored
9404
openlp/plugins/remotes/html/jquery.js
vendored
File diff suppressed because it is too large
Load Diff
4
openlp/plugins/remotes/html/jquery.min.js
vendored
Normal file
4
openlp/plugins/remotes/html/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
2
openlp/plugins/remotes/html/jquery.mobile.min.css
vendored
Normal file
2
openlp/plugins/remotes/html/jquery.mobile.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
openlp/plugins/remotes/html/jquery.mobile.min.js
vendored
Normal file
2
openlp/plugins/remotes/html/jquery.mobile.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -32,7 +32,7 @@
|
||||
<title>${live_title}</title>
|
||||
<link rel="stylesheet" href="/files/main.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
||||
<script type="text/javascript" src="/files/jquery.js"></script>
|
||||
<script type="text/javascript" src="/files/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/files/main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -32,7 +32,7 @@
|
||||
background-image: url(images/ui-icon-unblank.png);
|
||||
}
|
||||
|
||||
/* Overwrite style from jquery-mobile.css */
|
||||
/* Overwrite style from jquery-mobile.min.css */
|
||||
.ui-li .ui-btn-text a.ui-link-inherit{
|
||||
white-space: normal;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
<title>${stage_title}</title>
|
||||
<link rel="stylesheet" href="/files/stage.css" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
||||
<script type="text/javascript" src="/files/jquery.js"></script>
|
||||
<script type="text/javascript" src="/files/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/files/stage.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -239,6 +239,7 @@ class OpenLyrics(object):
|
||||
|
||||
def __init__(self, manager):
|
||||
self.manager = manager
|
||||
FormattingTags.load_tags()
|
||||
|
||||
def song_to_xml(self, song):
|
||||
"""
|
||||
@ -582,18 +583,20 @@ class OpenLyrics(object):
|
||||
# Some tags have only start html e.g. {br}
|
||||
'end html': tag.close.text if hasattr(tag, 'close') else '',
|
||||
'protected': False,
|
||||
}
|
||||
# Add 'temporary' key in case the formatting tag should not be saved otherwise it is supposed that
|
||||
# formatting tag is permanent.
|
||||
if temporary:
|
||||
openlp_tag['temporary'] = temporary
|
||||
'temporary': temporary
|
||||
}
|
||||
found_tags.append(openlp_tag)
|
||||
existing_tag_ids = [tag['start tag'] for tag in FormattingTags.get_html_tags()]
|
||||
new_tags = [tag for tag in found_tags if tag['start tag'] not in existing_tag_ids]
|
||||
# Do not save an empty list.
|
||||
if new_tags:
|
||||
FormattingTags.add_html_tags(new_tags)
|
||||
FormattingTags.save_html_tags()
|
||||
if not temporary:
|
||||
custom_tags = [tag for tag in FormattingTags.get_html_tags()
|
||||
if not tag['protected'] and not tag['temporary']]
|
||||
FormattingTags.save_html_tags(custom_tags)
|
||||
|
||||
def _process_lines_mixed_content(self, element, newlines=True):
|
||||
"""
|
||||
|
@ -106,7 +106,7 @@ class JenkinsTrigger(object):
|
||||
|
||||
def print_output(self):
|
||||
"""
|
||||
Print the status information of the build tirggered.
|
||||
Print the status information of the build triggered.
|
||||
"""
|
||||
print('Add this to your merge proposal:')
|
||||
print('--------------------------------')
|
||||
|
22
setup.py
22
setup.py
@ -45,7 +45,7 @@ def try_int(s):
|
||||
"""
|
||||
try:
|
||||
return int(s)
|
||||
except Exception:
|
||||
except (TypeError, ValueError):
|
||||
return s
|
||||
|
||||
|
||||
@ -58,27 +58,23 @@ def natural_sort_key(s):
|
||||
return list(map(try_int, SPLIT_ALPHA_DIGITS.findall(s)))
|
||||
|
||||
|
||||
def natural_compare(a, b):
|
||||
"""
|
||||
Compare two strings naturally and return the result.
|
||||
|
||||
:param a: A string to compare.
|
||||
:param b: A string to compare.
|
||||
"""
|
||||
return cmp(natural_sort_key(a), natural_sort_key(b))
|
||||
|
||||
|
||||
def natural_sort(seq, compare=natural_compare):
|
||||
def natural_sort(seq):
|
||||
"""
|
||||
Returns a copy of seq, sorted by natural string sort.
|
||||
|
||||
:param seq: The sequence to sort.
|
||||
:param compare: The comparison method to use
|
||||
:return: The sorted sequence
|
||||
"""
|
||||
import copy
|
||||
temp = copy.copy(seq)
|
||||
temp.sort(compare)
|
||||
temp.sort(key=natural_sort_key)
|
||||
return temp
|
||||
|
||||
|
||||
# NOTE: The following code is a duplicate of the code in openlp/core/utils/__init__.py. Any fix applied here should also
|
||||
# be applied there.
|
||||
ver_file = None
|
||||
try:
|
||||
# Get the revision of this tree.
|
||||
bzr = Popen(('bzr', 'revno'), stdout=PIPE)
|
||||
|
@ -0,0 +1,31 @@
|
||||
# -*- 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
All the tests
|
||||
"""
|
@ -43,7 +43,7 @@ class TestSettings(TestCase, TestMixin):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
|
||||
def tearDown(self):
|
||||
|
@ -52,7 +52,7 @@ class TestImageManager(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
ScreenList.create(self.app.desktop())
|
||||
self.image_manager = ImageManager()
|
||||
self.lock = Lock()
|
||||
|
@ -29,44 +29,78 @@
|
||||
"""
|
||||
Package to test the openlp.core.ui.firsttimeform package.
|
||||
"""
|
||||
from configparser import ConfigParser
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
|
||||
from tests.functional import MagicMock
|
||||
from tests.functional import MagicMock, patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
FAKE_CONFIG = b"""
|
||||
[general]
|
||||
base url = http://example.com/frw/
|
||||
[songs]
|
||||
directory = songs
|
||||
[bibles]
|
||||
directory = bibles
|
||||
[themes]
|
||||
directory = themes
|
||||
"""
|
||||
|
||||
|
||||
class TestFirstTimeForm(TestCase, TestMixin):
|
||||
|
||||
def setUp(self):
|
||||
screens = MagicMock()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.app.setApplicationVersion('0.0')
|
||||
Registry.create()
|
||||
Registry().register('application', self.app)
|
||||
self.first_time_form = FirstTimeForm(screens)
|
||||
|
||||
def access_to_config_test(self):
|
||||
def basic_initialise_test(self):
|
||||
"""
|
||||
Test if we can access the First Time Form's config file
|
||||
Test if we can intialise the FirstTimeForm without a config file
|
||||
"""
|
||||
# GIVEN A new First Time Form instance.
|
||||
# GIVEN: A mocked get_web_page, a First Time Wizard and an expected screen object
|
||||
with patch('openlp.core.ui.firsttimeform.get_web_page') as mocked_get_web_page:
|
||||
first_time_form = FirstTimeForm(None)
|
||||
expected_screens = MagicMock()
|
||||
expected_web_url = 'http://openlp.org/files/frw/'
|
||||
expected_user_agent = 'OpenLP/0.0'
|
||||
mocked_get_web_page.return_value = None
|
||||
|
||||
# WHEN The default First Time Form is built.
|
||||
# WHEN: The First Time Wizard is initialised
|
||||
first_time_form.initialize(expected_screens)
|
||||
|
||||
# THEN The First Time Form web configuration file should be accessable.
|
||||
self.assertTrue(self.first_time_form.web_access,
|
||||
'First Time Wizard\'s web configuration file should be available')
|
||||
# THEN: The First Time Form web configuration file should be accessible and parseable
|
||||
self.assertEqual(expected_screens, first_time_form.screens, 'The screens should be correct')
|
||||
self.assertEqual(expected_web_url, first_time_form.web, 'The base path of the URL should be correct')
|
||||
self.assertIsInstance(first_time_form.config, ConfigParser, 'The config object should be a ConfigParser')
|
||||
mocked_get_web_page.assert_called_with(expected_web_url + 'download.cfg',
|
||||
header=('User-Agent', expected_user_agent))
|
||||
|
||||
def parsable_config_test(self):
|
||||
def config_initialise_test(self):
|
||||
"""
|
||||
Test if the First Time Form's config file is parsable
|
||||
Test if we can intialise the FirstTimeForm with a config file
|
||||
"""
|
||||
# GIVEN A new First Time Form instance.
|
||||
# GIVEN: A mocked get_web_page, a First Time Wizard and an expected screen object
|
||||
with patch('openlp.core.ui.firsttimeform.get_web_page') as mocked_get_web_page:
|
||||
first_time_form = FirstTimeForm(None)
|
||||
expected_web_url = 'http://openlp.org/files/frw/'
|
||||
expected_songs_url = 'http://example.com/frw/songs/'
|
||||
expected_bibles_url = 'http://example.com/frw/bibles/'
|
||||
expected_themes_url = 'http://example.com/frw/themes/'
|
||||
expected_user_agent = 'OpenLP/0.0'
|
||||
mocked_get_web_page.return_value.read.return_value = FAKE_CONFIG
|
||||
|
||||
# WHEN The default First Time Form is built.
|
||||
# WHEN: The First Time Wizard is initialised
|
||||
first_time_form.initialize(MagicMock())
|
||||
|
||||
# THEN The First Time Form web configuration file should be parsable
|
||||
self.assertTrue(self.first_time_form.songs_url,
|
||||
'First Time Wizard\'s web configuration file should be parsable')
|
||||
# THEN: The First Time Form web configuration file should be accessible and parseable
|
||||
self.assertIsInstance(first_time_form.config, ConfigParser, 'The config object should be a ConfigParser')
|
||||
mocked_get_web_page.assert_called_with(expected_web_url + 'download.cfg',
|
||||
header=('User-Agent', expected_user_agent))
|
||||
self.assertEqual(expected_songs_url, first_time_form.songs_url, 'The songs URL should be correct')
|
||||
self.assertEqual(expected_bibles_url, first_time_form.bibles_url, 'The bibles URL should be correct')
|
||||
self.assertEqual(expected_themes_url, first_time_form.themes_url, 'The themes URL should be correct')
|
||||
|
@ -29,9 +29,7 @@
|
||||
"""
|
||||
Package to test the openlp.core.ui.formattingtagsform package.
|
||||
"""
|
||||
from PyQt4 import QtGui
|
||||
from unittest import TestCase
|
||||
from openlp.core.common import translate
|
||||
|
||||
from tests.functional import MagicMock, patch, call
|
||||
|
||||
|
@ -27,8 +27,38 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`resources` module contains a bunch of resources for OpenLP.
|
||||
|
||||
DO NOT REMOVE THIS FILE, IT IS REQUIRED FOR INCLUDING THE RESOURCES ON SOME
|
||||
PLATFORMS!
|
||||
Package to test the openlp.core.ui.listpreviewwidget package.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
from openlp.core.ui.listpreviewwidget import ListPreviewWidget
|
||||
|
||||
from tests.functional import patch
|
||||
|
||||
|
||||
class TestListPreviewWidget(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Mock out stuff for all the tests
|
||||
"""
|
||||
self.setup_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget._setup')
|
||||
self.mocked_setup = self.setup_patcher.start()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Remove the mocks
|
||||
"""
|
||||
self.setup_patcher.stop()
|
||||
|
||||
def new_list_preview_widget_test(self):
|
||||
"""
|
||||
Test that creating an instance of ListPreviewWidget works
|
||||
"""
|
||||
# GIVEN: A ListPreviewWidget class
|
||||
|
||||
# WHEN: An object is created
|
||||
list_preview_widget = ListPreviewWidget(None, 1)
|
||||
|
||||
# THEN: The object is not None, and the _setup() method was called.
|
||||
self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
|
||||
self.mocked_setup.assert_called_with(1)
|
@ -46,7 +46,7 @@ class TestMainWindow(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
Registry.create()
|
||||
self.registry = Registry()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
# Mock cursor busy/normal methods.
|
||||
self.app.set_busy_cursor = MagicMock()
|
||||
self.app.set_normal_cursor = MagicMock()
|
||||
|
@ -35,7 +35,7 @@ from openlp.core.common import Registry, ThemeLevel
|
||||
from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities
|
||||
from openlp.core.ui import ServiceManager
|
||||
|
||||
from tests.interfaces import MagicMock, patch
|
||||
from tests.functional import MagicMock
|
||||
|
||||
|
||||
class TestServiceManager(TestCase):
|
||||
|
85
tests/functional/openlp_core_ui/test_settingsform.py
Normal file
85
tests/functional/openlp_core_ui/test_settingsform.py
Normal file
@ -0,0 +1,85 @@
|
||||
# -*- 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui.settingsform package.
|
||||
"""
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.core.ui.generaltab import GeneralTab
|
||||
from openlp.core.ui.settingsform import SettingsForm
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
|
||||
|
||||
class TestSettingsForm(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up a few things for the tests
|
||||
"""
|
||||
Registry.create()
|
||||
|
||||
def insert_tab_visible_test(self):
|
||||
"""
|
||||
Test that the insert_tab() method works correctly when a visible tab is inserted
|
||||
"""
|
||||
# GIVEN: A mocked tab and a Settings Form
|
||||
settings_form = SettingsForm(None)
|
||||
general_tab = MagicMock()
|
||||
general_tab.tab_title = 'mock'
|
||||
general_tab.tab_title_visible = 'Mock'
|
||||
general_tab.icon_path = ':/icon/openlp-logo-16x16.png'
|
||||
|
||||
# WHEN: We insert the general tab
|
||||
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
|
||||
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
|
||||
settings_form.insert_tab(general_tab, is_visible=True)
|
||||
|
||||
# THEN: Stuff should happen
|
||||
mocked_add_widget.assert_called_with(general_tab)
|
||||
self.assertEqual(1, mocked_add_item.call_count, 'addItem should have been called')
|
||||
|
||||
def insert_tab_not_visible_test(self):
|
||||
"""
|
||||
Test that the insert_tab() method works correctly when a tab that should not be visible is inserted
|
||||
"""
|
||||
# GIVEN: A general tab and a Settings Form
|
||||
settings_form = SettingsForm(None)
|
||||
general_tab = MagicMock()
|
||||
general_tab.tab_title = 'mock'
|
||||
|
||||
# WHEN: We insert the general tab
|
||||
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
|
||||
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
|
||||
settings_form.insert_tab(general_tab, is_visible=False)
|
||||
|
||||
# THEN: Stuff should happen
|
||||
mocked_add_widget.assert_called_with(general_tab)
|
||||
self.assertEqual(0, mocked_add_item.call_count, 'addItem should not have been called')
|
@ -51,7 +51,7 @@ class TestImpressController(TestCase, TestMixin):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
self.mock_plugin = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
|
@ -51,7 +51,7 @@ class TestMediaItem(TestCase, TestMixin):
|
||||
with patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup'), \
|
||||
patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item'):
|
||||
self.media_item = PresentationMediaItem(None, MagicMock, MagicMock())
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
|
||||
def build_file_mask_string_test(self):
|
||||
"""
|
||||
@ -71,7 +71,7 @@ class TestMediaItem(TestCase, TestMixin):
|
||||
pdf_controller = MagicMock()
|
||||
pdf_controller.enabled.return_value = True
|
||||
pdf_controller.supports = ['pdf']
|
||||
pdf_controller.also_supports = ['xps']
|
||||
pdf_controller.also_supports = ['xps', 'oxps']
|
||||
# Mock the controllers.
|
||||
self.media_item.controllers = {
|
||||
'Impress': impress_controller,
|
||||
@ -90,3 +90,4 @@ class TestMediaItem(TestCase, TestMixin):
|
||||
self.assertIn('*.ppt', self.media_item.on_new_file_masks, 'The file mask should contain the ppt extension')
|
||||
self.assertIn('*.pdf', self.media_item.on_new_file_masks, 'The file mask should contain the pdf extension')
|
||||
self.assertIn('*.xps', self.media_item.on_new_file_masks, 'The file mask should contain the xps extension')
|
||||
self.assertIn('*.oxps', self.media_item.on_new_file_masks, 'The file mask should contain the oxps extension')
|
||||
|
@ -61,7 +61,7 @@ class TestPdfController(TestCase, TestMixin):
|
||||
"""
|
||||
Set up the components need for all tests.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
# Mocked out desktop object
|
||||
self.desktop = MagicMock()
|
||||
|
@ -55,7 +55,7 @@ class TestPowerpointController(TestCase, TestMixin):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
self.mock_plugin = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
@ -92,7 +92,7 @@ class TestPowerpointDocument(TestCase, TestMixin):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
self.mock_plugin = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
|
@ -59,7 +59,7 @@ class TestPptviewController(TestCase, TestMixin):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
self.mock_plugin = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
|
@ -33,7 +33,7 @@ classes and related methods.
|
||||
from unittest import TestCase
|
||||
import os
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||
from tests.functional import MagicMock, patch, mock_open
|
||||
from tests.functional import MagicMock, mock_open, patch
|
||||
|
||||
FOLDER_TO_PATCH = 'openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder'
|
||||
|
||||
@ -42,6 +42,19 @@ class TestPresentationController(TestCase):
|
||||
"""
|
||||
Test the PresentationController.
|
||||
"""
|
||||
# TODO: Items left to test
|
||||
# PresentationController
|
||||
# __init__
|
||||
# enabled
|
||||
# is_available
|
||||
# check_available
|
||||
# start_process
|
||||
# kill
|
||||
# add_document
|
||||
# remove_doc
|
||||
# close_presentation
|
||||
# _get_plugin_manager
|
||||
|
||||
def setUp(self):
|
||||
mocked_plugin = MagicMock()
|
||||
mocked_plugin.settings_section = 'presentations'
|
||||
@ -164,3 +177,124 @@ class TestPresentationController(TestCase):
|
||||
|
||||
# THEN: it should return two empty lists
|
||||
self.assertIs(type(result_titles), list, 'result_titles should be a list')
|
||||
|
||||
|
||||
class TestPresentationDocument(TestCase):
|
||||
"""
|
||||
Test the PresentationDocument Class
|
||||
"""
|
||||
# TODO: Items left to test
|
||||
# PresentationDocument
|
||||
# __init__
|
||||
# presentation_deleted
|
||||
# get_thumbnail_folder
|
||||
# get_temp_folder
|
||||
# check_thumbnails
|
||||
# close_presentation
|
||||
# is_active
|
||||
# is_loaded
|
||||
# blank_screen
|
||||
# unblank_screen
|
||||
# is_blank
|
||||
# stop_presentation
|
||||
# start_presentation
|
||||
# get_slide_number
|
||||
# get_slide_count
|
||||
# goto_slide
|
||||
# next_step
|
||||
# previous_step
|
||||
# convert_thumbnail
|
||||
# get_thumbnail_path
|
||||
# poll_slidenumber
|
||||
# get_slide_text
|
||||
# get_slide_notes
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.check_directory_exists_patcher = \
|
||||
patch('openlp.plugins.presentations.lib.presentationcontroller.check_directory_exists')
|
||||
self.get_thumbnail_folder_patcher = \
|
||||
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder')
|
||||
self.os_patcher = patch('openlp.plugins.presentations.lib.presentationcontroller.os')
|
||||
self._setup_patcher = \
|
||||
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument._setup')
|
||||
|
||||
self.mock_check_directory_exists = self.check_directory_exists_patcher.start()
|
||||
self.mock_get_thumbnail_folder = self.get_thumbnail_folder_patcher.start()
|
||||
self.mock_os = self.os_patcher.start()
|
||||
self.mock_setup = self._setup_patcher.start()
|
||||
|
||||
self.mock_controller = MagicMock()
|
||||
|
||||
self.mock_get_thumbnail_folder.return_value = 'returned/path/'
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Stop the patches
|
||||
"""
|
||||
self.check_directory_exists_patcher.stop()
|
||||
self.get_thumbnail_folder_patcher.stop()
|
||||
self.os_patcher.stop()
|
||||
self._setup_patcher.stop()
|
||||
|
||||
def initialise_presentation_document_test(self):
|
||||
"""
|
||||
Test the PresentationDocument __init__ method when initialising the PresentationDocument Class
|
||||
"""
|
||||
# GIVEN: A mocked setup method and mocked controller
|
||||
self.mock_setup.reset()
|
||||
|
||||
# WHEN: Creating an instance of PresentationDocument
|
||||
PresentationDocument(self.mock_controller, 'Name')
|
||||
|
||||
# THEN: PresentationDocument._setup should have been called with the argument 'Name'
|
||||
self.mock_setup.assert_called_once_with('Name')
|
||||
|
||||
def presentation_document_setup_test(self):
|
||||
"""
|
||||
Test the PresentationDocument _setup method when initialising the PresentationDocument Class
|
||||
"""
|
||||
self._setup_patcher.stop()
|
||||
|
||||
# GIVEN: A mocked controller, patched check_directory_exists and get_thumbnail_folder methods
|
||||
|
||||
# WHEN: Creating an instance of PresentationDocument
|
||||
PresentationDocument(self.mock_controller, 'Name')
|
||||
|
||||
# THEN: check_directory_exists should have been called with 'returned/path/'
|
||||
self.mock_check_directory_exists.assert_called_once_with('returned/path/')
|
||||
|
||||
self._setup_patcher.start()
|
||||
|
||||
def load_presentation_test(self):
|
||||
"""
|
||||
Test the PresentationDocument.load_presentation method.
|
||||
"""
|
||||
|
||||
# GIVEN: An instance of PresentationDocument
|
||||
instance = PresentationDocument(self.mock_controller, 'Name')
|
||||
|
||||
# WHEN: Calling load_presentation()
|
||||
result = instance.load_presentation()
|
||||
|
||||
# THEN: load_presentation should return false
|
||||
self.assertFalse(result, "PresentationDocument.load_presentation should return false.")
|
||||
|
||||
def get_file_name_test(self):
|
||||
"""
|
||||
Test the PresentationDocument.get_file_name method.
|
||||
"""
|
||||
|
||||
# GIVEN: A mocked os.path.split which returns a list, an instance of PresentationDocument and
|
||||
# arbitary file_path.
|
||||
self.mock_os.path.split.return_value = ['directory', 'file.ext']
|
||||
instance = PresentationDocument(self.mock_controller, 'Name')
|
||||
instance.file_path = 'filepath'
|
||||
|
||||
# WHEN: Calling get_file_name
|
||||
result = instance.get_file_name()
|
||||
|
||||
# THEN: get_file_name should return 'file.ext'
|
||||
self.assertEqual(result, 'file.ext')
|
||||
|
@ -63,7 +63,7 @@ class TestRemoteTab(TestCase, TestMixin):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
Settings().extend_default_settings(__default_settings__)
|
||||
self.parent = QtGui.QMainWindow()
|
||||
|
@ -61,7 +61,7 @@ class TestRouter(TestCase, TestMixin):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
Settings().extend_default_settings(__default_settings__)
|
||||
self.router = HttpRouter()
|
||||
@ -132,6 +132,7 @@ class TestRouter(TestCase, TestMixin):
|
||||
Test the main poll logic
|
||||
"""
|
||||
# GIVEN: a defined router with two slides
|
||||
Registry.create()
|
||||
Registry().register('live_controller', MagicMock)
|
||||
router = HttpRouter()
|
||||
router.send_response = MagicMock()
|
||||
|
@ -35,6 +35,7 @@ from unittest import TestCase
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
|
||||
from openlp.core.common import Registry
|
||||
from openlp.plugins.songs.lib.importers.easyworship import EasyWorshipSongImport, FieldDescEntry, FieldType
|
||||
|
||||
TEST_PATH = os.path.abspath(
|
||||
@ -153,6 +154,11 @@ class TestEasyWorshipSongImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`ewimport` module.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the registry
|
||||
"""
|
||||
Registry.create()
|
||||
|
||||
def create_field_desc_entry_test(self):
|
||||
"""
|
||||
|
@ -29,7 +29,7 @@ class TestMediaItem(TestCase, TestMixin):
|
||||
self.media_item = SongMediaItem(None, MagicMock())
|
||||
self.media_item.display_songbook = False
|
||||
self.media_item.display_copyright_symbol = False
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
|
||||
|
||||
|
@ -31,11 +31,17 @@ This module contains tests for the OpenLyrics song importer.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from unittest import TestCase
|
||||
from lxml import etree, objectify
|
||||
|
||||
from tests.functional import MagicMock, patch
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport
|
||||
from openlp.plugins.songs.lib.importers.songimport import SongImport
|
||||
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
|
||||
from openlp.core.common import Registry, Settings
|
||||
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..', '..', 'resources', 'openlyricssongs'))
|
||||
@ -59,11 +65,33 @@ SONG_TEST_DATA = {
|
||||
}
|
||||
}
|
||||
|
||||
start_tags = [{"protected": False, "desc": "z", "start tag": "{z}", "end html": "</strong>", "temporary": False,
|
||||
"end tag": "{/z}", "start html": "strong>"}]
|
||||
result_tags = [{"temporary": False, "protected": False, "desc": "z", "start tag": "{z}", "start html": "strong>",
|
||||
"end html": "</strong>", "end tag": "{/z}"},
|
||||
{"temporary": False, "end tag": "{/c}", "desc": "c", "start tag": "{c}",
|
||||
"start html": "<span class=\"chord\" style=\"display:none\"><strong>", "end html": "</strong></span>",
|
||||
"protected": False}]
|
||||
|
||||
class TestOpenLyricsImport(TestCase):
|
||||
|
||||
class TestOpenLyricsImport(TestCase, TestMixin):
|
||||
"""
|
||||
Test the functions in the :mod:`openlyricsimport` module.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the registry
|
||||
"""
|
||||
self.setup_application()
|
||||
Registry.create()
|
||||
self.build_settings()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Cleanup
|
||||
"""
|
||||
self.destroy_settings()
|
||||
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the OpenLyrics file importer
|
||||
@ -97,3 +125,24 @@ class TestOpenLyricsImport(TestCase):
|
||||
|
||||
# THEN: The xml_to_song() method should have been called
|
||||
self.assertTrue(importer.open_lyrics.xml_to_song.called)
|
||||
|
||||
def process_formatting_tags_test(self):
|
||||
"""
|
||||
Test that _process_formatting_tags works
|
||||
"""
|
||||
# GIVEN: A OpenLyric XML with formatting tags and a mocked out manager
|
||||
mocked_manager = MagicMock()
|
||||
Settings().setValue('formattingTags/html_tags', json.dumps(start_tags))
|
||||
ol = OpenLyrics(mocked_manager)
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
parsed_file = etree.parse(open(os.path.join(TEST_PATH, 'duchu-tags.xml'), 'rb'), parser)
|
||||
xml = etree.tostring(parsed_file).decode()
|
||||
song_xml = objectify.fromstring(xml)
|
||||
|
||||
# WHEN: processing the formatting tags
|
||||
ol._process_formatting_tags(song_xml, False)
|
||||
|
||||
# THEN: New tags should have been saved
|
||||
self.assertListEqual(json.loads(json.dumps(result_tags)),
|
||||
json.loads(str(Settings().value('formattingTags/html_tags'))),
|
||||
'The formatting tags should contain both the old and the new')
|
||||
|
@ -35,6 +35,7 @@ from unittest import TestCase
|
||||
|
||||
from tests.helpers.songfileimport import SongImportTestHelper
|
||||
from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
|
||||
from openlp.core.common import Registry
|
||||
from tests.functional import patch, MagicMock
|
||||
|
||||
TEST_PATH = os.path.abspath(
|
||||
@ -64,6 +65,12 @@ class TestOpenSongImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`opensongimport` module.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the registry
|
||||
"""
|
||||
Registry.create()
|
||||
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the OpenSong file importer
|
||||
|
@ -34,6 +34,7 @@ ProPresenter song files into the current installation database.
|
||||
import os
|
||||
|
||||
from tests.helpers.songfileimport import SongImportTestHelper
|
||||
from openlp.core.common import Registry
|
||||
|
||||
TEST_PATH = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs'))
|
||||
|
@ -38,12 +38,12 @@ TEST_PATH = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'presentationmanagersongs'))
|
||||
|
||||
|
||||
class TestSongShowPlusFileImport(SongImportTestHelper):
|
||||
class TestPresentationManagerFileImport(SongImportTestHelper):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.importer_class_name = 'PresentationManagerImport'
|
||||
self.importer_module_name = 'presentationmanager'
|
||||
super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs)
|
||||
super(TestPresentationManagerFileImport, self).__init__(*args, **kwargs)
|
||||
|
||||
def test_song_import(self):
|
||||
"""
|
||||
@ -51,3 +51,5 @@ class TestSongShowPlusFileImport(SongImportTestHelper):
|
||||
"""
|
||||
self.file_import([os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.sng')],
|
||||
self.load_external_result_data(os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.json')))
|
||||
self.file_import([os.path.join(TEST_PATH, 'Agnus Dei.sng')],
|
||||
self.load_external_result_data(os.path.join(TEST_PATH, 'Agnus Dei.json')))
|
||||
|
@ -36,6 +36,7 @@ from unittest import TestCase
|
||||
from tests.functional import MagicMock, patch
|
||||
from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport
|
||||
from openlp.plugins.songs.lib import VerseType
|
||||
from openlp.core.common import Registry
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..', '..', 'resources', 'songbeamersongs'))
|
||||
@ -59,6 +60,12 @@ class TestSongBeamerImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`songbeamerimport` module.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the registry
|
||||
"""
|
||||
Registry.create()
|
||||
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the SongBeamer file importer
|
||||
|
@ -35,12 +35,19 @@ from unittest import TestCase
|
||||
from tests.functional import MagicMock, patch
|
||||
from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport
|
||||
from openlp.plugins.songs.lib.importers.songimport import SongImport
|
||||
from openlp.core.common import Registry
|
||||
|
||||
|
||||
class TestZionWorxImport(TestCase):
|
||||
"""
|
||||
Test the functions in the :mod:`zionworximport` module.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the registry
|
||||
"""
|
||||
Registry.create()
|
||||
|
||||
def create_importer_test(self):
|
||||
"""
|
||||
Test creating an instance of the ZionWorx file importer
|
||||
|
@ -33,9 +33,10 @@ import os
|
||||
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
from PyQt4 import QtCore
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core import OpenLP
|
||||
from openlp.core.common import Settings
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
@ -44,11 +45,13 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resou
|
||||
|
||||
class TestInit(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
self.build_settings()
|
||||
with patch('openlp.core.common.OpenLPMixin.__init__') as constructor:
|
||||
constructor.return_value = None
|
||||
self.openlp = OpenLP(list())
|
||||
|
||||
def tearDown(self):
|
||||
self.destroy_settings()
|
||||
del self.openlp
|
||||
|
||||
def event_test(self):
|
||||
@ -68,3 +71,51 @@ class TestInit(TestCase, TestMixin):
|
||||
self.assertTrue(result, "The method should have returned True.")
|
||||
mocked_file_method.assert_called_once_with()
|
||||
self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.")
|
||||
|
||||
def backup_on_upgrade_first_install_test(self):
|
||||
"""
|
||||
Test that we don't try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are the same
|
||||
old_install = False
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.2.0')
|
||||
with patch('openlp.core.get_application_version') as mocked_get_application_version,\
|
||||
patch('openlp.core.QtGui.QMessageBox.question') as mocked_question:
|
||||
mocked_get_application_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtGui.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install)
|
||||
|
||||
# THEN: It should not ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
|
||||
self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!')
|
||||
|
||||
def backup_on_upgrade_test(self):
|
||||
"""
|
||||
Test that we try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are different
|
||||
old_install = True
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.0.5')
|
||||
with patch('openlp.core.get_application_version') as mocked_get_application_version,\
|
||||
patch('openlp.core.QtGui.QMessageBox.question') as mocked_question:
|
||||
mocked_get_application_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtGui.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install)
|
||||
|
||||
# THEN: It should ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
|
||||
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
|
||||
|
@ -34,6 +34,8 @@ import json
|
||||
import logging
|
||||
from unittest import TestCase
|
||||
|
||||
from openlp.plugins.songs.lib.importers.opensong import OpenSongImport
|
||||
from openlp.core.common import Registry
|
||||
from tests.functional import patch, MagicMock, call
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -53,6 +55,7 @@ class SongImportTestHelper(TestCase):
|
||||
"""
|
||||
Patch and set up the mocks required.
|
||||
"""
|
||||
Registry.create()
|
||||
self.add_copyright_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_copyright' %
|
||||
(self.importer_module_name, self.importer_class_name))
|
||||
self.add_verse_patcher = patch('openlp.plugins.songs.lib.importers.%s.%s.add_verse' %
|
||||
|
@ -37,8 +37,11 @@ from openlp.core.common import Settings
|
||||
|
||||
|
||||
class TestMixin(object):
|
||||
"""
|
||||
The :class:`TestMixin` class provides test with extra functionality
|
||||
"""
|
||||
|
||||
def get_application(self):
|
||||
def setup_application(self):
|
||||
"""
|
||||
Build or reuse the Application object
|
||||
"""
|
||||
|
@ -43,7 +43,7 @@ from tests.interfaces import MagicMock, patch
|
||||
class TestHistoryComboBox(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.combo = HistoryComboBox(self.main_window)
|
||||
|
@ -58,7 +58,7 @@ class TestPluginManager(TestCase, TestMixin):
|
||||
Settings().setValue('advanced/data path', self.temp_dir)
|
||||
Registry.create()
|
||||
Registry().register('service_list', MagicMock())
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
|
||||
|
@ -57,7 +57,7 @@ class TestSearchEdit(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
|
||||
|
@ -46,7 +46,7 @@ class TestStartFileRenameForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = filerenameform.FileRenameForm()
|
||||
|
@ -49,7 +49,7 @@ class TestListPreviewWidget(TestCase, TestMixin):
|
||||
Create the UI.
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
self.image = QtGui.QImage(1, 1, QtGui.QImage.Format_RGB32)
|
||||
self.image_manager = MagicMock()
|
||||
|
@ -46,7 +46,7 @@ class TestMainWindow(TestCase, TestMixin):
|
||||
"""
|
||||
Registry.create()
|
||||
self.registry = Registry()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
# Mock cursor busy/normal methods.
|
||||
self.app.set_busy_cursor = MagicMock()
|
||||
self.app.set_normal_cursor = MagicMock()
|
||||
|
@ -46,7 +46,7 @@ class TestServiceManager(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
ScreenList.create(self.app.desktop())
|
||||
Registry().register('application', MagicMock())
|
||||
with patch('openlp.core.lib.PluginManager'):
|
||||
|
@ -46,7 +46,7 @@ class TestStartNoteDialog(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = servicenoteform.ServiceNoteForm()
|
||||
|
@ -59,7 +59,7 @@ class TestSettingsForm(TestCase, TestMixin):
|
||||
self.dummy2 = MagicMock()
|
||||
self.dummy3 = MagicMock()
|
||||
self.desktop = MagicMock()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.desktop.primaryScreen.return_value = SCREEN['primary']
|
||||
self.desktop.screenCount.return_value = SCREEN['number']
|
||||
self.desktop.screenGeometry.return_value = SCREEN['size']
|
||||
|
@ -46,7 +46,7 @@ class TestShortcutform(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = ShortcutListForm()
|
||||
|
@ -46,7 +46,7 @@ class TestStartTimeDialog(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = starttimeform.StartTimeForm()
|
||||
|
@ -46,7 +46,7 @@ class TestThemeManager(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
self.build_settings()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
Registry.create()
|
||||
self.theme_manager = ThemeManager()
|
||||
|
||||
|
@ -46,7 +46,7 @@ class TestUtils(TestCase, TestMixin):
|
||||
"""
|
||||
Some pre-test setup required.
|
||||
"""
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
|
||||
def is_not_image_empty_test(self):
|
||||
"""
|
||||
|
@ -50,7 +50,7 @@ class TestEditCustomForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
media_item = MagicMock()
|
||||
|
@ -48,7 +48,7 @@ class TestEditCustomSlideForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = EditCustomSlideForm()
|
||||
|
@ -54,7 +54,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
# Mock VLC so we don't actually use it
|
||||
|
@ -48,7 +48,7 @@ class TestAuthorsForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = AuthorsForm()
|
||||
|
@ -49,7 +49,7 @@ class TestEditSongForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
Registry().register('theme_manager', MagicMock())
|
||||
|
@ -48,7 +48,7 @@ class TestEditVerseForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = EditVerseForm()
|
||||
|
@ -48,7 +48,7 @@ class TestTopicsForm(TestCase, TestMixin):
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.get_application()
|
||||
self.setup_application()
|
||||
self.main_window = QtGui.QMainWindow()
|
||||
Registry().register('main_window', self.main_window)
|
||||
self.form = TopicsForm()
|
||||
|
27
tests/resources/openlyricssongs/duchu-tags.xml
Normal file
27
tests/resources/openlyricssongs/duchu-tags.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<song xmlns="http://openlyrics.info/namespace/2009/song" version="0.8" createdIn="OpenLP 2.0.4" modifiedIn="OpenLP 2.0.4" modifiedDate="2014-06-27T09:55:49">
|
||||
<properties>
|
||||
<titles>
|
||||
<title>Duchu svätý volám príď <akordy></title>
|
||||
</titles>
|
||||
<authors>
|
||||
<author>Author Unknown</author>
|
||||
</authors>
|
||||
</properties>
|
||||
<format>
|
||||
<tags application="OpenLP">
|
||||
<tag name="c">
|
||||
<open><span class="chord" style="display:none"><strong></open>
|
||||
<close></strong></span></close>
|
||||
</tag>
|
||||
</tags>
|
||||
</format>
|
||||
<lyrics>
|
||||
<verse name="v1">
|
||||
<lines><tag name="c">[D]</tag>Duchu svätý volám príď, <tag name="c">[Ami]</tag>oheň mojej duši daj,<br/><tag name="c">[G]</tag>Oheň môjmu telu daj, <tag name="c">[D]</tag>rozpáľ ma.</lines>
|
||||
</verse>
|
||||
<verse name="c1">
|
||||
<lines>Všemoh<tag name="c">[Ami]</tag>úci <tag name="c">[G]</tag>Boh tu s nami <tag name="c">[D]</tag>je,<br/>neko<tag name="c">[Ami]</tag>nečne <tag name="c">[G]</tag>milostivý <tag name="c">[D]</tag>je,<br/>Uka<tag name="c">[Ami]</tag>zuje <tag name="c">[G]</tag>dobrotivú <tag name="c">[D]</tag>tvár voči <tag name="c">[Ami]</tag>t<tag name="c">[G]</tag>ým,<br/>ktorí milovať ho <tag name="c">[D]</tag>chcú.</lines>
|
||||
</verse>
|
||||
</lyrics>
|
||||
</song>
|
14
tests/resources/presentationmanagersongs/Agnus Dei.json
Normal file
14
tests/resources/presentationmanagersongs/Agnus Dei.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"title": "Agnus Dei",
|
||||
"verse_order_list": ["v1", "v2"],
|
||||
"verses": [
|
||||
[
|
||||
"Alleluia Alleluluia \nfor the Lord almighty reigns \nAlleluia Alleluluia \nHoly holy are you Lord God Almighty \nWorthy is the lamb \nWorthy is the lamb \nHoly holy are you Lord God Almighty",
|
||||
"v1"
|
||||
],
|
||||
[
|
||||
"Worthy is the lamb \nWorthy is the lamb \nYou are holy holy \nAre you lamb \nWorthy is the lamb \nYou are holy holy \nYou are holy holy",
|
||||
"v2"
|
||||
]
|
||||
]
|
||||
}
|
34
tests/resources/presentationmanagersongs/Agnus Dei.sng
Normal file
34
tests/resources/presentationmanagersongs/Agnus Dei.sng
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<song xmlns="creativelifestyles/song">
|
||||
<attributes>
|
||||
<title>Agnus Dei</title>
|
||||
<author></author>
|
||||
<copyright></copyright>
|
||||
<ccli_number></ccli_number>
|
||||
<comments></comments>
|
||||
</attributes>
|
||||
<verses>
|
||||
<verse id="Verse 1">
|
||||
Alleluia Alleluluia
|
||||
for the Lord almighty reigns
|
||||
Alleluia Alleluluia
|
||||
Holy holy are you Lord God Almighty
|
||||
Worthy is the lamb
|
||||
Worthy is the lamb
|
||||
Holy holy are you Lord God Almighty
|
||||
|
||||
|
||||
</verse>
|
||||
<verse id="Verse 2">
|
||||
Worthy is the lamb
|
||||
Worthy is the lamb
|
||||
You are holy holy
|
||||
Are you lamb
|
||||
Worthy is the lamb
|
||||
You are holy holy
|
||||
You are holy holy
|
||||
|
||||
|
||||
</verse>
|
||||
</verses>
|
||||
</song>
|
Loading…
Reference in New Issue
Block a user