This commit is contained in:
Phill Ridout 2014-12-23 18:57:04 +00:00
commit c9e1dcceff
17 changed files with 607 additions and 168 deletions

View File

@ -122,6 +122,9 @@ class OpenLP(OpenLPMixin, QtGui.QApplication):
ftw.initialize(screens)
if ftw.exec_() == QtGui.QDialog.Accepted:
Settings().setValue('core/has run wizard', True)
elif ftw.was_cancelled:
QtCore.QCoreApplication.exit()
sys.exit()
# Correct stylesheet bugs
application_stylesheet = ''
if not Settings().value('advanced/alternate rows'):

View File

@ -115,7 +115,7 @@ class UiStrings(object):
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.2')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')

View File

@ -31,7 +31,6 @@ This module contains the first time wizard.
"""
import logging
import os
import sys
import time
import urllib.request
import urllib.parse
@ -51,30 +50,48 @@ from .firsttimewizard import UiFirstTimeWizard, FirstTimePage
log = logging.getLogger(__name__)
class ThemeScreenshotThread(QtCore.QThread):
class ThemeScreenshotWorker(QtCore.QObject):
"""
This thread downloads the theme screenshots.
This thread downloads a theme's screenshot
"""
screenshot_downloaded = QtCore.pyqtSignal(str, str)
finished = QtCore.pyqtSignal()
def __init__(self, themes_url, title, filename, screenshot):
"""
Set up the worker object
"""
self.was_download_cancelled = False
self.themes_url = themes_url
self.title = title
self.filename = filename
self.screenshot = screenshot
super(ThemeScreenshotWorker, self).__init__()
def run(self):
"""
Overridden method to run the thread.
"""
themes = self.parent().config.get('themes', 'files')
themes = themes.split(',')
config = self.parent().config
for theme in themes:
# Stop if the wizard has been cancelled.
if self.parent().was_download_cancelled:
return
title = config.get('theme_%s' % theme, 'title')
filename = config.get('theme_%s' % theme, 'filename')
screenshot = config.get('theme_%s' % theme, 'screenshot')
urllib.request.urlretrieve('%s%s' % (self.parent().themes_url, screenshot),
os.path.join(gettempdir(), 'openlp', screenshot))
item = QtGui.QListWidgetItem(title, self.parent().themes_list_widget)
item.setData(QtCore.Qt.UserRole, filename)
item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
if self.was_download_cancelled:
return
try:
urllib.request.urlretrieve('%s%s' % (self.themes_url, self.screenshot),
os.path.join(gettempdir(), 'openlp', self.screenshot))
# Signal that the screenshot has been downloaded
self.screenshot_downloaded.emit(self.title, self.filename)
except:
log.exception('Unable to download screenshot')
finally:
self.finished.emit()
@QtCore.pyqtSlot(bool)
def set_download_canceled(self, toggle):
"""
Externally set if the download was canceled
:param toggle: Set if the download was canceled or not
"""
self.was_download_cancelled = toggle
class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
@ -88,22 +105,25 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
Create and set up the first time wizard.
"""
super(FirstTimeForm, self).__init__(parent)
self.web_access = True
self.web = ''
self.setup_ui(self)
def get_next_page_id(self):
"""
Returns the id of the next FirstTimePage to go to based on enabled plugins
"""
# The songs plugin is enabled
if FirstTimePage.Welcome < self.currentId() < FirstTimePage.Songs and self.songs_check_box.isChecked():
print('Go for songs! %r' % self.songs_check_box.isChecked())
# If the songs plugin is enabled then go to the songs page
return FirstTimePage.Songs
# The Bibles plugin is enabled
elif FirstTimePage.Welcome < self.currentId() < FirstTimePage.Bibles and self.bible_check_box.isChecked():
# Otherwise, if the Bibles plugin is enabled then go to the Bibles page
return FirstTimePage.Bibles
elif FirstTimePage.Welcome < self.currentId() < FirstTimePage.Themes:
# Otherwise, if the current page is somewhere between the Welcome and the Themes pages, go to the themes
return FirstTimePage.Themes
else:
# If all else fails, go to the next page
return self.currentId() + 1
def nextId(self):
@ -111,18 +131,20 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
Determine the next page in the Wizard to go to.
"""
self.application.process_events()
if self.currentId() == FirstTimePage.Plugins:
if self.currentId() == FirstTimePage.Download:
if not self.web_access:
return FirstTimePage.NoInternet
else:
return self.get_next_page_id()
return FirstTimePage.Plugins
elif self.currentId() == FirstTimePage.Plugins:
return self.get_next_page_id()
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():
while not all([thread.isFinished() for thread in self.theme_screenshot_threads]):
time.sleep(0.1)
self.application.process_events()
# Build the screenshot icons, as this can not be done in the thread.
@ -146,11 +168,20 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
:param screens: The screens detected by OpenLP
"""
self.screens = screens
self.was_cancelled = False
self.theme_screenshot_threads = []
self.theme_screenshot_workers = []
self.has_run_wizard = False
def _download_index(self):
"""
Download the configuration file and kick off the theme screenshot download threads
"""
# check to see if we have web access
self.web_access = False
self.web = 'http://openlp.org/files/frw/'
self.config = ConfigParser()
user_agent = 'OpenLP/' + Registry().get('application').applicationVersion()
self.application.process_events()
web_config = get_web_page('%s%s' % (self.web, 'download.cfg'), header=('User-Agent', user_agent))
if web_config:
files = web_config.read()
@ -165,24 +196,8 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
log.debug('A problem occured while parsing the downloaded config file')
trace_error_handler(log)
self.update_screen_list_combo()
self.was_download_cancelled = False
self.theme_screenshot_thread = None
self.has_run_wizard = False
self.application.process_events()
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)
self.currentIdChanged.connect(self.on_current_id_changed)
Registry().register_function('config_screen_changed', self.update_screen_list_combo)
def set_defaults(self):
"""
Set up display at start of theme edit.
"""
self.restart()
check_directory_exists(os.path.join(gettempdir(), 'openlp'))
self.no_internet_finish_button.setVisible(False)
# Check if this is a re-run of the wizard.
self.has_run_wizard = Settings().value('core/has run wizard')
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())
@ -199,6 +214,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
songs = self.config.get('songs', 'languages')
songs = songs.split(',')
for song in songs:
self.application.process_events()
title = self.config.get('songs_%s' % song, 'title')
filename = self.config.get('songs_%s' % song, 'filename')
item = QtGui.QListWidgetItem(title, self.songs_list_widget)
@ -208,11 +224,13 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
bible_languages = self.config.get('bibles', 'languages')
bible_languages = bible_languages.split(',')
for lang in bible_languages:
self.application.process_events()
language = self.config.get('bibles_%s' % lang, 'title')
lang_item = QtGui.QTreeWidgetItem(self.bibles_tree_widget, [language])
bibles = self.config.get('bibles_%s' % lang, 'translations')
bibles = bibles.split(',')
for bible in bibles:
self.application.process_events()
title = self.config.get('bible_%s' % bible, 'title')
filename = self.config.get('bible_%s' % bible, 'filename')
item = QtGui.QTreeWidgetItem(lang_item, [title])
@ -220,9 +238,38 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
item.setCheckState(0, QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
self.bibles_tree_widget.expandAll()
# Download the theme screenshots.
self.theme_screenshot_thread = ThemeScreenshotThread(self)
self.theme_screenshot_thread.start()
self.application.process_events()
# Download the theme screenshots
themes = self.config.get('themes', 'files').split(',')
for theme in themes:
self.application.process_events()
title = self.config.get('theme_%s' % theme, 'title')
filename = self.config.get('theme_%s' % theme, 'filename')
screenshot = self.config.get('theme_%s' % theme, 'screenshot')
worker = ThemeScreenshotWorker(self.themes_url, title, filename, screenshot)
self.theme_screenshot_workers.append(worker)
worker.screenshot_downloaded.connect(self.on_screenshot_downloaded)
thread = QtCore.QThread(self)
self.theme_screenshot_threads.append(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.moveToThread(thread)
thread.start()
def set_defaults(self):
"""
Set up display at start of theme edit.
"""
self.restart()
self.web = 'http://openlp.org/files/frw/'
self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)
self.currentIdChanged.connect(self.on_current_id_changed)
Registry().register_function('config_screen_changed', self.update_screen_list_combo)
self.no_internet_finish_button.setVisible(False)
# Check if this is a re-run of the wizard.
self.has_run_wizard = Settings().value('core/has run wizard')
check_directory_exists(os.path.join(gettempdir(), 'openlp'))
def update_screen_list_combo(self):
"""
@ -241,12 +288,20 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
self.application.process_events()
if page_id != -1:
self.last_id = page_id
if page_id == FirstTimePage.Plugins:
if page_id == FirstTimePage.Download:
self.back_button.setVisible(False)
self.next_button.setVisible(False)
# Set the no internet page text.
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.cancel_wizard_text)
self.application.set_busy_cursor()
self._download_index()
self.application.set_normal_cursor()
self.back_button.setVisible(False)
self.next_button.setVisible(True)
self.next()
elif page_id == FirstTimePage.Defaults:
self.theme_combo_box.clear()
for index in range(self.themes_list_widget.count()):
@ -266,15 +321,12 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
elif page_id == FirstTimePage.NoInternet:
self.back_button.setVisible(False)
self.next_button.setVisible(False)
self.cancel_button.setVisible(False)
self.no_internet_finish_button.setVisible(True)
if self.has_run_wizard:
self.cancel_button.setVisible(False)
elif page_id == FirstTimePage.Plugins:
self.back_button.setVisible(False)
elif page_id == FirstTimePage.Progress:
self.application.set_busy_cursor()
self.repaint()
self.application.process_events()
# Try to give the wizard a chance to redraw itself
time.sleep(0.2)
self._pre_wizard()
self._perform_wizard()
self._post_wizard()
@ -284,17 +336,28 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
"""
Process the triggering of the cancel button.
"""
if self.last_id == FirstTimePage.NoInternet or \
(self.last_id <= FirstTimePage.Plugins and not self.has_run_wizard):
QtCore.QCoreApplication.exit()
sys.exit()
self.was_download_cancelled = True
self.was_cancelled = True
if self.theme_screenshot_workers:
for worker in self.theme_screenshot_workers:
worker.set_download_canceled(True)
# Was the thread created.
if self.theme_screenshot_thread:
while self.theme_screenshot_thread.isRunning():
if self.theme_screenshot_threads:
while any([thread.isRunning() for thread in self.theme_screenshot_threads]):
time.sleep(0.1)
self.application.set_normal_cursor()
def on_screenshot_downloaded(self, title, filename):
"""
Add an item to the list when a theme has been downloaded
:param title: The title of the theme
:param filename: The filename of the theme
"""
item = QtGui.QListWidgetItem(title, self.themes_list_widget)
item.setData(QtCore.Qt.UserRole, filename)
item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
def on_no_internet_finish_button_clicked(self):
"""
Process the triggering of the "Finish" button on the No Internet page.
@ -321,7 +384,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
url_file = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
filename = open(f_path, "wb")
# Download until finished or canceled.
while not self.was_download_cancelled:
while not self.was_cancelled:
data = url_file.read(block_size)
if not data:
break
@ -341,7 +404,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
continue
break
# Delete file if cancelled, it may be a partial file.
if self.was_download_cancelled:
if self.was_cancelled:
os.remove(f_path)
return True
@ -354,6 +417,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
for index, theme in enumerate(themes):
screenshot = self.config.get('theme_%s' % theme, 'screenshot')
item = self.themes_list_widget.item(index)
# if item:
item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot)))
def _get_file_size(self, url):

View File

@ -41,13 +41,14 @@ class FirstTimePage(object):
An enumeration class with each of the pages of the wizard.
"""
Welcome = 0
Plugins = 1
Download = 1
NoInternet = 2
Songs = 3
Bibles = 4
Themes = 5
Defaults = 6
Progress = 7
Plugins = 3
Songs = 4
Bibles = 5
Themes = 6
Defaults = 7
Progress = 8
class UiFirstTimeWizard(object):
@ -78,6 +79,27 @@ class UiFirstTimeWizard(object):
self.next_button = self.button(QtGui.QWizard.NextButton)
self.back_button = self.button(QtGui.QWizard.BackButton)
add_welcome_page(first_time_wizard, ':/wizards/wizard_firsttime.bmp')
# The download page
self.download_page = QtGui.QWizardPage()
self.download_page.setObjectName('download_page')
self.download_layout = QtGui.QVBoxLayout(self.download_page)
self.download_layout.setMargin(48)
self.download_layout.setObjectName('download_layout')
self.download_label = QtGui.QLabel(self.download_page)
self.download_label.setObjectName('download_label')
self.download_layout.addWidget(self.download_label)
first_time_wizard.setPage(FirstTimePage.Download, self.download_page)
# The "you don't have an internet connection" page.
self.no_internet_page = QtGui.QWizardPage()
self.no_internet_page.setObjectName('no_internet_page')
self.no_internet_layout = QtGui.QVBoxLayout(self.no_internet_page)
self.no_internet_layout.setContentsMargins(50, 30, 50, 40)
self.no_internet_layout.setObjectName('no_internet_layout')
self.no_internet_label = QtGui.QLabel(self.no_internet_page)
self.no_internet_label.setWordWrap(True)
self.no_internet_label.setObjectName('no_internet_label')
self.no_internet_layout.addWidget(self.no_internet_label)
first_time_wizard.setPage(FirstTimePage.NoInternet, self.no_internet_page)
# The plugins page
self.plugin_page = QtGui.QWizardPage()
self.plugin_page.setObjectName('plugin_page')
@ -120,17 +142,6 @@ class UiFirstTimeWizard(object):
self.alert_check_box.setObjectName('alert_check_box')
self.plugin_layout.addWidget(self.alert_check_box)
first_time_wizard.setPage(FirstTimePage.Plugins, self.plugin_page)
# The "you don't have an internet connection" page.
self.no_internet_page = QtGui.QWizardPage()
self.no_internet_page.setObjectName('no_internet_page')
self.no_internet_layout = QtGui.QVBoxLayout(self.no_internet_page)
self.no_internet_layout.setContentsMargins(50, 30, 50, 40)
self.no_internet_layout.setObjectName('no_internet_layout')
self.no_internet_label = QtGui.QLabel(self.no_internet_page)
self.no_internet_label.setWordWrap(True)
self.no_internet_label.setObjectName('no_internet_label')
self.no_internet_layout.addWidget(self.no_internet_label)
first_time_wizard.setPage(FirstTimePage.NoInternet, self.no_internet_page)
# The song samples page
self.songs_page = QtGui.QWizardPage()
self.songs_page.setObjectName('songs_page')
@ -221,6 +232,11 @@ class UiFirstTimeWizard(object):
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
'Click the %s button below to start.') %
clean_button_text(first_time_wizard.buttonText(QtGui.QWizard.NextButton)))
self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index'))
self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is '
'downloaded.'))
self.download_label.setText(translate('OpenLP.FirstTimeWizard', 'Please wait while OpenLP downloads the '
'resource index file...'))
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'))
@ -257,5 +273,8 @@ class UiFirstTimeWizard(object):
'Set up default settings to be used by OpenLP.'))
self.display_label.setText(translate('OpenLP.FirstTimeWizard', 'Default output display:'))
self.theme_label.setText(translate('OpenLP.FirstTimeWizard', 'Select default theme:'))
self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading and Configuring'))
self.progress_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while resources are downloaded '
'and OpenLP is configured.'))
self.progress_label.setText(translate('OpenLP.FirstTimeWizard', 'Starting configuration process...'))
first_time_wizard.setButtonText(QtGui.QWizard.CustomButton1, translate('OpenLP.FirstTimeWizard', 'Finish'))

View File

@ -690,7 +690,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
first_run_wizard = FirstTimeForm(self)
first_run_wizard.initialize(ScreenList())
first_run_wizard.exec_()
if first_run_wizard.was_download_cancelled:
if first_run_wizard.was_cancelled:
return
self.application.set_busy_cursor()
self.first_time()

View File

@ -152,16 +152,19 @@ def set_button_tooltip(bar):
"""
for button in bar.buttons():
if bar.standardButton(button) == QDialogButtonBox.Cancel:
tip = "Ignoring current changes and return to OpenLP"
button.setToolTip(translate('OpenLP.SourceSelectForm',
'Ignoring current changes and return to OpenLP'))
elif bar.standardButton(button) == QDialogButtonBox.Reset:
tip = "Delete all user-defined text and revert to PJLink default text"
button.setToolTip(translate('OpenLP.SourceSelectForm',
'Delete all user-defined text and revert to PJLink default text'))
elif bar.standardButton(button) == QDialogButtonBox.Discard:
tip = "Discard changes and reset to previous user-defined text"
button.setToolTip(translate('OpenLP.SourceSelectForm',
'Discard changes and reset to previous user-defined text'))
elif bar.standardButton(button) == QDialogButtonBox.Ok:
tip = "Save changes and return to OpenLP"
button.setToolTip(translate('OpenLP.SourceSelectForm',
'Save changes and return to OpenLP'))
else:
tip = ""
button.setToolTip(tip)
log.debug('No tooltip for button {}'.format(button.text()))
class FingerTabBarWidget(QTabBar):
@ -237,12 +240,13 @@ class SourceSelectTabs(QDialog):
"""
log.debug('Initializing SourceSelectTabs()')
super(SourceSelectTabs, self).__init__(parent)
self.setMinimumWidth(350)
self.projectordb = projectordb
self.edit = edit
if self.edit:
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
else:
title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text')
else:
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
self.setWindowTitle(title)
self.setObjectName('source_select_tabs')
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
@ -286,6 +290,10 @@ class SourceSelectTabs(QDialog):
thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
if buttonchecked:
self.tabwidget.setCurrentIndex(thistab)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
QtGui.QDialogButtonBox.Discard |
QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
else:
for key in keys:
(tab, button_count, buttonchecked) = Build_Tab(group=self.button_group,
@ -297,10 +305,8 @@ class SourceSelectTabs(QDialog):
thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
if buttonchecked:
self.tabwidget.setCurrentIndex(thistab)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
QtGui.QDialogButtonBox.Discard |
QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
self.button_box.clicked.connect(self.button_clicked)
self.layout.addWidget(self.button_box)
set_button_tooltip(self.button_box)
@ -321,9 +327,9 @@ class SourceSelectTabs(QDialog):
if self.button_box.standardButton(button) == self.button_box.Cancel:
self.done(0)
elif self.button_box.standardButton(button) == self.button_box.Reset:
self.delete_sources()
elif self.button_box.standardButton(button) == self.button_box.Discard:
self.done(100)
elif self.button_box.standardButton(button) == self.button_box.Discard:
self.delete_sources()
elif self.button_box.standardButton(button) == self.button_box.Ok:
return self.accept_me()
else:
@ -331,9 +337,11 @@ class SourceSelectTabs(QDialog):
def delete_sources(self):
msg = QtGui.QMessageBox()
msg.setText('Delete entries for this projector')
msg.setInformativeText('Are you sure you want to delete ALL user-defined '
'source input text for this projector?')
msg.setText(translate('OpenLP.SourceSelectForm', 'Delete entries for this projector'))
msg.setInformativeText(translate('OpenLP.SourceSelectForm',
'Are you sure you want to delete ALL user-defined '),
translate('OpenLP.SourceSelectForm',
'source input text for this projector?'))
msg.setStandardButtons(msg.Cancel | msg.Ok)
msg.setDefaultButton(msg.Cancel)
ans = msg.exec_()
@ -382,7 +390,11 @@ class SourceSelectSingle(QDialog):
log.debug('Initializing SourceSelectSingle()')
self.projectordb = projectordb
super(SourceSelectSingle, self).__init__(parent)
self.setWindowTitle(translate('OpenLP.SourceSelectSingle', 'Select Projector Source'))
self.edit = edit
if self.edit:
title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text')
else:
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
self.setObjectName('source_select_single')
self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png'))
self.setModal(True)
@ -418,6 +430,10 @@ class SourceSelectSingle(QDialog):
item.setText(source_item.text)
self.layout.addRow(PJLINK_DEFAULT_CODES[key], item)
self.button_group.append(item)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
QtGui.QDialogButtonBox.Discard |
QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
else:
for key in keys:
source_text = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id)
@ -427,10 +443,8 @@ class SourceSelectSingle(QDialog):
self.layout.addWidget(button)
self.button_group.addButton(button, int(key))
button_list.append(key)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
QtGui.QDialogButtonBox.Discard |
QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Cancel)
self.button_box.clicked.connect(self.button_clicked)
self.layout.addWidget(self.button_box)
self.setMinimumHeight(key_count*25)
@ -452,9 +466,9 @@ class SourceSelectSingle(QDialog):
if self.button_box.standardButton(button) == self.button_box.Cancel:
self.done(0)
elif self.button_box.standardButton(button) == self.button_box.Reset:
self.delete_sources()
elif self.button_box.standardButton(button) == self.button_box.Discard:
self.done(100)
elif self.button_box.standardButton(button) == self.button_box.Discard:
self.delete_sources()
elif self.button_box.standardButton(button) == self.button_box.Ok:
return self.accept_me()
else:
@ -462,9 +476,11 @@ class SourceSelectSingle(QDialog):
def delete_sources(self):
msg = QtGui.QMessageBox()
msg.setText('Delete entries for this projector')
msg.setInformativeText('Are you sure you want to delete ALL user-defined '
'source input text for this projector?')
msg.setText(translate('OpenLP.SourceSelectForm', 'Delete entries for this projector'))
msg.setInformativeText(translate('OpenLP.SourceSelectForm',
'Are you sure you want to delete ALL user-defined '),
translate('OpenLP.SourceSelectForm',
'source input text for this projector?'))
msg.setStandardButtons(msg.Cancel | msg.Ok)
msg.setDefaultButton(msg.Cancel)
ans = msg.exec_()

View File

@ -96,7 +96,6 @@ class CustomMediaItem(MediaManagerItem):
def retranslateUi(self):
"""
"""
self.search_text_label.setText('%s:' % UiStrings().Search)
self.search_text_button.setText(UiStrings().Search)
@ -134,6 +133,7 @@ class CustomMediaItem(MediaManagerItem):
# Called to redisplay the custom list screen edith from a search
# or from the exit of the Custom edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
self.check_search_result()
def on_new_click(self):
"""
@ -287,10 +287,15 @@ class CustomMediaItem(MediaManagerItem):
log.debug('service_load')
if self.plugin.status != PluginStatus.Active:
return
custom = self.plugin.db_manager.get_object_filtered(CustomSlide, and_(CustomSlide.title == item.title,
CustomSlide.theme_name == item.theme,
CustomSlide.credits ==
item.raw_footer[0][len(item.title) + 1:]))
if item.theme:
custom = self.plugin.db_manager.get_object_filtered(CustomSlide, and_(CustomSlide.title == item.title,
CustomSlide.theme_name == item.theme,
CustomSlide.credits ==
item.raw_footer[0][len(item.title) + 1:]))
else:
custom = self.plugin.db_manager.get_object_filtered(CustomSlide, and_(CustomSlide.title == item.title,
CustomSlide.credits ==
item.raw_footer[0][len(item.title) + 1:]))
if custom:
item.edit_id = custom.id
return item

View File

@ -29,7 +29,6 @@
import logging
import os
from datetime import time
from PyQt4 import QtCore, QtGui
@ -126,18 +125,18 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
Adds buttons to the start of the header bar.
"""
if 'vlc' in get_media_players()[0]:
diable_optical_button_text = False
disable_optical_button_text = False
optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD')
optical_button_tooltip = translate('MediaPlugin.MediaItem', 'Load CD/DVD')
else:
diable_optical_button_text = True
disable_optical_button_text = True
optical_button_text = translate('MediaPlugin.MediaItem', 'Load CD/DVD')
optical_button_tooltip = translate('MediaPlugin.MediaItem',
'Load CD/DVD - only supported when VLC is installed and enabled')
self.load_optical = self.toolbar.add_toolbar_action('load_optical', icon=OPTICAL_ICON, text=optical_button_text,
tooltip=optical_button_tooltip,
triggers=self.on_load_optical)
if diable_optical_button_text:
if disable_optical_button_text:
self.load_optical.setDisabled(True)
def add_end_header_bar(self):
@ -282,7 +281,6 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
Initialize media item.
"""
self.list_view.clear()
self.list_view.setIconSize(QtCore.QSize(88, 50))
self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
check_directory_exists(self.service_path)
self.load_list(Settings().value(self.settings_section + '/media files'))

View File

@ -306,9 +306,9 @@ class HttpRouter(RegistryProperties):
Translate various strings in the mobile app.
"""
self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Stage View'),
'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Live View'),
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Stage View'),
'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Live View'),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),

View File

@ -265,7 +265,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
return False
return True
def _validate_tags(self, tags):
def _validate_tags(self, tags, first_time=True):
"""
Validates a list of tags
Deletes the first affiliated tag pair which is located side by side in the list
@ -277,6 +277,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
:param tags: A list of tags
:return: True if the function can't find any mismatched tags. Else False.
"""
if first_time:
fixed_tags = []
for i in range(len(tags)):
if tags[i] != '{br}':
fixed_tags.append(tags[i])
tags = fixed_tags
if len(tags) == 0:
return True
if len(tags) % 2 != 0:
@ -284,7 +290,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
for i in range(len(tags)-1):
if tags[i+1] == "{/" + tags[i][1:]:
del tags[i:i+2]
return self._validate_tags(tags)
return self._validate_tags(tags, False)
return False
def _process_lyrics(self):

View File

@ -30,6 +30,7 @@
Package to test the openlp.core.ui.firsttimeform package.
"""
from configparser import ConfigParser
import os
from unittest import TestCase
from openlp.core.common import Registry
@ -71,55 +72,117 @@ class TestFirstTimeForm(TestCase, TestMixin):
def setUp(self):
self.setup_application()
self.app.setApplicationVersion('0.0')
# Set up a fake "set_normal_cursor" method since we're not dealing with an actual OpenLP application object
self.app.set_normal_cursor = lambda: None
self.app.process_events = lambda: None
Registry.create()
Registry().register('application', self.app)
def basic_initialise_test(self):
def initialise_test(self):
"""
Test if we can intialise the FirstTimeForm without a config file
Test if we can intialise the FirstTimeForm
"""
# 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
# GIVEN: A First Time Wizard and an expected screen object
frw = FirstTimeForm(None)
expected_screens = MagicMock()
# WHEN: The First Time Wizard is initialised
first_time_form.initialize(expected_screens)
# WHEN: The First Time Wizard is initialised
frw.initialize(expected_screens)
# 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))
# THEN: The screens should be set up, and the default values initialised
self.assertEqual(expected_screens, frw.screens, 'The screens should be correct')
self.assertTrue(frw.web_access, 'The default value of self.web_access should be True')
self.assertFalse(frw.was_cancelled, 'The default value of self.was_cancelled should be False')
self.assertListEqual([], frw.theme_screenshot_threads, 'The list of threads should be empty')
self.assertListEqual([], frw.theme_screenshot_workers, 'The list of workers should be empty')
self.assertFalse(frw.has_run_wizard, 'has_run_wizard should be False')
def config_initialise_test(self):
def set_defaults_test(self):
"""
Test if we can intialise the FirstTimeForm with a config file
Test that the default values are set when set_defaults() is run
"""
# 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
# GIVEN: An initialised FRW and a whole lot of stuff mocked out
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
with patch.object(frw, 'restart') as mocked_restart, \
patch.object(frw, 'cancel_button') as mocked_cancel_button, \
patch.object(frw, 'no_internet_finish_button') as mocked_no_internet_finish_btn, \
patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
patch.object(Registry, 'register_function') as mocked_register_function, \
patch('openlp.core.ui.firsttimeform.Settings') as MockedSettings, \
patch('openlp.core.ui.firsttimeform.gettempdir') as mocked_gettempdir, \
patch('openlp.core.ui.firsttimeform.check_directory_exists') as mocked_check_directory_exists, \
patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
mocked_settings = MagicMock()
mocked_settings.value.return_value = True
MockedSettings.return_value = mocked_settings
mocked_gettempdir.return_value = 'temp'
expected_temp_path = os.path.join('temp', 'openlp')
# WHEN: The First Time Wizard is initialised
first_time_form.initialize(MagicMock())
# WHEN: The set_defaults() method is run
frw.set_defaults()
# 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')
# THEN: The default values should have been set
mocked_restart.assert_called_with()
self.assertEqual('http://openlp.org/files/frw/', frw.web, 'The default URL should be set')
mocked_cancel_button.clicked.connect.assert_called_with(frw.on_cancel_button_clicked)
mocked_no_internet_finish_btn.clicked.connect.assert_called_with(frw.on_no_internet_finish_button_clicked)
mocked_currentIdChanged.connect.assert_called_with(frw.on_current_id_changed)
mocked_register_function.assert_called_with('config_screen_changed', frw.update_screen_list_combo)
mocked_no_internet_finish_btn.setVisible.assert_called_with(False)
mocked_settings.value.assert_called_with('core/has run wizard')
mocked_gettempdir.assert_called_with()
mocked_check_directory_exists.assert_called_with(expected_temp_path)
def update_screen_list_combo_test(self):
"""
Test that the update_screen_list_combo() method works correctly
"""
# GIVEN: A mocked Screen() object and an initialised First Run Wizard and a mocked display_combo_box
expected_screen_list = ['Screen 1', 'Screen 2']
mocked_screens = MagicMock()
mocked_screens.get_screen_list.return_value = expected_screen_list
frw = FirstTimeForm(None)
frw.initialize(mocked_screens)
with patch.object(frw, 'display_combo_box') as mocked_display_combo_box:
mocked_display_combo_box.count.return_value = 2
# WHEN: update_screen_list_combo() is called
frw.update_screen_list_combo()
# THEN: The combobox should have been updated
mocked_display_combo_box.clear.assert_called_with()
mocked_screens.get_screen_list.assert_called_with()
mocked_display_combo_box.addItems.assert_called_with(expected_screen_list)
mocked_display_combo_box.count.assert_called_with()
mocked_display_combo_box.setCurrentIndex.assert_called_with(1)
def on_cancel_button_clicked_test(self):
"""
Test that the cancel button click slot shuts down the threads correctly
"""
# GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff
frw = FirstTimeForm(None)
frw.initialize(MagicMock())
mocked_worker = MagicMock()
mocked_thread = MagicMock()
mocked_thread.isRunning.side_effect = [True, False]
frw.theme_screenshot_workers.append(mocked_worker)
frw.theme_screenshot_threads.append(mocked_thread)
with patch('openlp.core.ui.firsttimeform.time') as mocked_time, \
patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
# WHEN: on_cancel_button_clicked() is called
frw.on_cancel_button_clicked()
# THEN: The right things should be called in the right order
self.assertTrue(frw.was_cancelled, 'The was_cancelled property should have been set to True')
mocked_worker.set_download_canceled.assert_called_with(True)
mocked_thread.isRunning.assert_called_with()
self.assertEqual(2, mocked_thread.isRunning.call_count, 'isRunning() should have been called twice')
mocked_time.sleep.assert_called_with(0.1)
self.assertEqual(1, mocked_time.sleep.call_count, 'sleep() should have only been called once')
mocked_set_normal_cursor.assert_called_with()
def broken_config_test(self):
"""
@ -128,10 +191,11 @@ class TestFirstTimeForm(TestCase, TestMixin):
# GIVEN: A mocked get_web_page, a First Time Wizard, an expected screen object, and a mocked broken config file
with patch('openlp.core.ui.firsttimeform.get_web_page') as mocked_get_web_page:
first_time_form = FirstTimeForm(None)
first_time_form.initialize(MagicMock())
mocked_get_web_page.return_value.read.return_value = FAKE_BROKEN_CONFIG
# WHEN: The First Time Wizard is initialised
first_time_form.initialize(MagicMock())
# WHEN: The First Time Wizard is downloads the config file
first_time_form._download_index()
# THEN: The First Time Form should not have web access
self.assertFalse(first_time_form.web_access, 'There should not be web access with a broken config file')
@ -143,10 +207,11 @@ class TestFirstTimeForm(TestCase, TestMixin):
# GIVEN: A mocked get_web_page, a First Time Wizard, an expected screen object, and a mocked invalid config file
with patch('openlp.core.ui.firsttimeform.get_web_page') as mocked_get_web_page:
first_time_form = FirstTimeForm(None)
first_time_form.initialize(MagicMock())
mocked_get_web_page.return_value.read.return_value = FAKE_INVALID_CONFIG
# WHEN: The First Time Wizard is initialised
first_time_form.initialize(MagicMock())
# WHEN: The First Time Wizard is downloads the config file
first_time_form._download_index()
# THEN: The First Time Form should not have web access
self.assertFalse(first_time_form.web_access, 'There should not be web access with an invalid config file')

View File

@ -382,7 +382,7 @@ class TestUtils(TestCase):
mocked_page_object = MagicMock()
mock_urlopen.return_value = mocked_page_object
fake_url = 'this://is.a.fake/url'
user_agent_header = ('User-Agent', 'OpenLP/2.1.0')
user_agent_header = ('User-Agent', 'OpenLP/2.2.0')
# WHEN: The get_web_page() method is called
returned_page = get_web_page(fake_url, header=user_agent_header)

View File

@ -0,0 +1,28 @@
# -*- 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 #
###############################################################################

View File

@ -0,0 +1,101 @@
"""
This module contains tests for the lib submodule of the Songs plugin.
"""
from unittest import TestCase
from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, Settings
from openlp.core.lib import ServiceItem, PluginStatus
from openlp.plugins.custom.lib import CustomMediaItem
from openlp.plugins.custom.lib.db import CustomSlide
from tests.functional import patch, MagicMock
from tests.helpers.testmixin import TestMixin
FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
class TestMediaItem(TestCase, TestMixin):
"""
Test the functions in the :mod:`lib` module.
"""
def setUp(self):
"""
Set up the components need for all tests.
"""
Registry.create()
Registry().register('service_list', MagicMock())
Registry().register('main_window', MagicMock())
with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
patch('openlp.core.lib.mediamanageritem.MediaManagerItem.setup_item'), \
patch('openlp.plugins.custom.forms.editcustomform.EditCustomForm.__init__'), \
patch('openlp.plugins.custom.lib.mediaitem.CustomMediaItem.setup_item'):
self.media_item = CustomMediaItem(None, MagicMock())
self.setup_application()
self.build_settings()
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
self.destroy_settings()
def service_load_inactive_test(self):
"""
Test the service load in custom with a default service item
"""
# GIVEN: An empty Service Item
service_item = ServiceItem(None)
# WHEN: I search for the custom in the database
item = self.media_item.service_load(service_item)
# THEN: the processing should be ignored
self.assertEqual(item, None, 'The Service item is inactive so processing should be bypassed')
def service_load_basic_custom_false_test(self):
"""
Test the service load in custom with a default service item and no requirement to add to the database
"""
# GIVEN: An empty Service Item and an active plugin
service_item = ServiceItem(None)
service_item.raw_footer = FOOTER
self.media_item.plugin = MagicMock()
self.media_item.plugin.status = PluginStatus.Active
self.media_item.plugin.db_manager = MagicMock()
self.media_item.plugin.db_manager.get_object_filtered = MagicMock()
self.media_item.plugin.db_manager.get_object_filtered.return_value = None
with patch('openlp.plugins.custom.lib.mediaitem.CustomSlide'):
# WHEN: I search for the custom in the database
self.media_item.add_custom_from_service = False
self.media_item.create_from_service_item = MagicMock()
self.media_item.service_load(service_item)
# THEN: the item should not be added to the database.
self.assertEqual(self.media_item.create_from_service_item.call_count, 0,
'The item should not have been added to the database')
def service_load_basic_custom_true_test(self):
"""
Test the service load in custom with a default service item and a requirement to add to the database
"""
# GIVEN: An empty Service Item and an active plugin
service_item = ServiceItem(None)
service_item.raw_footer = FOOTER
self.media_item.plugin = MagicMock()
self.media_item.plugin.status = PluginStatus.Active
self.media_item.plugin.db_manager = MagicMock()
self.media_item.plugin.db_manager.get_object_filtered = MagicMock()
self.media_item.plugin.db_manager.get_object_filtered.return_value = None
with patch('openlp.plugins.custom.lib.mediaitem.CustomSlide'):
# WHEN: I search for the custom in the database
self.media_item.add_custom_from_service = True
self.media_item.create_from_service_item = MagicMock()
self.media_item.service_load(service_item)
# THEN: the item should not be added to the database.
self.assertEqual(self.media_item.create_from_service_item.call_count, 1,
'The item should have been added to the database')

View File

@ -0,0 +1,57 @@
"""
This module contains tests for the lib submodule of the Songs plugin.
"""
from unittest import TestCase
from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, Settings
from openlp.core.lib import ServiceItem
from openlp.plugins.songs.forms.editsongform import EditSongForm
from openlp.plugins.songs.lib.db import AuthorType
from tests.functional import patch, MagicMock
from tests.helpers.testmixin import TestMixin
class TestEditSongForm(TestCase, TestMixin):
"""
Test the functions in the :mod:`lib` module.
"""
def setUp(self):
"""
Set up the components need for all tests.
"""
Registry.create()
Registry().register('service_list', MagicMock())
Registry().register('main_window', MagicMock())
with patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__', return_value=None):
self.edit_song_form = EditSongForm(None, MagicMock(), MagicMock())
self.setup_application()
self.build_settings()
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
self.destroy_settings()
def validate_matching_tags_test(self):
# Given a set of tags
tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{su}', '{/su}']
# WHEN we validate them
valid = self.edit_song_form._validate_tags(tags)
# THEN they should be valid
self.assertTrue(valid, "The tags list should be valid")
def validate_nonmatching_tags_test(self):
# Given a set of tags
tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{br}', '{su}', '{/su}']
# WHEN we validate them
valid = self.edit_song_form._validate_tags(tags)
# THEN they should be valid
self.assertTrue(valid, "The tags list should be valid")

View File

@ -94,11 +94,9 @@ class TestProjectorManager(TestCase, TestMixin):
self.projector_manager.bootstrap_initialise()
self.projector_manager.bootstrap_post_set_up()
# THEN: verify calls to retrieve saved projectors
# THEN: verify calls to retrieve saved projectors and edit page initialized
self.assertEqual(1, self.projector_manager._load_projectors.call_count,
'Initialization should have called load_projectors()')
# THEN: Verify edit page is initialized
self.assertEqual(type(self.projector_manager.projector_form), ProjectorEditForm,
'Initialization should have created a Projector Edit Form')
self.assertIs(self.projector_manager.projectordb,

View File

@ -0,0 +1,79 @@
# -*- 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, Ken Roberts, 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 #
###############################################################################
"""
:mod: `tests.interfaces.openlp_core_ui.test_projectorsourceform` module
Tests for the Projector Source Select form.
"""
import logging
log = logging.getLogger(__name__)
log.debug('test_projectorsourceform loaded')
from unittest import TestCase
from tests.helpers.testmixin import TestMixin
from openlp.core.lib.projector.constants import PJLINK_DEFAULT_CODES, PJLINK_DEFAULT_SOURCES
from openlp.core.ui.projector.sourceselectform import source_group
def build_source_dict():
"""
Builds a source dictionary to verify source_group returns a valid dictionary of dictionary items
:returns: dictionary of valid PJLink source codes grouped by PJLink source group
"""
test_group = {}
for group in PJLINK_DEFAULT_SOURCES.keys():
test_group[group] = {}
for key in PJLINK_DEFAULT_CODES:
test_group[key[0]][key] = PJLINK_DEFAULT_CODES[key]
return test_group
class ProjectorSourceFormTest(TestCase, TestMixin):
"""
Test class for the Projector Source Select form module
"""
def source_dict_test(self):
"""
Test that source list dict returned from sourceselectform module is a valid dict with proper entries
"""
# GIVEN: A list of inputs
codes = []
for item in PJLINK_DEFAULT_CODES.keys():
codes.append(item)
codes.sort()
# WHEN: projector.sourceselectform.source_select() is called
check = source_group(codes, PJLINK_DEFAULT_CODES)
# THEN: return dictionary should match test dictionary
self.assertEquals(check, build_source_dict(),
"Source group dictionary should match test dictionary")