phill.ridout@gmail.com 2016-11-16 00:44:11 +02:00 committed by Raoul Snyman
commit f6de30de23
8 changed files with 145 additions and 58 deletions

View File

@ -112,6 +112,7 @@ class UiStrings(object):
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.NoResults = translate('OpenLP.Ui', 'No Search Results')
self.OLP = translate('OpenLP.Ui', 'OpenLP')
self.OLPV2 = "{name} {version}".format(name=self.OLP, version="2")
self.OLPV2x = "{name} {version}".format(name=self.OLP, version="2.4")
@ -139,6 +140,7 @@ class UiStrings(object):
self.Settings = translate('OpenLP.Ui', 'Settings')
self.SaveService = translate('OpenLP.Ui', 'Save Service')
self.Service = translate('OpenLP.Ui', 'Service')
self.ShortResults = translate('OpenLP.Ui', 'Please type more text to use \'Search As You Type\'')
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')

View File

@ -397,8 +397,6 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
# Decide if we have to show the context menu or not.
if item is None:
return
if not item.flags() & QtCore.Qt.ItemIsSelectable:
return
self.menu.exec(self.list_view.mapToGlobal(point))
def get_file_list(self):
@ -638,34 +636,6 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
"""
return item
def check_search_result(self):
"""
Checks if the list_view is empty and adds a "No Search Results" item.
"""
if self.list_view.count():
return
message = translate('OpenLP.MediaManagerItem', 'No Search Results')
item = QtWidgets.QListWidgetItem(message)
item.setFlags(QtCore.Qt.NoItemFlags)
font = QtGui.QFont()
font.setItalic(True)
item.setFont(font)
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):
"""
Utility method to check items being submitted for slide generation.

View File

@ -26,7 +26,7 @@ import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry
from openlp.core.common import Registry, UiStrings
class ListWidgetWithDnD(QtWidgets.QListWidget):
@ -37,8 +37,9 @@ class ListWidgetWithDnD(QtWidgets.QListWidget):
"""
Initialise the list widget
"""
super(ListWidgetWithDnD, self).__init__(parent)
super().__init__(parent)
self.mime_data_text = name
self.no_results_text = UiStrings().NoResults
def activateDnD(self):
"""
@ -48,6 +49,19 @@ class ListWidgetWithDnD(QtWidgets.QListWidget):
self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
def clear(self, search_while_typing=False):
"""
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
:return: None
"""
if search_while_typing:
self.no_results_text = UiStrings().ShortResults
else:
self.no_results_text = UiStrings().NoResults
super().clear()
def mouseMoveEvent(self, event):
"""
Drag and drop event does not care what data is selected as the recipient will use events to request the data
@ -102,6 +116,24 @@ class ListWidgetWithDnD(QtWidgets.QListWidget):
listing = os.listdir(local_file)
for file in listing:
files.append(os.path.join(local_file, file))
Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
Registry().execute('{mime_data}_dnd'.format(mime_data=self.mime_data_text),
{'files': files, 'target': self.itemAt(event.pos())})
else:
event.ignore()
def paintEvent(self, event):
"""
Re-implement paintEvent so that we can add 'No Results' text when the listWidget is empty.
:param event: A QPaintEvent
:return: None
"""
super().paintEvent(event)
if not self.count():
viewport = self.viewport()
painter = QtGui.QPainter(viewport)
font = QtGui.QFont()
font.setItalic(True)
painter.setFont(font)
painter.drawText(QtCore.QRect(0, 0, viewport.width(), viewport.height()),
(QtCore.Qt.AlignHCenter | QtCore.Qt.TextWordWrap), self.no_results_text)

View File

@ -75,21 +75,16 @@ class BibleMediaItem(MediaManagerItem):
self.has_search = True
self.search_results = {}
self.second_search_results = {}
self.check_search_result()
Registry().register_function('bibles_load_list', self.reload_bibles)
def __check_second_bible(self, bible, second_bible):
"""
Check if the first item is a second bible item or not.
"""
bitem = self.list_view.item(0)
if not bitem.flags() & QtCore.Qt.ItemIsSelectable:
# The item is the "No Search Results" item.
self.list_view.clear()
if not self.list_view.count():
self.display_results(bible, second_bible)
return
else:
item_second_bible = self._decode_qt_object(bitem, 'second_bible')
item_second_bible = self._decode_qt_object(self.list_view.item(0), 'second_bible')
if item_second_bible and second_bible or not item_second_bible and not second_bible:
self.display_results(bible, second_bible)
elif critical_error_message_box(
@ -542,14 +537,12 @@ class BibleMediaItem(MediaManagerItem):
def on_clear_button_clicked(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_advanced_clear_button_clicked(self):
# The same as the on_clear_button_clicked, but gives focus to Book name field in "Select" (advanced).
self.list_view.clear()
self.check_search_result()
self.advanced_book_combo_box.setFocus()
def on_lock_button_toggled(self, checked):
@ -683,7 +676,6 @@ class BibleMediaItem(MediaManagerItem):
elif self.search_results:
self.display_results(bible, second_bible)
self.advancedSearchButton.setEnabled(True)
self.check_search_result()
self.application.set_normal_cursor()
def on_quick_reference_search(self):
@ -877,7 +869,6 @@ class BibleMediaItem(MediaManagerItem):
elif self.search_results:
self.display_results(bible, second_bible)
self.quickSearchButton.setEnabled(True)
self.check_search_result()
self.application.set_normal_cursor()
def on_quick_search_while_typing(self):
@ -908,7 +899,6 @@ class BibleMediaItem(MediaManagerItem):
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):
@ -947,17 +937,13 @@ class BibleMediaItem(MediaManagerItem):
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)):
elif limit == 8 and (len(text) < limit or len(count_two_chars_text) < 2):
if not self.quickLockButton.isChecked():
self.list_view.clear()
self.check_search_result_search_while_typing_short()
self.list_view.clear(search_while_typing=True)
else:
"""
Start search if no chars are entered or deleted for 0.2 s

View File

@ -129,7 +129,6 @@ class CustomMediaItem(MediaManagerItem):
# Called to redisplay the custom list screen edith from a search
# or from the exit of the Custom edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
self.check_search_result()
def on_new_click(self):
"""
@ -263,7 +262,6 @@ class CustomMediaItem(MediaManagerItem):
CustomSlide.theme_name.like(search_keywords),
order_by_ref=CustomSlide.title)
self.load_list(search_results)
self.check_search_result()
def on_search_text_edit_changed(self, text):
"""

View File

@ -227,7 +227,6 @@ class SongMediaItem(MediaManagerItem):
search_results = self.plugin.manager.get_all_objects(
Song, and_(Song.ccli_number.like(search_string), Song.ccli_number != ''))
self.display_results_cclinumber(search_results)
self.check_search_result()
def search_entire(self, search_keywords):
search_string = '%{text}%'.format(text=clean_string(search_keywords))

View File

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This module contains tests for the openlp.core.lib.listwidgetwithdnd module
"""
from unittest import TestCase
from openlp.core.common.uistrings import UiStrings
from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD
from unittest.mock import MagicMock, patch
class TestListWidgetWithDnD(TestCase):
"""
Test the :class:`~openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD` class
"""
def test_clear(self):
"""
Test the clear method when called without any arguments.
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# WHEN: Calling clear with out any arguments
widget.clear()
# THEN: The results text should be the standard 'no results' text.
self.assertEqual(widget.no_results_text, UiStrings().NoResults)
def test_clear_search_while_typing(self):
"""
Test the clear method when called with the search_while_typing argument set to True
"""
# GIVEN: An instance of ListWidgetWithDnD
widget = ListWidgetWithDnD()
# WHEN: Calling clear with search_while_typing set to True
widget.clear(search_while_typing=True)
# THEN: The results text should be the 'short results' text.
self.assertEqual(widget.no_results_text, UiStrings().ShortResults)
def test_paint_event(self):
"""
Test the paintEvent method when the list is not empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 1
# (i.e the list has an item)
widget = ListWidgetWithDnD()
with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=1), \
patch.object(widget, 'viewport') as mocked_viewport:
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called
mocked_paint_event.assert_called_once_with(mocked_event)
self.assertFalse(mocked_viewport.called)
def test_paint_event_no_items(self):
"""
Test the paintEvent method when the list is empty
"""
# GIVEN: An instance of ListWidgetWithDnD with a mocked out count methode which returns 0
# (i.e the list is empty)
widget = ListWidgetWithDnD()
mocked_painter_instance = MagicMock()
mocked_qrect = MagicMock()
with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.paintEvent') as mocked_paint_event, \
patch.object(widget, 'count', return_value=0), \
patch.object(widget, 'viewport'), \
patch('openlp.core.ui.lib.listwidgetwithdnd.QtGui.QPainter',
return_value=mocked_painter_instance) as mocked_qpainter, \
patch('openlp.core.ui.lib.listwidgetwithdnd.QtCore.QRect', return_value=mocked_qrect):
mocked_event = MagicMock()
# WHEN: Calling paintEvent
widget.paintEvent(mocked_event)
# THEN: The overridden paintEvnet should have been called, and some text should be drawn.
mocked_paint_event.assert_called_once_with(mocked_event)
mocked_qpainter.assert_called_once_with(widget.viewport())
mocked_painter_instance.drawText.assert_called_once_with(mocked_qrect, 4100, 'No Search Results')

View File

@ -155,7 +155,6 @@ class TestMediaItem(TestCase, TestMixin):
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
@ -169,7 +168,6 @@ class TestMediaItem(TestCase, TestMixin):
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')
def test_on_clear_button_clicked(self):
@ -178,7 +176,6 @@ class TestMediaItem(TestCase, TestMixin):
"""
# GIVEN: Mocked list_view, check_search_results & quick_search_edit.
self.media_item.list_view = MagicMock()
self.media_item.check_search_result = MagicMock()
self.media_item.quick_search_edit = MagicMock()
# WHEN: on_clear_button_clicked is called
@ -186,7 +183,6 @@ class TestMediaItem(TestCase, TestMixin):
# THEN: Search result should be reset and search field should receive focus.
self.media_item.list_view.clear.assert_called_once_with(),
self.media_item.check_search_result.assert_called_once_with(),
self.media_item.quick_search_edit.clear.assert_called_once_with(),
self.media_item.quick_search_edit.setFocus.assert_called_once_with()