forked from openlp/openlp
This branch introduces following improvements to Quick Bible search:
- Combined Reference/Text search which first performs the Reference search and then moves to Text search if nothing is found. - Added Search while typing functionality for Quick Bible search - Possibility to use “.” when shortening Book names in Reference search. For an example Gen. 1 = Gen 1 = Genesis 1. - New/Improved error messages (E.g. added actual example verses to Reference error) - 3 New settings for controllin... bzr-revno: 2686 Fixes: https://launchpad.net/bugs/1591480
This commit is contained in:
commit
fb105f2e0b
@ -23,6 +23,7 @@
|
|||||||
The :mod:`uistrings` module provides standard strings for OpenLP.
|
The :mod:`uistrings` module provides standard strings for OpenLP.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import itertools
|
||||||
|
|
||||||
from openlp.core.common import translate
|
from openlp.core.common import translate
|
||||||
|
|
||||||
@ -155,3 +156,30 @@ class UiStrings(object):
|
|||||||
self.View = translate('OpenLP.Ui', 'View')
|
self.View = translate('OpenLP.Ui', 'View')
|
||||||
self.ViewMode = translate('OpenLP.Ui', 'View Mode')
|
self.ViewMode = translate('OpenLP.Ui', 'View Mode')
|
||||||
self.Video = translate('OpenLP.Ui', 'Video')
|
self.Video = translate('OpenLP.Ui', 'Video')
|
||||||
|
self.BibleShortSearchTitle = translate('OpenLP.Ui', 'Search is Empty or too Short')
|
||||||
|
self.BibleShortSearch = translate('OpenLP.Ui', '<strong>The search you have entered is empty or shorter '
|
||||||
|
'than 3 characters long.</strong><br><br>Please try again with '
|
||||||
|
'a longer search.')
|
||||||
|
self.BibleNoBiblesTitle = translate('OpenLP.Ui', 'No Bibles Available')
|
||||||
|
self.BibleNoBibles = translate('OpenLP.Ui', '<strong>There are no Bibles currently installed.</strong><br><br>'
|
||||||
|
'Please use the Import Wizard to install one or more Bibles.')
|
||||||
|
book_chapter = translate('OpenLP.Ui', 'Book Chapter')
|
||||||
|
chapter = translate('OpenLP.Ui', 'Chapter')
|
||||||
|
verse = translate('OpenLP.Ui', 'Verse')
|
||||||
|
gap = ' | '
|
||||||
|
psalm = translate('OpenLP.Ui', 'Psalm')
|
||||||
|
may_shorten = translate('OpenLP.Ui', 'Book names may be shortened from full names, for an example Ps 23 = '
|
||||||
|
'Psalm 23')
|
||||||
|
bible_scripture_items = \
|
||||||
|
[book_chapter, gap, psalm, ' 23<br>',
|
||||||
|
book_chapter, '%(range)s', chapter, gap, psalm, ' 23%(range)s24<br>',
|
||||||
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, gap, psalm, ' 23%(verse)s1%(range)s2<br>',
|
||||||
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', verse, '%(range)s', verse, gap, psalm,
|
||||||
|
' 23%(verse)s1%(range)s2%(list)s5%(range)s6<br>',
|
||||||
|
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', chapter, '%(verse)s', verse, '%(range)s',
|
||||||
|
verse, gap, psalm, ' 23%(verse)s1%(range)s2%(list)s24%(verse)s1%(range)s3<br>',
|
||||||
|
book_chapter, '%(verse)s', verse, '%(range)s', chapter, '%(verse)s', verse, gap, psalm,
|
||||||
|
' 23%(verse)s1%(range)s24%(verse)s1<br><br>', may_shorten]
|
||||||
|
itertools.chain.from_iterable(itertools.repeat(strings, 1) if isinstance(strings, str)
|
||||||
|
else strings for strings in bible_scripture_items)
|
||||||
|
self.BibleScriptureError = ''.join(str(joined) for joined in bible_scripture_items)
|
||||||
|
@ -651,6 +651,20 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
|
|||||||
item.setFont(font)
|
item.setFont(font)
|
||||||
self.list_view.addItem(item)
|
self.list_view.addItem(item)
|
||||||
|
|
||||||
|
def check_search_result_search_while_typing_short(self):
|
||||||
|
"""
|
||||||
|
This is used in Bible "Search while typing" if the search is shorter than the min required len.
|
||||||
|
"""
|
||||||
|
if self.list_view.count():
|
||||||
|
return
|
||||||
|
message = translate('OpenLP.MediaManagerItem', 'Search is too short to be used in: "Search while typing"')
|
||||||
|
item = QtWidgets.QListWidgetItem(message)
|
||||||
|
item.setFlags(QtCore.Qt.NoItemFlags)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setItalic(True)
|
||||||
|
item.setFont(font)
|
||||||
|
self.list_view.addItem(item)
|
||||||
|
|
||||||
def _get_id_of_item_to_generate(self, item, remote_item):
|
def _get_id_of_item_to_generate(self, item, remote_item):
|
||||||
"""
|
"""
|
||||||
Utility method to check items being submitted for slide generation.
|
Utility method to check items being submitted for slide generation.
|
||||||
|
@ -41,7 +41,8 @@ __default_settings__ = {
|
|||||||
'bibles/db password': '',
|
'bibles/db password': '',
|
||||||
'bibles/db hostname': '',
|
'bibles/db hostname': '',
|
||||||
'bibles/db database': '',
|
'bibles/db database': '',
|
||||||
'bibles/last search type': BibleSearch.Reference,
|
'bibles/last search type': BibleSearch.Combined,
|
||||||
|
'bibles/reset to combined quick search': True,
|
||||||
'bibles/verse layout style': LayoutStyle.VersePerSlide,
|
'bibles/verse layout style': LayoutStyle.VersePerSlide,
|
||||||
'bibles/book name language': LanguageSelection.Bible,
|
'bibles/book name language': LanguageSelection.Bible,
|
||||||
'bibles/display brackets': DisplayStyle.NoBrackets,
|
'bibles/display brackets': DisplayStyle.NoBrackets,
|
||||||
@ -59,7 +60,9 @@ __default_settings__ = {
|
|||||||
'bibles/range separator': '',
|
'bibles/range separator': '',
|
||||||
'bibles/list separator': '',
|
'bibles/list separator': '',
|
||||||
'bibles/end separator': '',
|
'bibles/end separator': '',
|
||||||
'bibles/last directory import': ''
|
'bibles/last directory import': '',
|
||||||
|
'bibles/hide combined quick error': False,
|
||||||
|
'bibles/is search while typing enabled': True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,6 +128,20 @@ class BiblesTab(SettingsTab):
|
|||||||
self.language_selection_layout.addWidget(self.language_selection_label)
|
self.language_selection_layout.addWidget(self.language_selection_label)
|
||||||
self.language_selection_layout.addWidget(self.language_selection_combo_box)
|
self.language_selection_layout.addWidget(self.language_selection_combo_box)
|
||||||
self.right_layout.addWidget(self.language_selection_group_box)
|
self.right_layout.addWidget(self.language_selection_group_box)
|
||||||
|
self.bible_quick_settings_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
|
self.bible_quick_settings_group_box.setObjectName('bible_quick_settings_group_box')
|
||||||
|
self.right_layout.addWidget(self.bible_quick_settings_group_box)
|
||||||
|
self.search_settings_layout = QtWidgets.QFormLayout(self.bible_quick_settings_group_box)
|
||||||
|
self.search_settings_layout.setObjectName('search_settings_layout')
|
||||||
|
self.reset_to_combined_quick_search_check_box = QtWidgets.QCheckBox(self.bible_quick_settings_group_box)
|
||||||
|
self.reset_to_combined_quick_search_check_box.setObjectName('reset_to_combined_quick_search_check_box')
|
||||||
|
self.search_settings_layout.addRow(self.reset_to_combined_quick_search_check_box)
|
||||||
|
self.hide_combined_quick_error_check_box = QtWidgets.QCheckBox(self.bible_quick_settings_group_box)
|
||||||
|
self.hide_combined_quick_error_check_box.setObjectName('hide_combined_quick_error_check_box')
|
||||||
|
self.search_settings_layout.addRow(self.hide_combined_quick_error_check_box)
|
||||||
|
self.bible_search_while_typing_check_box = QtWidgets.QCheckBox(self.bible_quick_settings_group_box)
|
||||||
|
self.bible_search_while_typing_check_box.setObjectName('bible_search_while_typing_check_box')
|
||||||
|
self.search_settings_layout.addRow(self.bible_search_while_typing_check_box)
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
self.right_layout.addStretch()
|
self.right_layout.addStretch()
|
||||||
# Signals and slots
|
# Signals and slots
|
||||||
@ -151,6 +165,12 @@ class BiblesTab(SettingsTab):
|
|||||||
self.end_separator_line_edit.editingFinished.connect(self.on_end_separator_line_edit_finished)
|
self.end_separator_line_edit.editingFinished.connect(self.on_end_separator_line_edit_finished)
|
||||||
Registry().register_function('theme_update_list', self.update_theme_list)
|
Registry().register_function('theme_update_list', self.update_theme_list)
|
||||||
self.language_selection_combo_box.activated.connect(self.on_language_selection_combo_box_changed)
|
self.language_selection_combo_box.activated.connect(self.on_language_selection_combo_box_changed)
|
||||||
|
self.reset_to_combined_quick_search_check_box.stateChanged.connect(
|
||||||
|
self.on_reset_to_combined_quick_search_check_box_changed)
|
||||||
|
self.hide_combined_quick_error_check_box.stateChanged.connect(
|
||||||
|
self.on_hide_combined_quick_error_check_box_changed)
|
||||||
|
self.bible_search_while_typing_check_box.stateChanged.connect(
|
||||||
|
self.on_bible_search_while_typing_check_box_changed)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.verse_display_group_box.setTitle(translate('BiblesPlugin.BiblesTab', 'Verse Display'))
|
self.verse_display_group_box.setTitle(translate('BiblesPlugin.BiblesTab', 'Verse Display'))
|
||||||
@ -194,6 +214,17 @@ class BiblesTab(SettingsTab):
|
|||||||
LanguageSelection.Application, translate('BiblesPlugin.BiblesTab', 'Application Language'))
|
LanguageSelection.Application, translate('BiblesPlugin.BiblesTab', 'Application Language'))
|
||||||
self.language_selection_combo_box.setItemText(
|
self.language_selection_combo_box.setItemText(
|
||||||
LanguageSelection.English, translate('BiblesPlugin.BiblesTab', 'English'))
|
LanguageSelection.English, translate('BiblesPlugin.BiblesTab', 'English'))
|
||||||
|
self.bible_quick_settings_group_box.setTitle(translate('BiblesPlugin.BiblesTab', 'Quick Search Settings'))
|
||||||
|
self.reset_to_combined_quick_search_check_box.setText(translate('BiblesPlugin.BiblesTab',
|
||||||
|
'Reset search type to "Text or Scripture'
|
||||||
|
' Reference" on startup'))
|
||||||
|
self.hide_combined_quick_error_check_box.setText(translate('BiblesPlugin.BiblesTab',
|
||||||
|
'Don\'t show error if nothing is found in "Text or '
|
||||||
|
'Scripture Reference"'))
|
||||||
|
self.bible_search_while_typing_check_box.setText(translate('BiblesPlugin.BiblesTab',
|
||||||
|
'Search automatically while typing (Text search must'
|
||||||
|
' contain a\nminimum of {count} characters and a '
|
||||||
|
'space for performance reasons)').format(count='8'))
|
||||||
|
|
||||||
def on_bible_theme_combo_box_changed(self):
|
def on_bible_theme_combo_box_changed(self):
|
||||||
self.bible_theme = self.bible_theme_combo_box.currentText()
|
self.bible_theme = self.bible_theme_combo_box.currentText()
|
||||||
@ -302,6 +333,24 @@ class BiblesTab(SettingsTab):
|
|||||||
self.end_separator_line_edit.setText(get_reference_separator('sep_e_default'))
|
self.end_separator_line_edit.setText(get_reference_separator('sep_e_default'))
|
||||||
self.end_separator_line_edit.setPalette(self.get_grey_text_palette(True))
|
self.end_separator_line_edit.setPalette(self.get_grey_text_palette(True))
|
||||||
|
|
||||||
|
def on_reset_to_combined_quick_search_check_box_changed(self, check_state):
|
||||||
|
"""
|
||||||
|
Event handler for the 'hide_combined_quick_error' check box
|
||||||
|
"""
|
||||||
|
self.reset_to_combined_quick_search = (check_state == QtCore.Qt.Checked)
|
||||||
|
|
||||||
|
def on_hide_combined_quick_error_check_box_changed(self, check_state):
|
||||||
|
"""
|
||||||
|
Event handler for the 'hide_combined_quick_error' check box
|
||||||
|
"""
|
||||||
|
self.hide_combined_quick_error = (check_state == QtCore.Qt.Checked)
|
||||||
|
|
||||||
|
def on_bible_search_while_typing_check_box_changed(self, check_state):
|
||||||
|
"""
|
||||||
|
Event handler for the 'hide_combined_quick_error' check box
|
||||||
|
"""
|
||||||
|
self.bible_search_while_typing = (check_state == QtCore.Qt.Checked)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(self.settings_section)
|
settings.beginGroup(self.settings_section)
|
||||||
@ -355,6 +404,12 @@ class BiblesTab(SettingsTab):
|
|||||||
self.end_separator_check_box.setChecked(True)
|
self.end_separator_check_box.setChecked(True)
|
||||||
self.language_selection = settings.value('book name language')
|
self.language_selection = settings.value('book name language')
|
||||||
self.language_selection_combo_box.setCurrentIndex(self.language_selection)
|
self.language_selection_combo_box.setCurrentIndex(self.language_selection)
|
||||||
|
self.reset_to_combined_quick_search = settings.value('reset to combined quick search')
|
||||||
|
self.reset_to_combined_quick_search_check_box.setChecked(self.reset_to_combined_quick_search)
|
||||||
|
self.hide_combined_quick_error = settings.value('hide combined quick error')
|
||||||
|
self.hide_combined_quick_error_check_box.setChecked(self.hide_combined_quick_error)
|
||||||
|
self.bible_search_while_typing = settings.value('is search while typing enabled')
|
||||||
|
self.bible_search_while_typing_check_box.setChecked(self.bible_search_while_typing)
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
@ -386,6 +441,9 @@ class BiblesTab(SettingsTab):
|
|||||||
if self.language_selection != settings.value('book name language'):
|
if self.language_selection != settings.value('book name language'):
|
||||||
settings.setValue('book name language', self.language_selection)
|
settings.setValue('book name language', self.language_selection)
|
||||||
self.settings_form.register_post_process('bibles_load_list')
|
self.settings_form.register_post_process('bibles_load_list')
|
||||||
|
settings.setValue('reset to combined quick search', self.reset_to_combined_quick_search)
|
||||||
|
settings.setValue('hide combined quick error', self.hide_combined_quick_error)
|
||||||
|
settings.setValue('is search while typing enabled', self.bible_search_while_typing)
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
if self.tab_visited:
|
if self.tab_visited:
|
||||||
self.settings_form.register_post_process('bibles_config_updated')
|
self.settings_form.register_post_process('bibles_config_updated')
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from openlp.core.common import RegistryProperties, AppLocation, Settings, translate, delete_file
|
from openlp.core.common import RegistryProperties, AppLocation, Settings, translate, delete_file, UiStrings
|
||||||
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
|
from openlp.plugins.bibles.lib import parse_reference, LanguageSelection
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
|
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
|
||||||
from .csvbible import CSVBible
|
from .csvbible import CSVBible
|
||||||
from .http import HTTPBible
|
from .http import HTTPBible
|
||||||
@ -267,42 +267,21 @@ class BibleManager(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.
|
||||||
log.debug('BibleManager.get_verses("{bible}", "{verse}")'.format(bible=bible, verse=verse_text))
|
log.debug('BibleManager.get_verses("{bible}", "{verse}")'.format(bible=bible, verse=verse_text))
|
||||||
if not bible:
|
if not bible:
|
||||||
if show_error:
|
if show_error:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.BibleManager', 'No Bibles Available'),
|
UiStrings().BibleNoBiblesTitle,
|
||||||
translate('BiblesPlugin.BibleManager', 'There are no Bibles currently installed. Please use the '
|
UiStrings().BibleNoBibles)
|
||||||
'Import Wizard to install one or more Bibles.')
|
|
||||||
)
|
|
||||||
return None
|
return None
|
||||||
|
# Get the language for books.
|
||||||
language_selection = self.get_language_selection(bible)
|
language_selection = self.get_language_selection(bible)
|
||||||
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
ref_list = parse_reference(verse_text, self.db_cache[bible], language_selection, book_ref_id)
|
||||||
if ref_list:
|
if ref_list:
|
||||||
return self.db_cache[bible].get_verses(ref_list, show_error)
|
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:
|
else:
|
||||||
if show_error:
|
|
||||||
reference_separators = {
|
|
||||||
'verse': get_reference_separator('sep_v_display'),
|
|
||||||
'range': get_reference_separator('sep_r_display'),
|
|
||||||
'list': get_reference_separator('sep_l_display')}
|
|
||||||
self.main_window.information_message(
|
|
||||||
translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'),
|
|
||||||
translate('BiblesPlugin.BibleManager', 'Your scripture reference is either not supported by '
|
|
||||||
'OpenLP or is invalid. Please make sure your reference '
|
|
||||||
'conforms to one of the following patterns or consult the manual:\n\n'
|
|
||||||
'Book Chapter\n'
|
|
||||||
'Book Chapter%(range)sChapter\n'
|
|
||||||
'Book Chapter%(verse)sVerse%(range)sVerse\n'
|
|
||||||
'Book Chapter%(verse)sVerse%(range)sVerse%(list)sVerse'
|
|
||||||
'%(range)sVerse\n'
|
|
||||||
'Book Chapter%(verse)sVerse%(range)sVerse%(list)sChapter'
|
|
||||||
'%(verse)sVerse%(range)sVerse\n'
|
|
||||||
'Book Chapter%(verse)sVerse%(range)sChapter%(verse)sVerse',
|
|
||||||
'Please pay attention to the appended "s" of the wildcards '
|
|
||||||
'and refrain from translating the words inside the names in the brackets.')
|
|
||||||
% reference_separators
|
|
||||||
)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_language_selection(self, bible):
|
def get_language_selection(self, bible):
|
||||||
@ -334,13 +313,11 @@ class BibleManager(RegistryProperties):
|
|||||||
:param text: The text to search for (unicode).
|
:param text: The text to search for (unicode).
|
||||||
"""
|
"""
|
||||||
log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text))
|
log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text))
|
||||||
|
# If no bibles are installed, message is given.
|
||||||
if not bible:
|
if not bible:
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.BibleManager', 'No Bibles Available'),
|
UiStrings().BibleNoBiblesTitle,
|
||||||
translate('BiblesPlugin.BibleManager',
|
UiStrings().BibleNoBibles)
|
||||||
'There are no Bibles currently installed. Please use the Import Wizard to install one or '
|
|
||||||
'more Bibles.')
|
|
||||||
)
|
|
||||||
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')
|
||||||
@ -348,20 +325,56 @@ class BibleManager(RegistryProperties):
|
|||||||
if second_bible:
|
if second_bible:
|
||||||
second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source')
|
second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source')
|
||||||
if web_bible or second_web_bible:
|
if web_bible or second_web_bible:
|
||||||
|
# If either Bible is Web, cursor is reset to normal and message is given.
|
||||||
|
self.application.set_normal_cursor()
|
||||||
self.main_window.information_message(
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used'),
|
translate('BiblesPlugin.BibleManager', 'Web Bible cannot be used in Text Search'),
|
||||||
translate('BiblesPlugin.BibleManager', 'Text Search is not available with Web Bibles.')
|
translate('BiblesPlugin.BibleManager', 'Text Search is not available with Web Bibles.\n'
|
||||||
|
'Please use the Scripture Reference Search instead.\n\n'
|
||||||
|
'This means that the currently used Bible\nor Second 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
|
||||||
if text:
|
# Shorter than 3 char searches break OpenLP with very long search times, thus they are blocked.
|
||||||
|
if len(text) - text.count(' ') < 3:
|
||||||
|
return None
|
||||||
|
# Fetch the results from db. If no results are found, return None, no message is given for this.
|
||||||
|
elif text:
|
||||||
|
return self.db_cache[bible].verse_search(text)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def verse_search_while_typing(self, bible, second_bible, text):
|
||||||
|
"""
|
||||||
|
Does a verse search for the given bible and text.
|
||||||
|
This is used during "Search while typing"
|
||||||
|
It's the same thing as the normal text search, but it does not show the web Bible error.
|
||||||
|
(It would result in the error popping every time a char is entered or removed)
|
||||||
|
It also does not have a minimum text len, this is set in mediaitem.py
|
||||||
|
|
||||||
|
:param bible: The bible to search in (unicode).
|
||||||
|
:param second_bible: The second bible (unicode). We do not search in this bible.
|
||||||
|
:param text: The text to search for (unicode).
|
||||||
|
"""
|
||||||
|
# If no bibles are installed, message is given.
|
||||||
|
if not bible:
|
||||||
|
return None
|
||||||
|
# Check if the bible or second_bible is a web bible.
|
||||||
|
web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source')
|
||||||
|
second_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 search ends w/o any message.
|
||||||
|
self.check_search_result()
|
||||||
|
self.application.set_normal_cursor()
|
||||||
|
return None
|
||||||
|
# Fetch the results from db. If no results are found, return None, no message is given for this.
|
||||||
|
elif text:
|
||||||
return self.db_cache[bible].verse_search(text)
|
return self.db_cache[bible].verse_search(text)
|
||||||
else:
|
else:
|
||||||
self.main_window.information_message(
|
|
||||||
translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'),
|
|
||||||
translate('BiblesPlugin.BibleManager', 'You did not enter a search keyword.\nYou can separate '
|
|
||||||
'different keywords by a space to search for all of your keywords and you can separate '
|
|
||||||
'them by a comma to search for one of them.')
|
|
||||||
)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def save_meta_data(self, bible, version, copyright, permissions, book_name_language=None):
|
def save_meta_data(self, bible, version, copyright, permissions, book_name_language=None):
|
||||||
|
@ -35,6 +35,7 @@ from openlp.plugins.bibles.forms.editbibleform import EditBibleForm
|
|||||||
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
||||||
LanguageSelection, BibleStrings
|
LanguageSelection, BibleStrings
|
||||||
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
|
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
|
||||||
|
import re
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ class BibleSearch(object):
|
|||||||
"""
|
"""
|
||||||
Reference = 1
|
Reference = 1
|
||||||
Text = 2
|
Text = 2
|
||||||
|
Combined = 3
|
||||||
|
|
||||||
|
|
||||||
class BibleMediaItem(MediaManagerItem):
|
class BibleMediaItem(MediaManagerItem):
|
||||||
@ -56,6 +58,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
log.info('Bible Media Item loaded')
|
log.info('Bible Media Item loaded')
|
||||||
|
|
||||||
def __init__(self, parent, plugin):
|
def __init__(self, parent, plugin):
|
||||||
|
self.clear_icon = build_icon(':/bibles/bibles_search_clear.png')
|
||||||
self.lock_icon = build_icon(':/bibles/bibles_search_lock.png')
|
self.lock_icon = build_icon(':/bibles/bibles_search_lock.png')
|
||||||
self.unlock_icon = build_icon(':/bibles/bibles_search_unlock.png')
|
self.unlock_icon = build_icon(':/bibles/bibles_search_unlock.png')
|
||||||
MediaManagerItem.__init__(self, parent, plugin)
|
MediaManagerItem.__init__(self, parent, plugin)
|
||||||
@ -157,10 +160,15 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
search_button_layout = QtWidgets.QHBoxLayout()
|
search_button_layout = QtWidgets.QHBoxLayout()
|
||||||
search_button_layout.setObjectName(prefix + 'search_button_layout')
|
search_button_layout.setObjectName(prefix + 'search_button_layout')
|
||||||
search_button_layout.addStretch()
|
search_button_layout.addStretch()
|
||||||
|
# Note: If we use QPushButton instead of the QToolButton, the icon will be larger than the Lock icon.
|
||||||
|
clear_button = QtWidgets.QToolButton(tab)
|
||||||
|
clear_button.setIcon(self.clear_icon)
|
||||||
|
clear_button.setObjectName(prefix + 'ClearButton')
|
||||||
lock_button = QtWidgets.QToolButton(tab)
|
lock_button = QtWidgets.QToolButton(tab)
|
||||||
lock_button.setIcon(self.unlock_icon)
|
lock_button.setIcon(self.unlock_icon)
|
||||||
lock_button.setCheckable(True)
|
lock_button.setCheckable(True)
|
||||||
lock_button.setObjectName(prefix + 'LockButton')
|
lock_button.setObjectName(prefix + 'LockButton')
|
||||||
|
search_button_layout.addWidget(clear_button)
|
||||||
search_button_layout.addWidget(lock_button)
|
search_button_layout.addWidget(lock_button)
|
||||||
search_button = QtWidgets.QPushButton(tab)
|
search_button = QtWidgets.QPushButton(tab)
|
||||||
search_button.setObjectName(prefix + 'SearchButton')
|
search_button.setObjectName(prefix + 'SearchButton')
|
||||||
@ -176,6 +184,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
setattr(self, prefix + 'SecondComboBox', second_combo_box)
|
setattr(self, prefix + 'SecondComboBox', second_combo_box)
|
||||||
setattr(self, prefix + 'StyleLabel', style_label)
|
setattr(self, prefix + 'StyleLabel', style_label)
|
||||||
setattr(self, prefix + 'StyleComboBox', style_combo_box)
|
setattr(self, prefix + 'StyleComboBox', style_combo_box)
|
||||||
|
setattr(self, prefix + 'ClearButton', clear_button)
|
||||||
setattr(self, prefix + 'LockButton', lock_button)
|
setattr(self, prefix + 'LockButton', lock_button)
|
||||||
setattr(self, prefix + 'SearchButtonLayout', search_button_layout)
|
setattr(self, prefix + 'SearchButtonLayout', search_button_layout)
|
||||||
setattr(self, prefix + 'SearchButton', search_button)
|
setattr(self, prefix + 'SearchButton', search_button)
|
||||||
@ -245,11 +254,14 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.quickStyleComboBox.activated.connect(self.on_quick_style_combo_box_changed)
|
self.quickStyleComboBox.activated.connect(self.on_quick_style_combo_box_changed)
|
||||||
self.advancedStyleComboBox.activated.connect(self.on_advanced_style_combo_box_changed)
|
self.advancedStyleComboBox.activated.connect(self.on_advanced_style_combo_box_changed)
|
||||||
# Buttons
|
# Buttons
|
||||||
|
self.advancedClearButton.clicked.connect(self.on_clear_button)
|
||||||
|
self.quickClearButton.clicked.connect(self.on_clear_button)
|
||||||
self.advancedSearchButton.clicked.connect(self.on_advanced_search_button)
|
self.advancedSearchButton.clicked.connect(self.on_advanced_search_button)
|
||||||
self.quickSearchButton.clicked.connect(self.on_quick_search_button)
|
self.quickSearchButton.clicked.connect(self.on_quick_search_button)
|
||||||
# Other stuff
|
# Other stuff
|
||||||
self.quick_search_edit.returnPressed.connect(self.on_quick_search_button)
|
self.quick_search_edit.returnPressed.connect(self.on_quick_search_button)
|
||||||
self.search_tab_bar.currentChanged.connect(self.on_search_tab_bar_current_changed)
|
self.search_tab_bar.currentChanged.connect(self.on_search_tab_bar_current_changed)
|
||||||
|
self.quick_search_edit.textChanged.connect(self.on_search_text_edit_changed)
|
||||||
|
|
||||||
def on_focus(self):
|
def on_focus(self):
|
||||||
if self.quickTab.isVisible():
|
if self.quickTab.isVisible():
|
||||||
@ -286,6 +298,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
|
self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
|
||||||
self.quickStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine)
|
self.quickStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine)
|
||||||
self.quickStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous)
|
self.quickStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous)
|
||||||
|
self.quickClearButton.setToolTip(translate('BiblesPlugin.MediaItem', 'Clear the search results.'))
|
||||||
self.quickLockButton.setToolTip(translate('BiblesPlugin.MediaItem',
|
self.quickLockButton.setToolTip(translate('BiblesPlugin.MediaItem',
|
||||||
'Toggle to keep or clear the previous results.'))
|
'Toggle to keep or clear the previous results.'))
|
||||||
self.quickSearchButton.setText(UiStrings().Search)
|
self.quickSearchButton.setText(UiStrings().Search)
|
||||||
@ -300,6 +313,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
|
self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
|
||||||
self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine)
|
self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine)
|
||||||
self.advancedStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous)
|
self.advancedStyleComboBox.setItemText(LayoutStyle.Continuous, UiStrings().Continuous)
|
||||||
|
self.advancedClearButton.setToolTip(translate('BiblesPlugin.MediaItem', 'Clear the search results.'))
|
||||||
self.advancedLockButton.setToolTip(translate('BiblesPlugin.MediaItem',
|
self.advancedLockButton.setToolTip(translate('BiblesPlugin.MediaItem',
|
||||||
'Toggle to keep or clear the previous results.'))
|
'Toggle to keep or clear the previous results.'))
|
||||||
self.advancedSearchButton.setText(UiStrings().Search)
|
self.advancedSearchButton.setText(UiStrings().Search)
|
||||||
@ -309,6 +323,9 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.plugin.manager.media = self
|
self.plugin.manager.media = self
|
||||||
self.load_bibles()
|
self.load_bibles()
|
||||||
self.quick_search_edit.set_search_types([
|
self.quick_search_edit.set_search_types([
|
||||||
|
(BibleSearch.Combined, ':/bibles/bibles_search_combined.png',
|
||||||
|
translate('BiblesPlugin.MediaItem', 'Text or Reference'),
|
||||||
|
translate('BiblesPlugin.MediaItem', 'Text or Reference...')),
|
||||||
(BibleSearch.Reference, ':/bibles/bibles_search_reference.png',
|
(BibleSearch.Reference, ':/bibles/bibles_search_reference.png',
|
||||||
translate('BiblesPlugin.MediaItem', 'Scripture Reference'),
|
translate('BiblesPlugin.MediaItem', 'Scripture Reference'),
|
||||||
translate('BiblesPlugin.MediaItem', 'Search Scripture Reference...')),
|
translate('BiblesPlugin.MediaItem', 'Search Scripture Reference...')),
|
||||||
@ -424,18 +441,24 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
def update_auto_completer(self):
|
def update_auto_completer(self):
|
||||||
"""
|
"""
|
||||||
This updates the bible book completion list for the search field. The completion depends on the bible. It is
|
This updates the bible book completion list for the search field. The completion depends on the bible. It is
|
||||||
only updated when we are doing a reference search, otherwise the auto completion list is removed.
|
only updated when we are doing reference or combined search, in text search the completion list is removed.
|
||||||
"""
|
"""
|
||||||
log.debug('update_auto_completer')
|
log.debug('update_auto_completer')
|
||||||
# Save the current search type to the configuration.
|
# Save the current search type to the configuration. If setting for automatically resetting the search type to
|
||||||
|
# Combined is enabled, use that otherwise use the currently selected search type.
|
||||||
|
# Note: This setting requires a restart to take effect.
|
||||||
|
if Settings().value(self.settings_section + '/reset to combined quick search'):
|
||||||
|
Settings().setValue('{section}/last search type'.format(section=self.settings_section),
|
||||||
|
BibleSearch.Combined)
|
||||||
|
else:
|
||||||
Settings().setValue('{section}/last search type'.format(section=self.settings_section),
|
Settings().setValue('{section}/last search type'.format(section=self.settings_section),
|
||||||
self.quick_search_edit.current_search_type())
|
self.quick_search_edit.current_search_type())
|
||||||
# Save the current bible to the configuration.
|
# Save the current bible to the configuration.
|
||||||
Settings().setValue('{section}/quick bible'.format(section=self.settings_section),
|
Settings().setValue('{section}/quick bible'.format(section=self.settings_section),
|
||||||
self.quickVersionComboBox.currentText())
|
self.quickVersionComboBox.currentText())
|
||||||
books = []
|
books = []
|
||||||
# We have to do a 'Reference Search'.
|
# We have to do a 'Reference Search' (Or as part of Combined Search).
|
||||||
if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
if self.quick_search_edit.current_search_type() is not BibleSearch.Text:
|
||||||
bibles = self.plugin.manager.get_bibles()
|
bibles = self.plugin.manager.get_bibles()
|
||||||
bible = self.quickVersionComboBox.currentText()
|
bible = self.quickVersionComboBox.currentText()
|
||||||
if bible:
|
if bible:
|
||||||
@ -525,7 +548,15 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.advancedTab.setVisible(True)
|
self.advancedTab.setVisible(True)
|
||||||
self.advanced_book_combo_box.setFocus()
|
self.advanced_book_combo_box.setFocus()
|
||||||
|
|
||||||
|
def on_clear_button(self):
|
||||||
|
# Clear the list, then set the "No search Results" message, then clear the text field and give it focus.
|
||||||
|
self.list_view.clear()
|
||||||
|
self.check_search_result()
|
||||||
|
self.quick_search_edit.clear()
|
||||||
|
self.quick_search_edit.setFocus()
|
||||||
|
|
||||||
def on_lock_button_toggled(self, checked):
|
def on_lock_button_toggled(self, checked):
|
||||||
|
self.quick_search_edit.setFocus()
|
||||||
if checked:
|
if checked:
|
||||||
self.sender().setIcon(self.lock_icon)
|
self.sender().setIcon(self.lock_icon)
|
||||||
else:
|
else:
|
||||||
@ -652,33 +683,53 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.check_search_result()
|
self.check_search_result()
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def on_quick_search_button(self):
|
def on_quick_reference_search(self):
|
||||||
"""
|
"""
|
||||||
Does a quick search and saves the search results. Quick search can either be "Reference Search" or
|
We are doing a 'Reference Search'.
|
||||||
"Text Search".
|
This search is called on def on_quick_search_button by Quick Reference and Combined Searches.
|
||||||
"""
|
"""
|
||||||
log.debug('Quick Search Button clicked')
|
# Set Bibles to use the text input from Quick search field.
|
||||||
self.quickSearchButton.setEnabled(False)
|
|
||||||
self.application.process_events()
|
|
||||||
bible = self.quickVersionComboBox.currentText()
|
bible = self.quickVersionComboBox.currentText()
|
||||||
second_bible = self.quickSecondComboBox.currentText()
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
|
"""
|
||||||
|
Get input from field and replace 'A-Z + . ' with ''
|
||||||
|
This will check if field has any '.' after A-Z and removes them. Eg. Gen. 1 = Ge 1 = Genesis 1
|
||||||
|
If Book name has '.' after number. eg. 1. Genesis, the search fails without the dot, and vice versa.
|
||||||
|
A better solution would be to make '.' optional in the search results. Current solution was easier to code.
|
||||||
|
"""
|
||||||
text = self.quick_search_edit.text()
|
text = self.quick_search_edit.text()
|
||||||
if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
text = re.sub('\D[.]\s', ' ', text)
|
||||||
# We are doing a 'Reference Search'.
|
# This is triggered on reference search, use the search from manager.py
|
||||||
|
if self.quick_search_edit.current_search_type() != BibleSearch.Text:
|
||||||
self.search_results = self.plugin.manager.get_verses(bible, text)
|
self.search_results = self.plugin.manager.get_verses(bible, text)
|
||||||
if second_bible and self.search_results:
|
if second_bible and self.search_results:
|
||||||
self.second_search_results = \
|
self.second_search_results = \
|
||||||
self.plugin.manager.get_verses(second_bible, text, self.search_results[0].book.book_reference_id)
|
self.plugin.manager.get_verses(second_bible, text, self.search_results[0].book.book_reference_id)
|
||||||
else:
|
|
||||||
# We are doing a 'Text Search'.
|
def on_quick_text_search(self):
|
||||||
|
"""
|
||||||
|
We are doing a 'Text Search'.
|
||||||
|
This search is called on def on_quick_search_button by Quick Text and Combined Searches.
|
||||||
|
"""
|
||||||
|
# Set Bibles to use the text input from Quick search field.
|
||||||
|
bible = self.quickVersionComboBox.currentText()
|
||||||
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
|
text = self.quick_search_edit.text()
|
||||||
|
# If Text search ends with "," OpenLP will crash, prevent this from happening by removing all ","s.
|
||||||
|
text = re.sub('[,]', '', text)
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
|
# Get Bibles list
|
||||||
bibles = self.plugin.manager.get_bibles()
|
bibles = self.plugin.manager.get_bibles()
|
||||||
|
# Add results to "search_results"
|
||||||
self.search_results = self.plugin.manager.verse_search(bible, second_bible, text)
|
self.search_results = self.plugin.manager.verse_search(bible, second_bible, text)
|
||||||
if second_bible and self.search_results:
|
if second_bible and self.search_results:
|
||||||
|
# new_search_results is needed to make sure 2nd bible contains all verses. (And counting them on error)
|
||||||
text = []
|
text = []
|
||||||
new_search_results = []
|
new_search_results = []
|
||||||
count = 0
|
count = 0
|
||||||
passage_not_found = False
|
passage_not_found = False
|
||||||
|
# Search second bible for results of search_results to make sure everythigns there.
|
||||||
|
# Count all the unfound passages.
|
||||||
for verse in self.search_results:
|
for verse in self.search_results:
|
||||||
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
|
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
|
||||||
if not db_book:
|
if not db_book:
|
||||||
@ -690,15 +741,132 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
new_search_results.append(verse)
|
new_search_results.append(verse)
|
||||||
text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse))
|
text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse))
|
||||||
if passage_not_found:
|
if passage_not_found:
|
||||||
QtWidgets.QMessageBox.information(
|
# This is for the 2nd Bible.
|
||||||
self, translate('BiblesPlugin.MediaItem', 'Information'),
|
self.main_window.information_message(
|
||||||
translate('BiblesPlugin.MediaItem',
|
translate('BiblesPlugin.MediaItem', 'Information'),
|
||||||
'The second Bible does not contain all the verses that are in the main Bible. '
|
translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses '
|
||||||
'Only verses found in both Bibles will be shown. {count:d} verses have not been '
|
'that are in the main Bible.\nOnly verses found in both Bibles'
|
||||||
'included in the results.').format(count=count),
|
' will be shown.\n\n{count:d} verses have not been included '
|
||||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
|
'in the results.').format(count=count))
|
||||||
|
# Join the searches so only verses that are found on both Bibles are shown.
|
||||||
self.search_results = new_search_results
|
self.search_results = new_search_results
|
||||||
self.second_search_results = bibles[second_bible].get_verses(text)
|
self.second_search_results = bibles[second_bible].get_verses(text)
|
||||||
|
|
||||||
|
def on_quick_text_search_while_typing(self):
|
||||||
|
"""
|
||||||
|
We are doing a 'Text Search' while typing
|
||||||
|
Call the verse_search_while_typing from manager.py
|
||||||
|
It does not show web bible errors while typing.
|
||||||
|
(It would result in the error popping every time a char is entered or removed)
|
||||||
|
"""
|
||||||
|
# Set Bibles to use the text input from Quick search field.
|
||||||
|
bible = self.quickVersionComboBox.currentText()
|
||||||
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
|
text = self.quick_search_edit.text()
|
||||||
|
# If Text search ends with "," OpenLP will crash, prevent this from happening by removing all ","s.
|
||||||
|
text = re.sub('[,]', '', text)
|
||||||
|
self.application.set_busy_cursor()
|
||||||
|
# Get Bibles list
|
||||||
|
bibles = self.plugin.manager.get_bibles()
|
||||||
|
# Add results to "search_results"
|
||||||
|
self.search_results = self.plugin.manager.verse_search_while_typing(bible, second_bible, text)
|
||||||
|
if second_bible and self.search_results:
|
||||||
|
# new_search_results is needed to make sure 2nd bible contains all verses. (And counting them on error)
|
||||||
|
text = []
|
||||||
|
new_search_results = []
|
||||||
|
count = 0
|
||||||
|
passage_not_found = False
|
||||||
|
# Search second bible for results of search_results to make sure everythigns there.
|
||||||
|
# Count all the unfound passages. Even thou no error is shown, this needs to be done or
|
||||||
|
# the code breaks later on.
|
||||||
|
for verse in self.search_results:
|
||||||
|
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
|
||||||
|
if not db_book:
|
||||||
|
log.debug('Passage ("{versebookname}","{versechapter}","{verseverse}") not found in Second Bible'
|
||||||
|
.format(versebookname=verse.book.name, versechapter='verse.chapter',
|
||||||
|
verseverse=verse.verse))
|
||||||
|
count += 1
|
||||||
|
continue
|
||||||
|
new_search_results.append(verse)
|
||||||
|
text.append((verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse))
|
||||||
|
# Join the searches so only verses that are found on both Bibles are shown.
|
||||||
|
self.search_results = new_search_results
|
||||||
|
self.second_search_results = bibles[second_bible].get_verses(text)
|
||||||
|
|
||||||
|
def on_quick_search_button(self):
|
||||||
|
"""
|
||||||
|
This triggers the proper Quick search based on which search type is used.
|
||||||
|
"Eg. "Reference Search", "Text Search" or "Combined search".
|
||||||
|
"""
|
||||||
|
log.debug('Quick Search Button clicked')
|
||||||
|
self.quickSearchButton.setEnabled(False)
|
||||||
|
self.application.process_events()
|
||||||
|
bible = self.quickVersionComboBox.currentText()
|
||||||
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
|
text = self.quick_search_edit.text()
|
||||||
|
if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
||||||
|
# We are doing a 'Reference Search'. (Get script from def on_quick_reference_search)
|
||||||
|
self.on_quick_reference_search()
|
||||||
|
# Get reference separators from settings.
|
||||||
|
if not self.search_results:
|
||||||
|
reference_separators = {
|
||||||
|
'verse': get_reference_separator('sep_v_display'),
|
||||||
|
'range': get_reference_separator('sep_r_display'),
|
||||||
|
'list': get_reference_separator('sep_l_display')}
|
||||||
|
self.main_window.information_message(
|
||||||
|
translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'),
|
||||||
|
translate('BiblesPlugin.BibleManager', '<strong>OpenLP couldn’t find anything '
|
||||||
|
'with your search.<br><br>'
|
||||||
|
'Please make sure that your reference follows '
|
||||||
|
'one of these patterns:</strong><br><br>%s'
|
||||||
|
% UiStrings().BibleScriptureError % reference_separators))
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Text:
|
||||||
|
# We are doing a 'Text Search'. (Get script from def on_quick_text_search)
|
||||||
|
self.on_quick_text_search()
|
||||||
|
if not self.search_results and len(text) - text.count(' ') < 3 and bible:
|
||||||
|
self.main_window.information_message(
|
||||||
|
UiStrings().BibleShortSearchTitle,
|
||||||
|
UiStrings().BibleShortSearch)
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
||||||
|
# We are doing a 'Combined search'. Starting with reference search.
|
||||||
|
# Perform only if text contains any numbers
|
||||||
|
if (char.isdigit() for char in text):
|
||||||
|
self.on_quick_reference_search()
|
||||||
|
"""
|
||||||
|
If results are found, search will be finalized.
|
||||||
|
This check needs to be here in order to avoid duplicate errors.
|
||||||
|
If keyword is shorter than 3 (not including spaces), message is given. It's actually possible to find
|
||||||
|
verses with less than 3 chars (Eg. G1 = Genesis 1) thus this error is not shown if any results are found.
|
||||||
|
if no Bibles are installed, this message is not shown - "No bibles" message is shown instead.
|
||||||
|
"""
|
||||||
|
if not self.search_results and len(text) - text.count(' ') < 3 and bible:
|
||||||
|
self.main_window.information_message(
|
||||||
|
UiStrings().BibleShortSearchTitle,
|
||||||
|
UiStrings().BibleShortSearch)
|
||||||
|
if not self.search_results and len(text) - text.count(' ') > 2 and bible:
|
||||||
|
# Text search starts here if no reference was found and keyword is longer than 2.
|
||||||
|
# > 2 check is required in order to avoid duplicate error messages for short keywords.
|
||||||
|
self.on_quick_text_search()
|
||||||
|
if not self.search_results and not \
|
||||||
|
Settings().value(self.settings_section + '/hide combined quick error'):
|
||||||
|
self.application.set_normal_cursor()
|
||||||
|
# Reference separators need to be defined both, in here and on reference search,
|
||||||
|
# error won't work if they are left out from one.
|
||||||
|
reference_separators = {
|
||||||
|
'verse': get_reference_separator('sep_v_display'),
|
||||||
|
'range': get_reference_separator('sep_r_display'),
|
||||||
|
'list': get_reference_separator('sep_l_display')}
|
||||||
|
self.main_window.information_message(translate('BiblesPlugin.BibleManager', 'Nothing found'),
|
||||||
|
translate('BiblesPlugin.BibleManager',
|
||||||
|
'<strong>OpenLP couldn’t find anything with your'
|
||||||
|
' search.</strong><br><br>If you tried to search'
|
||||||
|
' with Scripture Reference, please make<br> sure'
|
||||||
|
' that your reference follows one of these'
|
||||||
|
' patterns: <br><br>%s'
|
||||||
|
% UiStrings().BibleScriptureError %
|
||||||
|
reference_separators))
|
||||||
|
# Finalizing the search
|
||||||
|
# List is cleared if not locked, results are listed, button is set available, cursor is set to normal.
|
||||||
if not self.quickLockButton.isChecked():
|
if not self.quickLockButton.isChecked():
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
if self.list_view.count() != 0 and self.search_results:
|
if self.list_view.count() != 0 and self.search_results:
|
||||||
@ -709,6 +877,99 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.check_search_result()
|
self.check_search_result()
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
|
def on_quick_search_while_typing(self):
|
||||||
|
"""
|
||||||
|
This function is called when "Search as you type" is enabled for Bibles.
|
||||||
|
It is basically the same thing as "on_quick_search_search" but all the error messages are removed.
|
||||||
|
This also has increased min len for text search for performance reasons.
|
||||||
|
For commented version, please visit def on_quick_search_button.
|
||||||
|
"""
|
||||||
|
bible = self.quickVersionComboBox.currentText()
|
||||||
|
second_bible = self.quickSecondComboBox.currentText()
|
||||||
|
text = self.quick_search_edit.text()
|
||||||
|
if self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
||||||
|
# If text has no numbers, auto search limit is min 8 characters for performance reasons.
|
||||||
|
# If you change this value, also change it in biblestab.py (Count) in enabling search while typing.
|
||||||
|
if (char.isdigit() for char in text) and len(text) > 2:
|
||||||
|
self.on_quick_reference_search()
|
||||||
|
if not self.search_results and len(text) > 7:
|
||||||
|
self.on_quick_text_search_while_typing()
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
||||||
|
self.on_quick_reference_search()
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Text:
|
||||||
|
if len(text) > 7:
|
||||||
|
self.on_quick_text_search_while_typing()
|
||||||
|
if not self.quickLockButton.isChecked():
|
||||||
|
self.list_view.clear()
|
||||||
|
if self.list_view.count() != 0 and self.search_results:
|
||||||
|
self.__check_second_bible(bible, second_bible)
|
||||||
|
elif self.search_results:
|
||||||
|
self.display_results(bible, second_bible)
|
||||||
|
self.check_search_result()
|
||||||
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
|
def on_search_text_edit_changed(self):
|
||||||
|
"""
|
||||||
|
If search automatically while typing is enabled, perform the search and list results when conditions are met.
|
||||||
|
"""
|
||||||
|
if Settings().value('bibles/is search while typing enabled'):
|
||||||
|
text = self.quick_search_edit.text()
|
||||||
|
"""
|
||||||
|
Use Regex for finding space + number in reference search and space + 2 characters in text search.
|
||||||
|
Also search for two characters (Searches require at least two sets of two characters)
|
||||||
|
These are used to prevent bad search queries from starting. (Long/crashing queries)
|
||||||
|
"""
|
||||||
|
space_and_digit_reference = re.compile(' \d')
|
||||||
|
two_chars_text = re.compile('\S\S')
|
||||||
|
space_and_two_chars_text = re.compile(' \S\S')
|
||||||
|
# Turn this into a format that may be used in if statement.
|
||||||
|
count_space_digit_reference = space_and_digit_reference.findall(text)
|
||||||
|
count_two_chars_text = two_chars_text.findall(text)
|
||||||
|
count_spaces_two_chars_text = space_and_two_chars_text.findall(text)
|
||||||
|
"""
|
||||||
|
The Limit is required for setting the proper "No items found" message.
|
||||||
|
"Limit" is also hard coded to on_quick_search_while_typing, it must be there to avoid bad search
|
||||||
|
performance. Limit 8 = Text search, 3 = Reference search.
|
||||||
|
"""
|
||||||
|
limit = 8
|
||||||
|
if self.quick_search_edit.current_search_type() == BibleSearch.Combined:
|
||||||
|
if len(count_space_digit_reference) != 0:
|
||||||
|
limit = 3
|
||||||
|
elif self.quick_search_edit.current_search_type() == BibleSearch.Reference:
|
||||||
|
limit = 3
|
||||||
|
"""
|
||||||
|
If text is empty, clear the list.
|
||||||
|
else: Start by checking if the search is suitable for "Search while typing"
|
||||||
|
"""
|
||||||
|
if len(text) == 0:
|
||||||
|
if not self.quickLockButton.isChecked():
|
||||||
|
self.list_view.clear()
|
||||||
|
self.check_search_result()
|
||||||
|
else:
|
||||||
|
if limit == 3 and (len(text) < limit or len(count_space_digit_reference) == 0):
|
||||||
|
if not self.quickLockButton.isChecked():
|
||||||
|
self.list_view.clear()
|
||||||
|
self.check_search_result()
|
||||||
|
elif (limit == 8 and (len(text) < limit or len(count_spaces_two_chars_text) == 0 or
|
||||||
|
len(count_two_chars_text) < 2)):
|
||||||
|
if not self.quickLockButton.isChecked():
|
||||||
|
self.list_view.clear()
|
||||||
|
self.check_search_result_search_while_typing_short()
|
||||||
|
else:
|
||||||
|
"""
|
||||||
|
Start search if no chars are entered or deleted for 0.2 s
|
||||||
|
If no Timer is set, Text search will break the search by sending repeative search Quaries on
|
||||||
|
all chars. Use the self.on_quick_search_while_typing, this does not contain any error messages.
|
||||||
|
"""
|
||||||
|
self.search_timer = ()
|
||||||
|
if self.search_timer:
|
||||||
|
self.search_timer.stop()
|
||||||
|
self.search_timer.deleteLater()
|
||||||
|
self.search_timer = QtCore.QTimer()
|
||||||
|
self.search_timer.timeout.connect(self.on_quick_search_while_typing)
|
||||||
|
self.search_timer.setSingleShot(True)
|
||||||
|
self.search_timer.start(200)
|
||||||
|
|
||||||
def display_results(self, bible, second_bible=''):
|
def display_results(self, bible, second_bible=''):
|
||||||
"""
|
"""
|
||||||
Displays the search results in the media manager. All data needed for further action is saved for/in each row.
|
Displays the search results in the media manager. All data needed for further action is saved for/in each row.
|
||||||
|
BIN
resources/images/bibles_search_clear.png
Normal file
BIN
resources/images/bibles_search_clear.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
resources/images/bibles_search_combined.png
Normal file
BIN
resources/images/bibles_search_combined.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
@ -30,9 +30,11 @@
|
|||||||
<file>image_new_group.png</file>
|
<file>image_new_group.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="bibles">
|
<qresource prefix="bibles">
|
||||||
|
<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>
|
||||||
<file>bibles_upgrade_alert.png</file>
|
<file>bibles_upgrade_alert.png</file>
|
||||||
|
<file>bibles_search_clear.png</file>
|
||||||
<file>bibles_search_unlock.png</file>
|
<file>bibles_search_unlock.png</file>
|
||||||
<file>bibles_search_lock.png</file>
|
<file>bibles_search_lock.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
This module contains tests for the lib submodule of the Presentations plugin.
|
This module contains tests for the lib submodule of the Presentations plugin.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from openlp.core.common import Registry
|
||||||
from openlp.plugins.bibles.lib.mediaitem import BibleMediaItem
|
from openlp.plugins.bibles.lib.mediaitem import BibleMediaItem
|
||||||
from tests.functional import MagicMock, patch
|
from tests.functional import MagicMock, patch
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
@ -41,6 +42,9 @@ class TestMediaItem(TestCase, TestMixin):
|
|||||||
patch('openlp.plugins.bibles.lib.mediaitem.BibleMediaItem.setup_item'):
|
patch('openlp.plugins.bibles.lib.mediaitem.BibleMediaItem.setup_item'):
|
||||||
self.media_item = BibleMediaItem(None, MagicMock())
|
self.media_item = BibleMediaItem(None, MagicMock())
|
||||||
self.setup_application()
|
self.setup_application()
|
||||||
|
self.mocked_main_window = MagicMock()
|
||||||
|
Registry.create()
|
||||||
|
Registry().register('main_window', self.mocked_main_window)
|
||||||
|
|
||||||
def test_display_results_no_results(self):
|
def test_display_results_no_results(self):
|
||||||
"""
|
"""
|
||||||
@ -109,3 +113,40 @@ class TestMediaItem(TestCase, TestMixin):
|
|||||||
mocked_list_view.selectAll.assert_called_once_with()
|
mocked_list_view.selectAll.assert_called_once_with()
|
||||||
self.assertEqual(self.media_item.search_results, {})
|
self.assertEqual(self.media_item.search_results, {})
|
||||||
self.assertEqual(self.media_item.second_search_results, {})
|
self.assertEqual(self.media_item.second_search_results, {})
|
||||||
|
|
||||||
|
def on_quick_search_button_general_test(self):
|
||||||
|
"""
|
||||||
|
Test that general things, which should be called on all Quick searches are called.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: self.application as self.app, all the required functions
|
||||||
|
Registry.create()
|
||||||
|
Registry().register('application', self.app)
|
||||||
|
self.media_item.quickSearchButton = MagicMock()
|
||||||
|
self.app.process_events = MagicMock()
|
||||||
|
self.media_item.quickVersionComboBox = MagicMock()
|
||||||
|
self.media_item.quickVersionComboBox.currentText = MagicMock()
|
||||||
|
self.media_item.quickSecondComboBox = MagicMock()
|
||||||
|
self.media_item.quickSecondComboBox.currentText = MagicMock()
|
||||||
|
self.media_item.quick_search_edit = MagicMock()
|
||||||
|
self.media_item.quick_search_edit.text = MagicMock()
|
||||||
|
self.media_item.quickLockButton = MagicMock()
|
||||||
|
self.media_item.list_view = MagicMock()
|
||||||
|
self.media_item.search_results = MagicMock()
|
||||||
|
self.media_item.display_results = MagicMock()
|
||||||
|
self.media_item.check_search_result = MagicMock()
|
||||||
|
self.app.set_normal_cursor = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: on_quick_search_button is called
|
||||||
|
self.media_item.on_quick_search_button()
|
||||||
|
|
||||||
|
# THEN: Search should had been started and finalized properly
|
||||||
|
self.assertEqual(1, self.app.process_events.call_count, 'Normal cursor should had been called once')
|
||||||
|
self.assertEqual(1, self.media_item.quickVersionComboBox.currentText.call_count, 'Should had been called once')
|
||||||
|
self.assertEqual(1, self.media_item.quickSecondComboBox.currentText.call_count, 'Should had been called once')
|
||||||
|
self.assertEqual(1, self.media_item.quick_search_edit.text.call_count, 'Text edit Should had been called once')
|
||||||
|
self.assertEqual(1, self.media_item.quickLockButton.isChecked.call_count, 'Lock Should had been called once')
|
||||||
|
self.assertEqual(1, self.media_item.display_results.call_count, 'Display results Should had been called once')
|
||||||
|
self.assertEqual(2, self.media_item.quickSearchButton.setEnabled.call_count, 'Disable and Enable the button')
|
||||||
|
self.assertEqual(1, self.media_item.check_search_result.call_count, 'Check results Should had been called once')
|
||||||
|
self.assertEqual(1, self.app.set_normal_cursor.call_count, 'Normal cursor should had been called once')
|
||||||
|
Loading…
Reference in New Issue
Block a user