forked from openlp/openlp
merge lastest trunk
This commit is contained in:
commit
31ee3999c0
@ -217,7 +217,9 @@ class Settings(QtCore.QSettings):
|
|||||||
('advanced/default image', 'core/logo file', []), # Default image renamed + moved to general after 2.4.
|
('advanced/default image', 'core/logo file', []), # Default image renamed + moved to general after 2.4.
|
||||||
('shortcuts/escapeItem', 'shortcuts/desktopScreenEnable', []), # Escape item was removed in 2.6.
|
('shortcuts/escapeItem', 'shortcuts/desktopScreenEnable', []), # Escape item was removed in 2.6.
|
||||||
('shortcuts/offlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
|
('shortcuts/offlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
|
||||||
('shortcuts/onlineHelpItem', 'shortcuts/userManualItem', []) # Online and Offline help were combined in 2.6.
|
('shortcuts/onlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
|
||||||
|
('bibles/advanced bible', '', []), # Common bible search widgets combined in 2.6
|
||||||
|
('bibles/quick bible', 'bibles/primary bible', []) # Common bible search widgets combined in 2.6
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -197,14 +197,9 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
|
|||||||
"""
|
"""
|
||||||
# Add the List widget
|
# Add the List widget
|
||||||
self.list_view = ListWidgetWithDnD(self, self.plugin.name)
|
self.list_view = ListWidgetWithDnD(self, self.plugin.name)
|
||||||
self.list_view.setSpacing(1)
|
|
||||||
self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
|
||||||
self.list_view.setAlternatingRowColors(True)
|
|
||||||
self.list_view.setObjectName('{name}ListView'.format(name=self.plugin.name))
|
self.list_view.setObjectName('{name}ListView'.format(name=self.plugin.name))
|
||||||
# Add to page_layout
|
# Add to page_layout
|
||||||
self.page_layout.addWidget(self.list_view)
|
self.page_layout.addWidget(self.list_view)
|
||||||
# define and add the context menu
|
|
||||||
self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
|
||||||
if self.has_edit_icon:
|
if self.has_edit_icon:
|
||||||
create_widget_action(self.list_view,
|
create_widget_action(self.list_view,
|
||||||
text=self.plugin.get_string(StringContent.Edit)['title'],
|
text=self.plugin.get_string(StringContent.Edit)['title'],
|
||||||
|
@ -40,6 +40,11 @@ class ListWidgetWithDnD(QtWidgets.QListWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.mime_data_text = name
|
self.mime_data_text = name
|
||||||
self.no_results_text = UiStrings().NoResults
|
self.no_results_text = UiStrings().NoResults
|
||||||
|
self.setSpacing(1)
|
||||||
|
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
|
self.setAlternatingRowColors(True)
|
||||||
|
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
|
self.locked = False
|
||||||
|
|
||||||
def activateDnD(self):
|
def activateDnD(self):
|
||||||
"""
|
"""
|
||||||
@ -49,13 +54,15 @@ class ListWidgetWithDnD(QtWidgets.QListWidget):
|
|||||||
self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
|
self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
|
||||||
Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
|
Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
|
||||||
|
|
||||||
def clear(self, search_while_typing=False):
|
def clear(self, search_while_typing=False, override_lock=False):
|
||||||
"""
|
"""
|
||||||
Re-implement clear, so that we can customise feedback when using 'Search as you type'
|
Re-implement clear, so that we can customise feedback when using 'Search as you type'
|
||||||
|
|
||||||
:param search_while_typing: True if we want to display the customised message
|
:param search_while_typing: True if we want to display the customised message
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
if self.locked and not override_lock:
|
||||||
|
return
|
||||||
if search_while_typing:
|
if search_while_typing:
|
||||||
self.no_results_text = UiStrings().ShortResults
|
self.no_results_text = UiStrings().ShortResults
|
||||||
else:
|
else:
|
||||||
|
@ -39,7 +39,7 @@ class Ui_SettingsDialog(object):
|
|||||||
"""
|
"""
|
||||||
settings_dialog.setObjectName('settings_dialog')
|
settings_dialog.setObjectName('settings_dialog')
|
||||||
settings_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
|
settings_dialog.setWindowIcon(build_icon(':/icon/openlp-logo.svg'))
|
||||||
settings_dialog.resize(800, 700)
|
settings_dialog.resize(920, 625)
|
||||||
self.dialog_layout = QtWidgets.QGridLayout(settings_dialog)
|
self.dialog_layout = QtWidgets.QGridLayout(settings_dialog)
|
||||||
self.dialog_layout.setObjectName('dialog_layout')
|
self.dialog_layout.setObjectName('dialog_layout')
|
||||||
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
|
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
|
||||||
|
@ -46,8 +46,7 @@ __default_settings__ = {
|
|||||||
'bibles/is verse number visible': True,
|
'bibles/is verse number visible': True,
|
||||||
'bibles/display new chapter': False,
|
'bibles/display new chapter': False,
|
||||||
'bibles/second bibles': True,
|
'bibles/second bibles': True,
|
||||||
'bibles/advanced bible': '',
|
'bibles/primary bible': '',
|
||||||
'bibles/quick bible': '',
|
|
||||||
'bibles/proxy name': '',
|
'bibles/proxy name': '',
|
||||||
'bibles/proxy address': '',
|
'bibles/proxy address': '',
|
||||||
'bibles/proxy username': '',
|
'bibles/proxy username': '',
|
||||||
|
@ -230,7 +230,7 @@ def update_reference_separators():
|
|||||||
REFERENCE_MATCHES['range_separator'] = re.compile(REFERENCE_SEPARATORS['sep_l'], re.UNICODE)
|
REFERENCE_MATCHES['range_separator'] = re.compile(REFERENCE_SEPARATORS['sep_l'], re.UNICODE)
|
||||||
# full reference match: <book>(<range>(,(?!$)|(?=$)))+
|
# full reference match: <book>(<range>(,(?!$)|(?=$)))+
|
||||||
REFERENCE_MATCHES['full'] = \
|
REFERENCE_MATCHES['full'] = \
|
||||||
re.compile('^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*'
|
re.compile('^\s*(?!\s)(?P<book>[\d]*[^\d\.]+)\.*(?<!\s)\s*'
|
||||||
'(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$'
|
'(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$'
|
||||||
% dict(list(REFERENCE_SEPARATORS.items()) + [('range_regex', range_regex)]), re.UNICODE)
|
% dict(list(REFERENCE_SEPARATORS.items()) + [('range_regex', range_regex)]), re.UNICODE)
|
||||||
|
|
||||||
@ -326,7 +326,7 @@ def parse_reference(reference, bible, language_selection, book_ref_id=False):
|
|||||||
|
|
||||||
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
||||||
The ``book`` group starts with the first non-whitespace character. There are optional leading digits followed by
|
The ``book`` group starts with the first non-whitespace character. There are optional leading digits followed by
|
||||||
non-digits. The group ends before the whitspace in front of the next digit.
|
non-digits. The group ends before the whitspace, or a full stop in front of the next digit.
|
||||||
|
|
||||||
``(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$``
|
``(?P<ranges>(?:%(range_regex)s(?:%(sep_l)s(?!\s*$)|(?=\s*$)))+)\s*$``
|
||||||
The second group contains all ``ranges``. This can be multiple declarations of range_regex separated by a list
|
The second group contains all ``ranges``. This can be multiple declarations of range_regex separated by a list
|
||||||
|
@ -36,7 +36,7 @@ from sqlalchemy.orm.exc import UnmappedClassError
|
|||||||
from openlp.core.common import AppLocation, translate, clean_filename
|
from openlp.core.common import AppLocation, translate, clean_filename
|
||||||
from openlp.core.lib.db import BaseModel, init_db, Manager
|
from openlp.core.lib.db import BaseModel, init_db, Manager
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.plugins.bibles.lib import upgrade
|
from openlp.plugins.bibles.lib import BibleStrings, LanguageSelection, upgrade
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -52,9 +52,15 @@ class BibleMeta(BaseModel):
|
|||||||
|
|
||||||
class Book(BaseModel):
|
class Book(BaseModel):
|
||||||
"""
|
"""
|
||||||
Song model
|
Bible Book model
|
||||||
"""
|
"""
|
||||||
pass
|
def get_name(self, language_selection=LanguageSelection.Bible):
|
||||||
|
if language_selection == LanguageSelection.Bible:
|
||||||
|
return self.name
|
||||||
|
elif language_selection == LanguageSelection.Application:
|
||||||
|
return BibleStrings().BookNames[BiblesResourcesDB.get_book_by_id(self.book_reference_id)['abbreviation']]
|
||||||
|
elif language_selection == LanguageSelection.English:
|
||||||
|
return BiblesResourcesDB.get_book_by_id(self.book_reference_id)['name']
|
||||||
|
|
||||||
|
|
||||||
class Verse(BaseModel):
|
class Verse(BaseModel):
|
||||||
@ -380,13 +386,12 @@ class BibleDB(Manager):
|
|||||||
"""
|
"""
|
||||||
log.debug('BibleDB.verse_search("{text}")'.format(text=text))
|
log.debug('BibleDB.verse_search("{text}")'.format(text=text))
|
||||||
verses = self.session.query(Verse)
|
verses = self.session.query(Verse)
|
||||||
# TODO: Find out what this is doing before converting to format()
|
|
||||||
if text.find(',') > -1:
|
if text.find(',') > -1:
|
||||||
keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')]
|
keywords = ['%{keyword}%'.format(keyword=keyword.strip()) for keyword in text.split(',') if keyword.strip()]
|
||||||
or_clause = [Verse.text.like(keyword) for keyword in keywords]
|
or_clause = [Verse.text.like(keyword) for keyword in keywords]
|
||||||
verses = verses.filter(or_(*or_clause))
|
verses = verses.filter(or_(*or_clause))
|
||||||
else:
|
else:
|
||||||
keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(' ')]
|
keywords = ['%{keyword}%'.format(keyword=keyword.strip()) for keyword in text.split(' ') if keyword.strip()]
|
||||||
for keyword in keywords:
|
for keyword in keywords:
|
||||||
verses = verses.filter(Verse.text.like(keyword))
|
verses = verses.filter(Verse.text.like(keyword))
|
||||||
verses = verses.all()
|
verses = verses.all()
|
||||||
|
@ -250,14 +250,20 @@ class BibleManager(OpenLPMixin, RegistryProperties):
|
|||||||
'"{book}", "{chapter}")'.format(bible=bible, book=book_ref_id, chapter=chapter))
|
'"{book}", "{chapter}")'.format(bible=bible, book=book_ref_id, chapter=chapter))
|
||||||
return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
|
return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
|
||||||
|
|
||||||
def get_verses(self, bible, verse_text, book_ref_id=False, show_error=True):
|
def parse_ref(self, bible, reference_text, book_ref_id=False):
|
||||||
|
if not bible:
|
||||||
|
return
|
||||||
|
language_selection = self.get_language_selection(bible)
|
||||||
|
return parse_reference(reference_text, self.db_cache[bible], language_selection, book_ref_id)
|
||||||
|
|
||||||
|
def get_verses(self, bible, ref_list, show_error=True):
|
||||||
"""
|
"""
|
||||||
Parses a scripture reference, fetches the verses from the Bible
|
Parses a scripture reference, fetches the verses from the Bible
|
||||||
specified, and returns a list of ``Verse`` objects.
|
specified, and returns a list of ``Verse`` objects.
|
||||||
|
|
||||||
:param bible: Unicode. The Bible to use.
|
:param bible: Unicode. The Bible to use.
|
||||||
:param verse_text:
|
:param verse_text:
|
||||||
Unicode. The scripture reference. Valid scripture references are:
|
String. The scripture reference. Valid scripture references are:
|
||||||
|
|
||||||
- Genesis 1
|
- Genesis 1
|
||||||
- Genesis 1-2
|
- Genesis 1-2
|
||||||
@ -271,22 +277,9 @@ class BibleManager(OpenLPMixin, RegistryProperties):
|
|||||||
For second bible this is necessary.
|
For second bible this is necessary.
|
||||||
:param show_error:
|
:param show_error:
|
||||||
"""
|
"""
|
||||||
# If no bibles are installed, message is given.
|
if not bible or not ref_list:
|
||||||
log.debug('BibleManager.get_verses("{bible}", "{verse}")'.format(bible=bible, verse=verse_text))
|
|
||||||
if not bible:
|
|
||||||
if show_error:
|
|
||||||
self.main_window.information_message(
|
|
||||||
UiStrings().BibleNoBiblesTitle,
|
|
||||||
UiStrings().BibleNoBibles)
|
|
||||||
return None
|
|
||||||
# Get the language for books.
|
|
||||||
language_selection = self.get_language_selection(bible)
|
|
||||||
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
|
||||||
if ref_list:
|
|
||||||
return self.db_cache[bible].get_verses(ref_list, show_error)
|
|
||||||
# If nothing is found. Message is given if this is not combined search. (defined in mediaitem.py)
|
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
return self.db_cache[bible].get_verses(ref_list, show_error)
|
||||||
|
|
||||||
def get_language_selection(self, bible):
|
def get_language_selection(self, bible):
|
||||||
"""
|
"""
|
||||||
@ -308,7 +301,7 @@ class BibleManager(OpenLPMixin, RegistryProperties):
|
|||||||
language_selection = LanguageSelection.Application
|
language_selection = LanguageSelection.Application
|
||||||
return language_selection
|
return language_selection
|
||||||
|
|
||||||
def verse_search(self, bible, second_bible, text):
|
def verse_search(self, bible, text):
|
||||||
"""
|
"""
|
||||||
Does a verse search for the given bible and text.
|
Does a verse search for the given bible and text.
|
||||||
|
|
||||||
@ -325,20 +318,14 @@ class BibleManager(OpenLPMixin, RegistryProperties):
|
|||||||
return None
|
return None
|
||||||
# Check if the bible or second_bible is a web bible.
|
# Check if the bible or second_bible is a web bible.
|
||||||
web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source')
|
web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source')
|
||||||
second_web_bible = ''
|
if web_bible:
|
||||||
if second_bible:
|
|
||||||
second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source')
|
|
||||||
if web_bible or second_web_bible:
|
|
||||||
# If either Bible is Web, cursor is reset to normal and message is given.
|
# If either Bible is Web, cursor is reset to normal and message is given.
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used in Text Search'),
|
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used in Text Search'),
|
||||||
translate('BiblesPlugin.BibleManager', 'Text Search is not available with Web Bibles.\n'
|
translate('BiblesPlugin.BibleManager', 'Text Search is not available with Web Bibles.\n'
|
||||||
'Please use the Scripture Reference Search instead.\n\n'
|
'Please use the Scripture Reference Search instead.\n\n'
|
||||||
'This means that the currently used Bible\nor Second Bible '
|
'This means that the currently selected Bible is a Web Bible.')
|
||||||
'is installed as Web Bible.\n\n'
|
|
||||||
'If you were trying to perform a Reference search\nin Combined '
|
|
||||||
'Search, your reference is invalid.')
|
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
# Shorter than 3 char searches break OpenLP with very long search times, thus they are blocked.
|
# Shorter than 3 char searches break OpenLP with very long search times, thus they are blocked.
|
||||||
@ -380,6 +367,20 @@ class BibleManager(OpenLPMixin, RegistryProperties):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def process_verse_range(self, book_ref_id, chapter_from, verse_from, chapter_to, verse_to):
|
||||||
|
verse_ranges = []
|
||||||
|
for chapter in range(chapter_from, chapter_to + 1):
|
||||||
|
if chapter == chapter_from:
|
||||||
|
start_verse = verse_from
|
||||||
|
else:
|
||||||
|
start_verse = 1
|
||||||
|
if chapter == chapter_to:
|
||||||
|
end_verse = verse_to
|
||||||
|
else:
|
||||||
|
end_verse = -1
|
||||||
|
verse_ranges.append((book_ref_id, chapter, start_verse, end_verse))
|
||||||
|
return verse_ranges
|
||||||
|
|
||||||
def save_meta_data(self, bible, version, copyright, permissions, full_license, book_name_language=None):
|
def save_meta_data(self, bible, version, copyright, permissions, full_license, book_name_language=None):
|
||||||
"""
|
"""
|
||||||
Saves the bibles meta data.
|
Saves the bibles meta data.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -111,14 +111,9 @@ class OpenLPServer(RegistryProperties):
|
|||||||
self.address = address
|
self.address = address
|
||||||
self.is_secure = Settings().value(self.settings_section + '/https enabled')
|
self.is_secure = Settings().value(self.settings_section + '/https enabled')
|
||||||
self.needs_authentication = Settings().value(self.settings_section + '/authentication enabled')
|
self.needs_authentication = Settings().value(self.settings_section + '/authentication enabled')
|
||||||
if self.is_secure:
|
port = Settings().value(self.settings_section + '/port')
|
||||||
port = Settings().value(self.settings_section + '/https port')
|
self.port = port
|
||||||
self.port = port
|
self.start_server_instance(address, port, ThreadingHTTPServer)
|
||||||
self.start_server_instance(address, port, HTTPSServer)
|
|
||||||
else:
|
|
||||||
port = Settings().value(self.settings_section + '/port')
|
|
||||||
self.port = port
|
|
||||||
self.start_server_instance(address, port, ThreadingHTTPServer)
|
|
||||||
if hasattr(self, 'httpd') and self.httpd:
|
if hasattr(self, 'httpd') and self.httpd:
|
||||||
self.httpd.serve_forever()
|
self.httpd.serve_forever()
|
||||||
else:
|
else:
|
||||||
@ -158,19 +153,3 @@ class OpenLPServer(RegistryProperties):
|
|||||||
self.http_thread.stop()
|
self.http_thread.stop()
|
||||||
self.httpd = None
|
self.httpd = None
|
||||||
log.debug('Stopped the server.')
|
log.debug('Stopped the server.')
|
||||||
|
|
||||||
|
|
||||||
class HTTPSServer(HTTPServer):
|
|
||||||
def __init__(self, address, handler):
|
|
||||||
"""
|
|
||||||
Initialise the secure handlers for the SSL server if required.s
|
|
||||||
"""
|
|
||||||
BaseServer.__init__(self, address, handler)
|
|
||||||
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
|
||||||
self.socket = ssl.SSLSocket(
|
|
||||||
sock=socket.socket(self.address_family, self.socket_type),
|
|
||||||
certfile=os.path.join(local_data, 'remotes', 'openlp.crt'),
|
|
||||||
keyfile=os.path.join(local_data, 'remotes', 'openlp.key'),
|
|
||||||
server_side=True)
|
|
||||||
self.server_bind()
|
|
||||||
self.server_activate()
|
|
||||||
|
@ -94,48 +94,6 @@ class RemoteTab(SettingsTab):
|
|||||||
self.live_url.setOpenExternalLinks(True)
|
self.live_url.setOpenExternalLinks(True)
|
||||||
self.http_setting_layout.addRow(self.live_url_label, self.live_url)
|
self.http_setting_layout.addRow(self.live_url_label, self.live_url)
|
||||||
self.left_layout.addWidget(self.http_settings_group_box)
|
self.left_layout.addWidget(self.http_settings_group_box)
|
||||||
self.https_settings_group_box = QtWidgets.QGroupBox(self.left_column)
|
|
||||||
self.https_settings_group_box.setCheckable(True)
|
|
||||||
self.https_settings_group_box.setChecked(False)
|
|
||||||
self.https_settings_group_box.setObjectName('https_settings_group_box')
|
|
||||||
self.https_settings_layout = QtWidgets.QFormLayout(self.https_settings_group_box)
|
|
||||||
self.https_settings_layout.setObjectName('https_settings_layout')
|
|
||||||
self.https_error_label = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.https_error_label.setVisible(False)
|
|
||||||
self.https_error_label.setWordWrap(True)
|
|
||||||
self.https_error_label.setObjectName('https_error_label')
|
|
||||||
self.https_settings_layout.addRow(self.https_error_label)
|
|
||||||
self.https_port_label = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.https_port_label.setObjectName('https_port_label')
|
|
||||||
self.https_port_spin_box = QtWidgets.QSpinBox(self.https_settings_group_box)
|
|
||||||
self.https_port_spin_box.setMaximum(32767)
|
|
||||||
self.https_port_spin_box.setObjectName('https_port_spin_box')
|
|
||||||
self.https_settings_layout.addRow(self.https_port_label, self.https_port_spin_box)
|
|
||||||
self.remote_https_url = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.remote_https_url.setObjectName('remote_http_url')
|
|
||||||
self.remote_https_url.setOpenExternalLinks(True)
|
|
||||||
self.remote_https_url_label = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.remote_https_url_label.setObjectName('remote_http_url_label')
|
|
||||||
self.https_settings_layout.addRow(self.remote_https_url_label, self.remote_https_url)
|
|
||||||
self.stage_https_url_label = QtWidgets.QLabel(self.http_settings_group_box)
|
|
||||||
self.stage_https_url_label.setObjectName('stage_https_url_label')
|
|
||||||
self.stage_https_url = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.stage_https_url.setObjectName('stage_https_url')
|
|
||||||
self.stage_https_url.setOpenExternalLinks(True)
|
|
||||||
self.https_settings_layout.addRow(self.stage_https_url_label, self.stage_https_url)
|
|
||||||
self.chords_https_url_label = QtWidgets.QLabel(self.http_settings_group_box)
|
|
||||||
self.chords_https_url_label.setObjectName('chords_https_url_label')
|
|
||||||
self.chords_https_url = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.chords_https_url.setObjectName('chords_https_url')
|
|
||||||
self.chords_https_url.setOpenExternalLinks(True)
|
|
||||||
self.https_settings_layout.addRow(self.chords_https_url_label, self.chords_https_url)
|
|
||||||
self.live_https_url_label = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.live_https_url_label.setObjectName('live_url_label')
|
|
||||||
self.live_https_url = QtWidgets.QLabel(self.https_settings_group_box)
|
|
||||||
self.live_https_url.setObjectName('live_https_url')
|
|
||||||
self.live_https_url.setOpenExternalLinks(True)
|
|
||||||
self.https_settings_layout.addRow(self.live_https_url_label, self.live_https_url)
|
|
||||||
self.left_layout.addWidget(self.https_settings_group_box)
|
|
||||||
self.user_login_group_box = QtWidgets.QGroupBox(self.left_column)
|
self.user_login_group_box = QtWidgets.QGroupBox(self.left_column)
|
||||||
self.user_login_group_box.setCheckable(True)
|
self.user_login_group_box.setCheckable(True)
|
||||||
self.user_login_group_box.setChecked(False)
|
self.user_login_group_box.setChecked(False)
|
||||||
@ -189,8 +147,6 @@ class RemoteTab(SettingsTab):
|
|||||||
self.thumbnails_check_box.stateChanged.connect(self.on_thumbnails_check_box_changed)
|
self.thumbnails_check_box.stateChanged.connect(self.on_thumbnails_check_box_changed)
|
||||||
self.address_edit.textChanged.connect(self.set_urls)
|
self.address_edit.textChanged.connect(self.set_urls)
|
||||||
self.port_spin_box.valueChanged.connect(self.set_urls)
|
self.port_spin_box.valueChanged.connect(self.set_urls)
|
||||||
self.https_port_spin_box.valueChanged.connect(self.set_urls)
|
|
||||||
self.https_settings_group_box.clicked.connect(self.https_changed)
|
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings'))
|
self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings'))
|
||||||
@ -213,15 +169,6 @@ class RemoteTab(SettingsTab):
|
|||||||
translate('RemotePlugin.RemoteTab',
|
translate('RemotePlugin.RemoteTab',
|
||||||
'Scan the QR code or click <a href="{qr}">download</a> to install the iOS app from the App '
|
'Scan the QR code or click <a href="{qr}">download</a> to install the iOS app from the App '
|
||||||
'Store.').format(qr='https://itunes.apple.com/app/id1096218725'))
|
'Store.').format(qr='https://itunes.apple.com/app/id1096218725'))
|
||||||
self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server'))
|
|
||||||
self.https_error_label.setText(
|
|
||||||
translate('RemotePlugin.RemoteTab', 'Could not find an SSL certificate. The HTTPS server will not be '
|
|
||||||
'available unless an SSL certificate is found. Please see the manual for more information.'))
|
|
||||||
self.https_port_label.setText(self.port_label.text())
|
|
||||||
self.remote_https_url_label.setText(self.remote_url_label.text())
|
|
||||||
self.stage_https_url_label.setText(self.stage_url_label.text())
|
|
||||||
self.chords_https_url_label.setText(self.chords_url_label.text())
|
|
||||||
self.live_https_url_label.setText(self.live_url_label.text())
|
|
||||||
self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication'))
|
self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication'))
|
||||||
self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:'))
|
self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:'))
|
||||||
self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:'))
|
self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:'))
|
||||||
@ -232,21 +179,11 @@ class RemoteTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
ip_address = self.get_ip_address(self.address_edit.text())
|
ip_address = self.get_ip_address(self.address_edit.text())
|
||||||
http_url = 'http://{url}:{text}/'.format(url=ip_address, text=self.port_spin_box.value())
|
http_url = 'http://{url}:{text}/'.format(url=ip_address, text=self.port_spin_box.value())
|
||||||
https_url = 'https://{url}:{text}/'.format(url=ip_address, text=self.https_port_spin_box.value())
|
|
||||||
self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
|
self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
|
||||||
self.remote_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url))
|
|
||||||
http_url_temp = http_url + 'stage'
|
http_url_temp = http_url + 'stage'
|
||||||
https_url_temp = https_url + 'stage'
|
|
||||||
self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
||||||
self.stage_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
|
|
||||||
http_url_temp = http_url + 'chords'
|
|
||||||
https_url_temp = https_url + 'chords'
|
|
||||||
self.chords_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
|
||||||
self.chords_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
|
|
||||||
http_url_temp = http_url + 'main'
|
http_url_temp = http_url + 'main'
|
||||||
https_url_temp = https_url + 'main'
|
|
||||||
self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
|
||||||
self.live_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
|
|
||||||
|
|
||||||
def get_ip_address(self, ip_address):
|
def get_ip_address(self, ip_address):
|
||||||
"""
|
"""
|
||||||
@ -272,43 +209,25 @@ class RemoteTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
Load the configuration and update the server configuration if necessary
|
Load the configuration and update the server configuration if necessary
|
||||||
"""
|
"""
|
||||||
self.is_secure = Settings().value(self.settings_section + '/https enabled')
|
|
||||||
self.port_spin_box.setValue(Settings().value(self.settings_section + '/port'))
|
self.port_spin_box.setValue(Settings().value(self.settings_section + '/port'))
|
||||||
self.https_port_spin_box.setValue(Settings().value(self.settings_section + '/https port'))
|
|
||||||
self.address_edit.setText(Settings().value(self.settings_section + '/ip address'))
|
self.address_edit.setText(Settings().value(self.settings_section + '/ip address'))
|
||||||
self.twelve_hour = Settings().value(self.settings_section + '/twelve hour')
|
self.twelve_hour = Settings().value(self.settings_section + '/twelve hour')
|
||||||
self.twelve_hour_check_box.setChecked(self.twelve_hour)
|
self.twelve_hour_check_box.setChecked(self.twelve_hour)
|
||||||
self.thumbnails = Settings().value(self.settings_section + '/thumbnails')
|
self.thumbnails = Settings().value(self.settings_section + '/thumbnails')
|
||||||
self.thumbnails_check_box.setChecked(self.thumbnails)
|
self.thumbnails_check_box.setChecked(self.thumbnails)
|
||||||
local_data = AppLocation.get_directory(AppLocation.DataDir)
|
|
||||||
if not os.path.exists(os.path.join(local_data, 'remotes', 'openlp.crt')) or \
|
|
||||||
not os.path.exists(os.path.join(local_data, 'remotes', 'openlp.key')):
|
|
||||||
self.https_settings_group_box.setChecked(False)
|
|
||||||
self.https_settings_group_box.setEnabled(False)
|
|
||||||
self.https_error_label.setVisible(True)
|
|
||||||
else:
|
|
||||||
self.https_settings_group_box.setChecked(Settings().value(self.settings_section + '/https enabled'))
|
|
||||||
self.https_settings_group_box.setEnabled(True)
|
|
||||||
self.https_error_label.setVisible(False)
|
|
||||||
self.user_login_group_box.setChecked(Settings().value(self.settings_section + '/authentication enabled'))
|
self.user_login_group_box.setChecked(Settings().value(self.settings_section + '/authentication enabled'))
|
||||||
self.user_id.setText(Settings().value(self.settings_section + '/user id'))
|
self.user_id.setText(Settings().value(self.settings_section + '/user id'))
|
||||||
self.password.setText(Settings().value(self.settings_section + '/password'))
|
self.password.setText(Settings().value(self.settings_section + '/password'))
|
||||||
self.set_urls()
|
self.set_urls()
|
||||||
self.https_changed()
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
Save the configuration and update the server configuration if necessary
|
Save the configuration and update the server configuration if necessary
|
||||||
"""
|
"""
|
||||||
if Settings().value(self.settings_section + '/ip address') != self.address_edit.text() or \
|
if Settings().value(self.settings_section + '/ip address') != self.address_edit.text() or \
|
||||||
Settings().value(self.settings_section + '/port') != self.port_spin_box.value() or \
|
Settings().value(self.settings_section + '/port') != self.port_spin_box.value():
|
||||||
Settings().value(self.settings_section + '/https port') != self.https_port_spin_box.value() or \
|
|
||||||
Settings().value(self.settings_section + '/https enabled') != \
|
|
||||||
self.https_settings_group_box.isChecked():
|
|
||||||
self.settings_form.register_post_process('remotes_config_updated')
|
self.settings_form.register_post_process('remotes_config_updated')
|
||||||
Settings().setValue(self.settings_section + '/port', self.port_spin_box.value())
|
Settings().setValue(self.settings_section + '/port', self.port_spin_box.value())
|
||||||
Settings().setValue(self.settings_section + '/https port', self.https_port_spin_box.value())
|
|
||||||
Settings().setValue(self.settings_section + '/https enabled', self.https_settings_group_box.isChecked())
|
|
||||||
Settings().setValue(self.settings_section + '/ip address', self.address_edit.text())
|
Settings().setValue(self.settings_section + '/ip address', self.address_edit.text())
|
||||||
Settings().setValue(self.settings_section + '/twelve hour', self.twelve_hour)
|
Settings().setValue(self.settings_section + '/twelve hour', self.twelve_hour)
|
||||||
Settings().setValue(self.settings_section + '/thumbnails', self.thumbnails)
|
Settings().setValue(self.settings_section + '/thumbnails', self.thumbnails)
|
||||||
@ -335,12 +254,6 @@ class RemoteTab(SettingsTab):
|
|||||||
if check_state == QtCore.Qt.Checked:
|
if check_state == QtCore.Qt.Checked:
|
||||||
self.thumbnails = True
|
self.thumbnails = True
|
||||||
|
|
||||||
def https_changed(self):
|
|
||||||
"""
|
|
||||||
Invert the HTTP group box based on Https group settings
|
|
||||||
"""
|
|
||||||
self.http_settings_group_box.setEnabled(not self.https_settings_group_box.isChecked())
|
|
||||||
|
|
||||||
def generate_icon(self):
|
def generate_icon(self):
|
||||||
"""
|
"""
|
||||||
Generate icon for main window
|
Generate icon for main window
|
||||||
@ -348,12 +261,6 @@ class RemoteTab(SettingsTab):
|
|||||||
self.remote_server_icon.hide()
|
self.remote_server_icon.hide()
|
||||||
icon = QtGui.QImage(':/remote/network_server.png')
|
icon = QtGui.QImage(':/remote/network_server.png')
|
||||||
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
||||||
if self.is_secure:
|
|
||||||
overlay = QtGui.QImage(':/remote/network_ssl.png')
|
|
||||||
overlay = overlay.scaled(60, 60, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
|
||||||
painter = QtGui.QPainter(icon)
|
|
||||||
painter.drawImage(0, 0, overlay)
|
|
||||||
painter.end()
|
|
||||||
if Settings().value(self.settings_section + '/authentication enabled'):
|
if Settings().value(self.settings_section + '/authentication enabled'):
|
||||||
overlay = QtGui.QImage(':/remote/network_auth.png')
|
overlay = QtGui.QImage(':/remote/network_auth.png')
|
||||||
overlay = overlay.scaled(60, 60, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
overlay = overlay.scaled(60, 60, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
||||||
|
@ -124,7 +124,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
cache.append(obj.name)
|
cache.append(obj.name)
|
||||||
combo.setItemData(row, obj.id)
|
combo.setItemData(row, obj.id)
|
||||||
set_case_insensitive_completer(cache, combo)
|
set_case_insensitive_completer(cache, combo)
|
||||||
combo.setEditText('')
|
combo.setCurrentIndex(-1)
|
||||||
|
combo.setCurrentText('')
|
||||||
|
|
||||||
def _add_author_to_list(self, author, author_type):
|
def _add_author_to_list(self, author, author_type):
|
||||||
"""
|
"""
|
||||||
@ -367,7 +368,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
self.authors_combo_box.setItemData(row, author.id)
|
self.authors_combo_box.setItemData(row, author.id)
|
||||||
self.authors.append(author.display_name)
|
self.authors.append(author.display_name)
|
||||||
set_case_insensitive_completer(self.authors, self.authors_combo_box)
|
set_case_insensitive_completer(self.authors, self.authors_combo_box)
|
||||||
self.authors_combo_box.setEditText('')
|
self.authors_combo_box.setCurrentIndex(-1)
|
||||||
|
self.authors_combo_box.setCurrentText('')
|
||||||
|
|
||||||
# Types
|
# Types
|
||||||
self.author_types_combo_box.clear()
|
self.author_types_combo_box.clear()
|
||||||
@ -402,7 +404,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
self.themes.sort(key=get_theme_key)
|
self.themes.sort(key=get_theme_key)
|
||||||
self.theme_combo_box.addItems(theme_list)
|
self.theme_combo_box.addItems(theme_list)
|
||||||
set_case_insensitive_completer(self.themes, self.theme_combo_box)
|
set_case_insensitive_completer(self.themes, self.theme_combo_box)
|
||||||
self.theme_combo_box.setEditText('')
|
self.theme_combo_box.setCurrentIndex(-1)
|
||||||
|
self.theme_combo_box.setCurrentText('')
|
||||||
|
|
||||||
def load_media_files(self):
|
def load_media_files(self):
|
||||||
"""
|
"""
|
||||||
@ -441,7 +444,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
self.load_topics()
|
self.load_topics()
|
||||||
self.load_songbooks()
|
self.load_songbooks()
|
||||||
self.load_media_files()
|
self.load_media_files()
|
||||||
self.theme_combo_box.setEditText('')
|
self.theme_combo_box.setCurrentIndex(-1)
|
||||||
|
self.theme_combo_box.setCurrentText('')
|
||||||
# it's a new song to preview is not possible
|
# it's a new song to preview is not possible
|
||||||
self.preview_button.setVisible(False)
|
self.preview_button.setVisible(False)
|
||||||
|
|
||||||
@ -466,8 +470,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
find_and_set_in_combo_box(self.theme_combo_box, str(self.song.theme_name))
|
find_and_set_in_combo_box(self.theme_combo_box, str(self.song.theme_name))
|
||||||
else:
|
else:
|
||||||
# Clear the theme combo box in case it was previously set (bug #1212801)
|
# Clear the theme combo box in case it was previously set (bug #1212801)
|
||||||
self.theme_combo_box.setEditText('')
|
self.theme_combo_box.setCurrentIndex(-1)
|
||||||
self.theme_combo_box.setCurrentIndex(0)
|
self.theme_combo_box.setCurrentText('')
|
||||||
self.copyright_edit.setText(self.song.copyright if self.song.copyright else '')
|
self.copyright_edit.setText(self.song.copyright if self.song.copyright else '')
|
||||||
self.comments_edit.setPlainText(self.song.comments if self.song.comments else '')
|
self.comments_edit.setPlainText(self.song.comments if self.song.comments else '')
|
||||||
self.ccli_number_edit.setText(self.song.ccli_number if self.song.ccli_number else '')
|
self.ccli_number_edit.setText(self.song.ccli_number if self.song.ccli_number else '')
|
||||||
@ -570,12 +574,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
item = int(self.authors_combo_box.currentIndex())
|
item = int(self.authors_combo_box.currentIndex())
|
||||||
text = self.authors_combo_box.currentText().strip(' \r\n\t')
|
text = self.authors_combo_box.currentText().strip(' \r\n\t')
|
||||||
author_type = self.author_types_combo_box.itemData(self.author_types_combo_box.currentIndex())
|
author_type = self.author_types_combo_box.itemData(self.author_types_combo_box.currentIndex())
|
||||||
# This if statement is for OS X, which doesn't seem to work well with
|
if item == -1 and text:
|
||||||
# the QCompleter auto-completion class. See bug #812628.
|
|
||||||
if text in self.authors:
|
|
||||||
# Index 0 is a blank string, so add 1
|
|
||||||
item = self.authors.index(text) + 1
|
|
||||||
if item == 0 and text:
|
|
||||||
if QtWidgets.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self,
|
self,
|
||||||
translate('SongsPlugin.EditSongForm', 'Add Author'),
|
translate('SongsPlugin.EditSongForm', 'Add Author'),
|
||||||
@ -590,10 +589,11 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
self.manager.save_object(author)
|
self.manager.save_object(author)
|
||||||
self._add_author_to_list(author, author_type)
|
self._add_author_to_list(author, author_type)
|
||||||
self.load_authors()
|
self.load_authors()
|
||||||
self.authors_combo_box.setEditText('')
|
self.authors_combo_box.setCurrentIndex(-1)
|
||||||
|
self.authors_combo_box.setCurrentText('')
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
elif item > 0:
|
elif item >= 0:
|
||||||
item_id = (self.authors_combo_box.itemData(item))
|
item_id = (self.authors_combo_box.itemData(item))
|
||||||
author = self.manager.get_object(Author, item_id)
|
author = self.manager.get_object(Author, item_id)
|
||||||
if self.authors_list_view.findItems(author.get_display_name(author_type), QtCore.Qt.MatchExactly):
|
if self.authors_list_view.findItems(author.get_display_name(author_type), QtCore.Qt.MatchExactly):
|
||||||
@ -601,7 +601,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
message=translate('SongsPlugin.EditSongForm', 'This author is already in the list.'))
|
message=translate('SongsPlugin.EditSongForm', 'This author is already in the list.'))
|
||||||
else:
|
else:
|
||||||
self._add_author_to_list(author, author_type)
|
self._add_author_to_list(author, author_type)
|
||||||
self.authors_combo_box.setEditText('')
|
self.authors_combo_box.setCurrentIndex(-1)
|
||||||
|
self.authors_combo_box.setCurrentText('')
|
||||||
else:
|
else:
|
||||||
QtWidgets.QMessageBox.warning(
|
QtWidgets.QMessageBox.warning(
|
||||||
self, UiStrings().NISs,
|
self, UiStrings().NISs,
|
||||||
@ -653,7 +654,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
def on_topic_add_button_clicked(self):
|
def on_topic_add_button_clicked(self):
|
||||||
item = int(self.topics_combo_box.currentIndex())
|
item = int(self.topics_combo_box.currentIndex())
|
||||||
text = self.topics_combo_box.currentText()
|
text = self.topics_combo_box.currentText()
|
||||||
if item == 0 and text:
|
if item == -1 and text:
|
||||||
if QtWidgets.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self, translate('SongsPlugin.EditSongForm', 'Add Topic'),
|
self, translate('SongsPlugin.EditSongForm', 'Add Topic'),
|
||||||
translate('SongsPlugin.EditSongForm', 'This topic does not exist, do you want to add it?'),
|
translate('SongsPlugin.EditSongForm', 'This topic does not exist, do you want to add it?'),
|
||||||
@ -665,10 +666,11 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
||||||
self.topics_list_view.addItem(topic_item)
|
self.topics_list_view.addItem(topic_item)
|
||||||
self.load_topics()
|
self.load_topics()
|
||||||
self.topics_combo_box.setEditText('')
|
self.topics_combo_box.setCurrentIndex(-1)
|
||||||
|
self.topics_combo_box.setCurrentText('')
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
elif item > 0:
|
elif item >= 0:
|
||||||
item_id = (self.topics_combo_box.itemData(item))
|
item_id = (self.topics_combo_box.itemData(item))
|
||||||
topic = self.manager.get_object(Topic, item_id)
|
topic = self.manager.get_object(Topic, item_id)
|
||||||
if self.topics_list_view.findItems(str(topic.name), QtCore.Qt.MatchExactly):
|
if self.topics_list_view.findItems(str(topic.name), QtCore.Qt.MatchExactly):
|
||||||
@ -678,7 +680,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
topic_item = QtWidgets.QListWidgetItem(str(topic.name))
|
topic_item = QtWidgets.QListWidgetItem(str(topic.name))
|
||||||
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
topic_item.setData(QtCore.Qt.UserRole, topic.id)
|
||||||
self.topics_list_view.addItem(topic_item)
|
self.topics_list_view.addItem(topic_item)
|
||||||
self.topics_combo_box.setEditText('')
|
self.topics_combo_box.setCurrentIndex(-1)
|
||||||
|
self.topics_combo_box.setCurrentText('')
|
||||||
else:
|
else:
|
||||||
QtWidgets.QMessageBox.warning(
|
QtWidgets.QMessageBox.warning(
|
||||||
self, UiStrings().NISs,
|
self, UiStrings().NISs,
|
||||||
@ -698,7 +701,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
def on_songbook_add_button_clicked(self):
|
def on_songbook_add_button_clicked(self):
|
||||||
item = int(self.songbooks_combo_box.currentIndex())
|
item = int(self.songbooks_combo_box.currentIndex())
|
||||||
text = self.songbooks_combo_box.currentText()
|
text = self.songbooks_combo_box.currentText()
|
||||||
if item == 0 and text:
|
if item == -1 and text:
|
||||||
if QtWidgets.QMessageBox.question(
|
if QtWidgets.QMessageBox.question(
|
||||||
self, translate('SongsPlugin.EditSongForm', 'Add Songbook'),
|
self, translate('SongsPlugin.EditSongForm', 'Add Songbook'),
|
||||||
translate('SongsPlugin.EditSongForm', 'This Songbook does not exist, do you want to add it?'),
|
translate('SongsPlugin.EditSongForm', 'This Songbook does not exist, do you want to add it?'),
|
||||||
@ -708,11 +711,12 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
self.manager.save_object(songbook)
|
self.manager.save_object(songbook)
|
||||||
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
||||||
self.load_songbooks()
|
self.load_songbooks()
|
||||||
self.songbooks_combo_box.setEditText('')
|
self.songbooks_combo_box.setCurrentIndex(-1)
|
||||||
|
self.songbooks_combo_box.setCurrentText('')
|
||||||
self.songbook_entry_edit.clear()
|
self.songbook_entry_edit.clear()
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
elif item > 0:
|
elif item >= 0:
|
||||||
item_id = (self.songbooks_combo_box.itemData(item))
|
item_id = (self.songbooks_combo_box.itemData(item))
|
||||||
songbook = self.manager.get_object(Book, item_id)
|
songbook = self.manager.get_object(Book, item_id)
|
||||||
if self.songbooks_list_view.findItems(str(songbook.name), QtCore.Qt.MatchExactly):
|
if self.songbooks_list_view.findItems(str(songbook.name), QtCore.Qt.MatchExactly):
|
||||||
@ -720,7 +724,8 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
|
|||||||
message=translate('SongsPlugin.EditSongForm', 'This Songbook is already in the list.'))
|
message=translate('SongsPlugin.EditSongForm', 'This Songbook is already in the list.'))
|
||||||
else:
|
else:
|
||||||
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
self.add_songbook_entry_to_list(songbook.id, songbook.name, self.songbook_entry_edit.text())
|
||||||
self.songbooks_combo_box.setEditText('')
|
self.songbooks_combo_box.setCurrentIndex(-1)
|
||||||
|
self.songbooks_combo_box.setCurrentText('')
|
||||||
self.songbook_entry_edit.clear()
|
self.songbook_entry_edit.clear()
|
||||||
else:
|
else:
|
||||||
QtWidgets.QMessageBox.warning(
|
QtWidgets.QMessageBox.warning(
|
||||||
|
0
openlp/plugins/songs/forms/songselectform.py
Executable file → Normal file
0
openlp/plugins/songs/forms/songselectform.py
Executable file → Normal file
BIN
resources/images/bibles_book_sort.png
Normal file
BIN
resources/images/bibles_book_sort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 632 B |
@ -29,6 +29,7 @@
|
|||||||
<file>image_new_group.png</file>
|
<file>image_new_group.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="bibles">
|
<qresource prefix="bibles">
|
||||||
|
<file>bibles_book_sort.png</file>
|
||||||
<file>bibles_search_combined.png</file>
|
<file>bibles_search_combined.png</file>
|
||||||
<file>bibles_search_text.png</file>
|
<file>bibles_search_text.png</file>
|
||||||
<file>bibles_search_reference.png</file>
|
<file>bibles_search_reference.png</file>
|
||||||
|
@ -151,3 +151,17 @@ class TestSettingsForm(TestCase):
|
|||||||
# THEN: The general tab's cancel() method should have been called, but not the themes tab
|
# THEN: The general tab's cancel() method should have been called, but not the themes tab
|
||||||
mocked_general_cancel.assert_called_with()
|
mocked_general_cancel.assert_called_with()
|
||||||
self.assertEqual(0, mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called')
|
self.assertEqual(0, mocked_theme_cancel.call_count, 'The Themes tab\'s cancel() should not have been called')
|
||||||
|
|
||||||
|
def test_register_post_process(self):
|
||||||
|
"""
|
||||||
|
Test that the register_post_process() method works correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: A settings form instance
|
||||||
|
settings_form = SettingsForm(None)
|
||||||
|
fake_function = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: register_post_process() is called
|
||||||
|
settings_form.register_post_process(fake_function)
|
||||||
|
|
||||||
|
# THEN: The fake function should be in the settings form's list
|
||||||
|
assert fake_function in settings_form.processes
|
||||||
|
@ -33,6 +33,37 @@ class TestListWidgetWithDnD(TestCase):
|
|||||||
"""
|
"""
|
||||||
Test the :class:`~openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD` class
|
Test the :class:`~openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD` class
|
||||||
"""
|
"""
|
||||||
|
def test_clear_locked(self):
|
||||||
|
"""
|
||||||
|
Test the clear method the list is 'locked'
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.clear') as mocked_clear_super_method:
|
||||||
|
# GIVEN: An instance of ListWidgetWithDnD
|
||||||
|
widget = ListWidgetWithDnD()
|
||||||
|
|
||||||
|
# WHEN: The list is 'locked' and clear has been called
|
||||||
|
widget.locked = True
|
||||||
|
widget.clear()
|
||||||
|
|
||||||
|
# THEN: The super method should not have been called (i.e. The list not cleared)
|
||||||
|
self.assertFalse(mocked_clear_super_method.called)
|
||||||
|
|
||||||
|
def test_clear_overide_locked(self):
|
||||||
|
"""
|
||||||
|
Test the clear method the list is 'locked', but clear is called with 'override_lock' set to True
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.clear') as mocked_clear_super_method:
|
||||||
|
# GIVEN: An instance of ListWidgetWithDnD
|
||||||
|
widget = ListWidgetWithDnD()
|
||||||
|
|
||||||
|
# WHEN: The list is 'locked' and clear has been called with override_lock se to True
|
||||||
|
widget.locked = True
|
||||||
|
widget.clear(override_lock=True)
|
||||||
|
|
||||||
|
# THEN: The super method should have been called (i.e. The list is cleared regardless whether it is locked
|
||||||
|
# or not)
|
||||||
|
mocked_clear_super_method.assert_called_once_with()
|
||||||
|
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
"""
|
"""
|
||||||
Test the clear method when called without any arguments.
|
Test the clear method when called without any arguments.
|
||||||
|
@ -25,11 +25,12 @@ This module contains tests for the lib submodule of the Bibles plugin.
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from openlp.plugins.bibles import lib
|
from openlp.plugins.bibles import lib
|
||||||
from openlp.plugins.bibles.lib import SearchResults
|
from openlp.plugins.bibles.lib import SearchResults, get_reference_match
|
||||||
from tests.functional import patch
|
from tests.functional import MagicMock, patch
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
class TestLib(TestCase):
|
class TestLib(TestCase, TestMixin):
|
||||||
"""
|
"""
|
||||||
Test the functions in the :mod:`lib` module.
|
Test the functions in the :mod:`lib` module.
|
||||||
"""
|
"""
|
||||||
@ -60,6 +61,142 @@ class TestLib(TestCase):
|
|||||||
self.assertEqual(separators[key], value)
|
self.assertEqual(separators[key], value)
|
||||||
mocked_update_reference_separators.assert_called_once_with()
|
mocked_update_reference_separators.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_reference_matched_full(self):
|
||||||
|
"""
|
||||||
|
Test that the 'full' regex parses bible verse references correctly.
|
||||||
|
"""
|
||||||
|
# GIVEN: Some test data which contains different references to parse, with the expected results.
|
||||||
|
with patch('openlp.plugins.bibles.lib.Settings', return_value=MagicMock(**{'value.return_value': ''})):
|
||||||
|
# The following test data tests with 222 variants when using the default 'separators'
|
||||||
|
test_data = [
|
||||||
|
# Input reference, book name, chapter + verse reference
|
||||||
|
('Psalm 23', 'Psalm', '23'),
|
||||||
|
('Psalm. 23', 'Psalm', '23'),
|
||||||
|
('Psalm 23{to}24', 'Psalm', '23-24'),
|
||||||
|
('Psalm 23{verse}1{to}2', 'Psalm', '23:1-2'),
|
||||||
|
('Psalm 23{verse}1{to}{end}', 'Psalm', '23:1-end'),
|
||||||
|
('Psalm 23{verse}1{to}2{_and}5{to}6', 'Psalm', '23:1-2,5-6'),
|
||||||
|
('Psalm 23{verse}1{to}2{_and}5{to}{end}', 'Psalm', '23:1-2,5-end'),
|
||||||
|
('Psalm 23{verse}1{to}2{_and}24{verse}1{to}3', 'Psalm', '23:1-2,24:1-3'),
|
||||||
|
('Psalm 23{verse}1{to}{end}{_and}24{verse}1{to}{end}', 'Psalm', '23:1-end,24:1-end'),
|
||||||
|
('Psalm 23{verse}1{to}24{verse}1', 'Psalm', '23:1-24:1'),
|
||||||
|
('Psalm 23{_and}24', 'Psalm', '23,24'),
|
||||||
|
('1 John 23', '1 John', '23'),
|
||||||
|
('1 John. 23', '1 John', '23'),
|
||||||
|
('1 John 23{to}24', '1 John', '23-24'),
|
||||||
|
('1 John 23{verse}1{to}2', '1 John', '23:1-2'),
|
||||||
|
('1 John 23{verse}1{to}{end}', '1 John', '23:1-end'),
|
||||||
|
('1 John 23{verse}1{to}2{_and}5{to}6', '1 John', '23:1-2,5-6'),
|
||||||
|
('1 John 23{verse}1{to}2{_and}5{to}{end}', '1 John', '23:1-2,5-end'),
|
||||||
|
('1 John 23{verse}1{to}2{_and}24{verse}1{to}3', '1 John', '23:1-2,24:1-3'),
|
||||||
|
('1 John 23{verse}1{to}{end}{_and}24{verse}1{to}{end}', '1 John', '23:1-end,24:1-end'),
|
||||||
|
('1 John 23{verse}1{to}24{verse}1', '1 John', '23:1-24:1'),
|
||||||
|
('1 John 23{_and}24', '1 John', '23,24')]
|
||||||
|
|
||||||
|
full_reference_match = get_reference_match('full')
|
||||||
|
for reference_text, book_result, ranges_result in test_data:
|
||||||
|
to_separators = ['-', ' - ', 'to', ' to '] if '{to}' in reference_text else ['']
|
||||||
|
verse_separators = [':', ' : ', 'v', ' v ', 'V', ' V ', 'verse', ' verse ', 'verses', ' verses '] \
|
||||||
|
if '{verse}' in reference_text else ['']
|
||||||
|
and_separators = [',', ' , ', 'and', ' and '] if '{_and}' in reference_text else ['']
|
||||||
|
end_separators = ['end', ' end '] if '{end}' in reference_text else ['']
|
||||||
|
|
||||||
|
for to in to_separators:
|
||||||
|
for verse in verse_separators:
|
||||||
|
for _and in and_separators:
|
||||||
|
for end in end_separators:
|
||||||
|
reference_text = reference_text.format(to=to, verse=verse, _and=_and, end=end)
|
||||||
|
|
||||||
|
# WHEN: Attempting to parse the input string
|
||||||
|
match = full_reference_match.match(reference_text)
|
||||||
|
|
||||||
|
# THEN: A match should be returned, and the book and reference should match the
|
||||||
|
# expected result
|
||||||
|
self.assertIsNotNone(match, '{text} should provide a match'.format(text=reference_text))
|
||||||
|
self.assertEqual(book_result, match.group('book'),
|
||||||
|
'{text} does not provide the expected result for the book group.'
|
||||||
|
.format(text=reference_text))
|
||||||
|
self.assertEqual(ranges_result, match.group('ranges'),
|
||||||
|
'{text} does not provide the expected result for the ranges group.'
|
||||||
|
.format(text=reference_text))
|
||||||
|
|
||||||
|
def test_reference_matched_range(self):
|
||||||
|
"""
|
||||||
|
Test that the 'range' regex parses bible verse references correctly.
|
||||||
|
Note: This test takes in to account that the regex does not work quite as expected!
|
||||||
|
see https://bugs.launchpad.net/openlp/+bug/1638620
|
||||||
|
"""
|
||||||
|
# GIVEN: Some test data which contains different references to parse, with the expected results.
|
||||||
|
with patch('openlp.plugins.bibles.lib.Settings', return_value=MagicMock(**{'value.return_value': ''})):
|
||||||
|
# The following test data tests with 45 variants when using the default 'separators'
|
||||||
|
test_data = [
|
||||||
|
('23', None, '23', None, None, None),
|
||||||
|
('23{to}24', None, '23', '-24', None, '24'),
|
||||||
|
('23{verse}1{to}2', '23', '1', '-2', None, '2'),
|
||||||
|
('23{verse}1{to}{end}', '23', '1', '-end', None, None),
|
||||||
|
('23{verse}1{to}24{verse}1', '23', '1', '-24:1', '24', '1')]
|
||||||
|
full_reference_match = get_reference_match('range')
|
||||||
|
for reference_text, from_chapter, from_verse, range_to, to_chapter, to_verse in test_data:
|
||||||
|
to_separators = ['-', ' - ', 'to', ' to '] if '{to}' in reference_text else ['']
|
||||||
|
verse_separators = [':', ' : ', 'v', ' v ', 'V', ' V ', 'verse', ' verse ', 'verses', ' verses '] \
|
||||||
|
if '{verse}' in reference_text else ['']
|
||||||
|
and_separators = [',', ' , ', 'and', ' and '] if '{_and}' in reference_text else ['']
|
||||||
|
end_separators = ['end', ' end '] if '{end}' in reference_text else ['']
|
||||||
|
|
||||||
|
for to in to_separators:
|
||||||
|
for verse in verse_separators:
|
||||||
|
for _and in and_separators:
|
||||||
|
for end in end_separators:
|
||||||
|
reference_text = reference_text.format(to=to, verse=verse, _and=_and, end=end)
|
||||||
|
|
||||||
|
# WHEN: Attempting to parse the input string
|
||||||
|
match = full_reference_match.match(reference_text)
|
||||||
|
|
||||||
|
# THEN: A match should be returned, and the to/from chapter/verses should match as
|
||||||
|
# expected
|
||||||
|
self.assertIsNotNone(match, '{text} should provide a match'.format(text=reference_text))
|
||||||
|
self.assertEqual(match.group('from_chapter'), from_chapter)
|
||||||
|
self.assertEqual(match.group('from_verse'), from_verse)
|
||||||
|
self.assertEqual(match.group('range_to'), range_to)
|
||||||
|
self.assertEqual(match.group('to_chapter'), to_chapter)
|
||||||
|
self.assertEqual(match.group('to_verse'), to_verse)
|
||||||
|
|
||||||
|
def test_reference_matched_range_separator(self):
|
||||||
|
# GIVEN: Some test data which contains different references to parse, with the expected results.
|
||||||
|
with patch('openlp.plugins.bibles.lib.Settings', return_value=MagicMock(**{'value.return_value': ''})):
|
||||||
|
# The following test data tests with 111 variants when using the default 'separators'
|
||||||
|
# The regex for handling ranges is a bit screwy, see https://bugs.launchpad.net/openlp/+bug/1638620
|
||||||
|
test_data = [
|
||||||
|
('23', ['23']),
|
||||||
|
('23{to}24', ['23-24']),
|
||||||
|
('23{verse}1{to}2', ['23:1-2']),
|
||||||
|
('23{verse}1{to}{end}', ['23:1-end']),
|
||||||
|
('23{verse}1{to}2{_and}5{to}6', ['23:1-2', '5-6']),
|
||||||
|
('23{verse}1{to}2{_and}5{to}{end}', ['23:1-2', '5-end']),
|
||||||
|
('23{verse}1{to}2{_and}24{verse}1{to}3', ['23:1-2', '24:1-3']),
|
||||||
|
('23{verse}1{to}{end}{_and}24{verse}1{to}{end}', ['23:1-end', '24:1-end']),
|
||||||
|
('23{verse}1{to}24{verse}1', ['23:1-24:1']),
|
||||||
|
('23,24', ['23', '24'])]
|
||||||
|
full_reference_match = get_reference_match('range_separator')
|
||||||
|
for reference_text, ranges in test_data:
|
||||||
|
to_separators = ['-', ' - ', 'to', ' to '] if '{to}' in reference_text else ['']
|
||||||
|
verse_separators = [':', ' : ', 'v', ' v ', 'V', ' V ', 'verse', ' verse ', 'verses', ' verses '] \
|
||||||
|
if '{verse}' in reference_text else ['']
|
||||||
|
and_separators = [',', ' , ', 'and', ' and '] if '{_and}' in reference_text else ['']
|
||||||
|
end_separators = ['end', ' end '] if '{end}' in reference_text else ['']
|
||||||
|
|
||||||
|
for to in to_separators:
|
||||||
|
for verse in verse_separators:
|
||||||
|
for _and in and_separators:
|
||||||
|
for end in end_separators:
|
||||||
|
reference_text = reference_text.format(to=to, verse=verse, _and=_and, end=end)
|
||||||
|
|
||||||
|
# WHEN: Attempting to parse the input string
|
||||||
|
references = full_reference_match.split(reference_text)
|
||||||
|
|
||||||
|
# THEN: The list of references should be as the expected results
|
||||||
|
self.assertEqual(references, ranges)
|
||||||
|
|
||||||
def test_search_results_creation(self):
|
def test_search_results_creation(self):
|
||||||
"""
|
"""
|
||||||
Test the creation and construction of the SearchResults class
|
Test the creation and construction of the SearchResults class
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,8 +37,6 @@ from tests.helpers.testmixin import TestMixin
|
|||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
'remotes/twelve hour': True,
|
'remotes/twelve hour': True,
|
||||||
'remotes/port': 4316,
|
'remotes/port': 4316,
|
||||||
'remotes/https port': 4317,
|
|
||||||
'remotes/https enabled': False,
|
|
||||||
'remotes/user id': 'openlp',
|
'remotes/user id': 'openlp',
|
||||||
'remotes/password': 'password',
|
'remotes/password': 'password',
|
||||||
'remotes/authentication enabled': False,
|
'remotes/authentication enabled': False,
|
||||||
@ -85,7 +83,6 @@ class TestRemoteTab(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
Test the get_ip_address function with given ip address
|
Test the get_ip_address function with given ip address
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked location
|
|
||||||
# GIVEN: An ip address
|
# GIVEN: An ip address
|
||||||
given_ip = '192.168.1.1'
|
given_ip = '192.168.1.1'
|
||||||
# WHEN: the default ip address is given
|
# WHEN: the default ip address is given
|
||||||
@ -114,36 +111,24 @@ class TestRemoteTab(TestCase, TestMixin):
|
|||||||
self.form.set_urls()
|
self.form.set_urls()
|
||||||
# THEN: the following screen values should be set
|
# THEN: the following screen values should be set
|
||||||
self.assertEqual(self.form.address_edit.text(), ZERO_URL, 'The default URL should be set on the screen')
|
self.assertEqual(self.form.address_edit.text(), ZERO_URL, 'The default URL should be set on the screen')
|
||||||
self.assertEqual(self.form.https_settings_group_box.isEnabled(), False,
|
|
||||||
'The Https box should not be enabled')
|
|
||||||
self.assertEqual(self.form.https_settings_group_box.isChecked(), False,
|
|
||||||
'The Https checked box should note be Checked')
|
|
||||||
self.assertEqual(self.form.user_login_group_box.isChecked(), False,
|
self.assertEqual(self.form.user_login_group_box.isChecked(), False,
|
||||||
'The authentication box should not be enabled')
|
'The authentication box should not be enabled')
|
||||||
|
|
||||||
def test_set_certificate_urls(self):
|
def test_set_urls(self):
|
||||||
"""
|
"""
|
||||||
Test the set_urls function with certificate available
|
Test the set_url function to generate correct url links
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked location
|
# GIVEN: An ip address
|
||||||
with patch('openlp.core.common.Settings') as mocked_class, \
|
self.form.address_edit.setText('192.168.1.1')
|
||||||
patch('openlp.core.common.applocation.AppLocation.get_directory') as mocked_get_directory, \
|
# WHEN: the urls are generated
|
||||||
patch('openlp.core.common.check_directory_exists') as mocked_check_directory_exists, \
|
self.form.set_urls()
|
||||||
patch('openlp.core.common.applocation.os') as mocked_os:
|
# THEN: the following links are returned
|
||||||
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
self.assertEqual(self.form.remote_url.text(),
|
||||||
mocked_settings = mocked_class.return_value
|
"<a href=\"http://192.168.1.1:4316/\">http://192.168.1.1:4316/</a>",
|
||||||
mocked_settings.contains.return_value = False
|
'The return value should be a fully formed link')
|
||||||
mocked_get_directory.return_value = TEST_PATH
|
self.assertEqual(self.form.stage_url.text(),
|
||||||
mocked_check_directory_exists.return_value = True
|
"<a href=\"http://192.168.1.1:4316/stage\">http://192.168.1.1:4316/stage</a>",
|
||||||
mocked_os.path.normpath.return_value = TEST_PATH
|
'The return value should be a fully formed stage link')
|
||||||
|
self.assertEqual(self.form.live_url.text(),
|
||||||
# WHEN: when the set_urls is called having reloaded the form.
|
"<a href=\"http://192.168.1.1:4316/main\">http://192.168.1.1:4316/main</a>",
|
||||||
self.form.load()
|
'The return value should be a fully formed main link')
|
||||||
self.form.set_urls()
|
|
||||||
# THEN: the following screen values should be set
|
|
||||||
self.assertEqual(self.form.http_settings_group_box.isEnabled(), True,
|
|
||||||
'The Http group box should be enabled')
|
|
||||||
self.assertEqual(self.form.https_settings_group_box.isChecked(), False,
|
|
||||||
'The Https checked box should be Checked')
|
|
||||||
self.assertEqual(self.form.https_settings_group_box.isEnabled(), True,
|
|
||||||
'The Https box should be enabled')
|
|
||||||
|
@ -35,8 +35,6 @@ from tests.helpers.testmixin import TestMixin
|
|||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
'remotes/twelve hour': True,
|
'remotes/twelve hour': True,
|
||||||
'remotes/port': 4316,
|
'remotes/port': 4316,
|
||||||
'remotes/https port': 4317,
|
|
||||||
'remotes/https enabled': False,
|
|
||||||
'remotes/user id': 'openlp',
|
'remotes/user id': 'openlp',
|
||||||
'remotes/password': 'password',
|
'remotes/password': 'password',
|
||||||
'remotes/authentication enabled': False,
|
'remotes/authentication enabled': False,
|
||||||
|
@ -106,4 +106,5 @@ class TestEditSongForm(TestCase, TestMixin):
|
|||||||
mocked_cache.append.assert_called_once_with('Charles')
|
mocked_cache.append.assert_called_once_with('Charles')
|
||||||
mocked_combo.setItemData.assert_called_once_with(0, 1)
|
mocked_combo.setItemData.assert_called_once_with(0, 1)
|
||||||
mocked_set_case_insensitive_completer.assert_called_once_with(mocked_cache, mocked_combo)
|
mocked_set_case_insensitive_completer.assert_called_once_with(mocked_cache, mocked_combo)
|
||||||
mocked_combo.setEditText.assert_called_once_with('')
|
mocked_combo.setCurrentIndex.assert_called_once_with(-1)
|
||||||
|
mocked_combo.setCurrentText.assert_called_once_with('')
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
Package to test the openlp.plugins.songs.forms.authorsform package.
|
Package to test the openlp.plugins.songs.forms.authorsform package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
@ -138,3 +139,217 @@ class TestAuthorsForm(TestCase, TestMixin):
|
|||||||
|
|
||||||
# THEN: The display_name_edit should have the correct value
|
# THEN: The display_name_edit should have the correct value
|
||||||
self.assertEqual(self.form.display_edit.text(), display_name, 'The display name should be set correctly')
|
self.assertEqual(self.form.display_edit.text(), display_name, 'The display name should be set correctly')
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.QtWidgets.QDialog.exec')
|
||||||
|
def test_exec(self, mocked_exec):
|
||||||
|
"""
|
||||||
|
Test the exec() method
|
||||||
|
"""
|
||||||
|
# GIVEN: An authors for and various mocked objects
|
||||||
|
with patch.object(self.form.first_name_edit, 'clear') as mocked_first_name_edit_clear, \
|
||||||
|
patch.object(self.form.last_name_edit, 'clear') as mocked_last_name_edit_clear, \
|
||||||
|
patch.object(self.form.display_edit, 'clear') as mocked_display_edit_clear, \
|
||||||
|
patch.object(self.form.first_name_edit, 'setFocus') as mocked_first_name_edit_setFocus:
|
||||||
|
# WHEN: The exec() method is called
|
||||||
|
self.form.exec(clear=True)
|
||||||
|
|
||||||
|
# THEN: The clear and exec() methods should have been called
|
||||||
|
mocked_first_name_edit_clear.assert_called_once_with()
|
||||||
|
mocked_last_name_edit_clear.assert_called_once_with()
|
||||||
|
mocked_display_edit_clear.assert_called_once_with()
|
||||||
|
mocked_first_name_edit_setFocus.assert_called_once_with()
|
||||||
|
mocked_exec.assert_called_once_with(self.form)
|
||||||
|
|
||||||
|
def test_first_name_edited(self):
|
||||||
|
"""
|
||||||
|
Test the on_first_name_edited() method
|
||||||
|
"""
|
||||||
|
# GIVEN: An author form
|
||||||
|
self.form.auto_display_name = True
|
||||||
|
|
||||||
|
with patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setText') as mocked_display_edit_setText:
|
||||||
|
mocked_last_name_edit_text.return_value = 'Newton'
|
||||||
|
|
||||||
|
# WHEN: on_first_name_edited() is called
|
||||||
|
self.form.on_first_name_edited('John')
|
||||||
|
|
||||||
|
# THEN: The display name should be updated
|
||||||
|
assert mocked_last_name_edit_text.call_count == 2
|
||||||
|
mocked_display_edit_setText.assert_called_once_with('John Newton')
|
||||||
|
|
||||||
|
def test_first_name_edited_no_auto(self):
|
||||||
|
"""
|
||||||
|
Test the on_first_name_edited() method without auto_display_name
|
||||||
|
"""
|
||||||
|
# GIVEN: An author form
|
||||||
|
self.form.auto_display_name = False
|
||||||
|
|
||||||
|
with patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setText') as mocked_display_edit_setText:
|
||||||
|
|
||||||
|
# WHEN: on_first_name_edited() is called
|
||||||
|
self.form.on_first_name_edited('John')
|
||||||
|
|
||||||
|
# THEN: The display name should not be updated
|
||||||
|
assert mocked_last_name_edit_text.call_count == 0
|
||||||
|
assert mocked_display_edit_setText.call_count == 0
|
||||||
|
|
||||||
|
def test_last_name_edited(self):
|
||||||
|
"""
|
||||||
|
Test the on_last_name_edited() method
|
||||||
|
"""
|
||||||
|
# GIVEN: An author form
|
||||||
|
self.form.auto_display_name = True
|
||||||
|
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setText') as mocked_display_edit_setText:
|
||||||
|
mocked_first_name_edit_text.return_value = 'John'
|
||||||
|
|
||||||
|
# WHEN: on_last_name_edited() is called
|
||||||
|
self.form.on_last_name_edited('Newton')
|
||||||
|
|
||||||
|
# THEN: The display name should be updated
|
||||||
|
assert mocked_first_name_edit_text.call_count == 2
|
||||||
|
mocked_display_edit_setText.assert_called_once_with('John Newton')
|
||||||
|
|
||||||
|
def test_last_name_edited_no_auto(self):
|
||||||
|
"""
|
||||||
|
Test the on_last_name_edited() method without auto_display_name
|
||||||
|
"""
|
||||||
|
# GIVEN: An author form
|
||||||
|
self.form.auto_display_name = False
|
||||||
|
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setText') as mocked_display_edit_setText:
|
||||||
|
|
||||||
|
# WHEN: on_last_name_edited() is called
|
||||||
|
self.form.on_last_name_edited('Newton')
|
||||||
|
|
||||||
|
# THEN: The display name should not be updated
|
||||||
|
assert mocked_first_name_edit_text.call_count == 0
|
||||||
|
assert mocked_display_edit_setText.call_count == 0
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.critical_error_message_box')
|
||||||
|
def test_accept_no_first_name(self, mocked_critical_error):
|
||||||
|
"""
|
||||||
|
Test the accept() method with no first name
|
||||||
|
"""
|
||||||
|
# GIVEN: A form and no text in thefirst name edit
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.first_name_edit, 'setFocus') as mocked_first_name_edit_setFocus:
|
||||||
|
mocked_first_name_edit_text.return_value = ''
|
||||||
|
|
||||||
|
# WHEN: accept() is called
|
||||||
|
result = self.form.accept()
|
||||||
|
|
||||||
|
# THEN: The result should be false and a critical error displayed
|
||||||
|
assert result is False
|
||||||
|
mocked_critical_error.assert_called_once_with(message='You need to type in the first name of the author.')
|
||||||
|
mocked_first_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_first_name_edit_setFocus.assert_called_once_with()
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.critical_error_message_box')
|
||||||
|
def test_accept_no_last_name(self, mocked_critical_error):
|
||||||
|
"""
|
||||||
|
Test the accept() method with no last name
|
||||||
|
"""
|
||||||
|
# GIVEN: A form and no text in the last name edit
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.last_name_edit, 'setFocus') as mocked_last_name_edit_setFocus:
|
||||||
|
mocked_first_name_edit_text.return_value = 'John'
|
||||||
|
mocked_last_name_edit_text.return_value = ''
|
||||||
|
|
||||||
|
# WHEN: accept() is called
|
||||||
|
result = self.form.accept()
|
||||||
|
|
||||||
|
# THEN: The result should be false and a critical error displayed
|
||||||
|
assert result is False
|
||||||
|
mocked_critical_error.assert_called_once_with(message='You need to type in the last name of the author.')
|
||||||
|
mocked_first_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_last_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_last_name_edit_setFocus.assert_called_once_with()
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.critical_error_message_box')
|
||||||
|
def test_accept_no_display_name_no_combine(self, mocked_critical_error):
|
||||||
|
"""
|
||||||
|
Test the accept() method with no display name and no combining
|
||||||
|
"""
|
||||||
|
# GIVEN: A form and no text in the display name edit
|
||||||
|
mocked_critical_error.return_value = QtWidgets.QMessageBox.No
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'text') as mocked_display_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setFocus') as mocked_display_edit_setFocus:
|
||||||
|
mocked_first_name_edit_text.return_value = 'John'
|
||||||
|
mocked_last_name_edit_text.return_value = 'Newton'
|
||||||
|
mocked_display_edit_text.return_value = ''
|
||||||
|
|
||||||
|
# WHEN: accept() is called
|
||||||
|
result = self.form.accept()
|
||||||
|
|
||||||
|
# THEN: The result should be false and a critical error displayed
|
||||||
|
assert result is False
|
||||||
|
mocked_critical_error.assert_called_once_with(
|
||||||
|
message='You have not set a display name for the author, combine the first and last names?',
|
||||||
|
parent=self.form, question=True)
|
||||||
|
mocked_first_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_last_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_display_edit_text.assert_called_once_with()
|
||||||
|
mocked_display_edit_setFocus.assert_called_once_with()
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.critical_error_message_box')
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.QtWidgets.QDialog.accept')
|
||||||
|
def test_accept_no_display_name(self, mocked_accept, mocked_critical_error):
|
||||||
|
"""
|
||||||
|
Test the accept() method with no display name and auto-combine
|
||||||
|
"""
|
||||||
|
# GIVEN: A form and no text in the display name edit
|
||||||
|
mocked_accept.return_value = True
|
||||||
|
mocked_critical_error.return_value = QtWidgets.QMessageBox.Yes
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'text') as mocked_display_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'setText') as mocked_display_edit_setText:
|
||||||
|
mocked_first_name_edit_text.return_value = 'John'
|
||||||
|
mocked_last_name_edit_text.return_value = 'Newton'
|
||||||
|
mocked_display_edit_text.return_value = ''
|
||||||
|
|
||||||
|
# WHEN: accept() is called
|
||||||
|
result = self.form.accept()
|
||||||
|
|
||||||
|
# THEN: The result should be false and a critical error displayed
|
||||||
|
assert result is True
|
||||||
|
mocked_critical_error.assert_called_once_with(
|
||||||
|
message='You have not set a display name for the author, combine the first and last names?',
|
||||||
|
parent=self.form, question=True)
|
||||||
|
assert mocked_first_name_edit_text.call_count == 2
|
||||||
|
assert mocked_last_name_edit_text.call_count == 2
|
||||||
|
mocked_display_edit_text.assert_called_once_with()
|
||||||
|
mocked_display_edit_setText.assert_called_once_with('John Newton')
|
||||||
|
mocked_accept.assert_called_once_with(self.form)
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.forms.authorsform.QtWidgets.QDialog.accept')
|
||||||
|
def test_accept(self, mocked_accept):
|
||||||
|
"""
|
||||||
|
Test the accept() method
|
||||||
|
"""
|
||||||
|
# GIVEN: A form and text in the right places
|
||||||
|
mocked_accept.return_value = True
|
||||||
|
with patch.object(self.form.first_name_edit, 'text') as mocked_first_name_edit_text, \
|
||||||
|
patch.object(self.form.last_name_edit, 'text') as mocked_last_name_edit_text, \
|
||||||
|
patch.object(self.form.display_edit, 'text') as mocked_display_edit_text:
|
||||||
|
mocked_first_name_edit_text.return_value = 'John'
|
||||||
|
mocked_last_name_edit_text.return_value = 'Newton'
|
||||||
|
mocked_display_edit_text.return_value = 'John Newton'
|
||||||
|
|
||||||
|
# WHEN: accept() is called
|
||||||
|
result = self.form.accept()
|
||||||
|
|
||||||
|
# THEN: The result should be false and a critical error displayed
|
||||||
|
assert result is True
|
||||||
|
mocked_first_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_last_name_edit_text.assert_called_once_with()
|
||||||
|
mocked_display_edit_text.assert_called_once_with()
|
||||||
|
mocked_accept.assert_called_once_with(self.form)
|
||||||
|
0
tests/resources/themes/Moss_on_tree.otz
Executable file → Normal file
0
tests/resources/themes/Moss_on_tree.otz
Executable file → Normal file
Loading…
Reference in New Issue
Block a user