forked from openlp/openlp
Merge branch 'fixes_june_2' into 'master'
Fixes June 2 See merge request openlp/openlp!210
This commit is contained in:
commit
84d94cb535
@ -60,7 +60,6 @@ def controller_text_api():
|
||||
full_thumbnail_path = AppLocation.get_data_path() / thumbnail_path
|
||||
if not full_thumbnail_path.exists():
|
||||
create_thumb(Path(current_item.get_frame_path(index)), full_thumbnail_path, False)
|
||||
# Registry().get('image_manager').add_image(str(full_thumbnail_path), frame['title'], None, 88, 88)
|
||||
item['img'] = urllib.request.pathname2url(os.path.sep + str(thumbnail_path))
|
||||
item['text'] = str(frame['title'])
|
||||
item['html'] = str(frame['title'])
|
||||
@ -76,7 +75,6 @@ def controller_text_api():
|
||||
data_path = str(AppLocation.get_data_path())
|
||||
if frame['image'][0:len(data_path)] == data_path:
|
||||
item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
|
||||
# Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)
|
||||
item['text'] = str(frame['title'])
|
||||
item['html'] = str(frame['title'])
|
||||
data.append(item)
|
||||
|
@ -60,7 +60,6 @@ def controller_text_api():
|
||||
full_thumbnail_path = AppLocation.get_data_path() / thumbnail_path
|
||||
if not full_thumbnail_path.exists():
|
||||
create_thumb(Path(current_item.get_frame_path(index)), full_thumbnail_path, False)
|
||||
# Registry().get('image_manager').add_image(str(full_thumbnail_path), frame['title'], None, 88, 88)
|
||||
item['img'] = urllib.request.pathname2url(os.path.sep + str(thumbnail_path))
|
||||
item['text'] = str(frame['title'])
|
||||
item['html'] = str(frame['title'])
|
||||
@ -76,7 +75,6 @@ def controller_text_api():
|
||||
data_path = str(AppLocation.get_data_path())
|
||||
if frame['image'][0:len(data_path)] == data_path:
|
||||
item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
|
||||
# Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)
|
||||
item['text'] = str(frame['title'])
|
||||
item['html'] = str(frame['title'])
|
||||
data.append(item)
|
||||
|
@ -114,7 +114,6 @@ class RegistryProperties(object):
|
||||
"""
|
||||
_application = None
|
||||
_plugin_manager = None
|
||||
_image_manager = None
|
||||
_media_controller = None
|
||||
_service_manager = None
|
||||
_preview_controller = None
|
||||
@ -149,15 +148,6 @@ class RegistryProperties(object):
|
||||
self._plugin_manager = Registry().get('plugin_manager')
|
||||
return self._plugin_manager
|
||||
|
||||
@property
|
||||
def image_manager(self):
|
||||
"""
|
||||
Adds the image manager to the class dynamically
|
||||
"""
|
||||
if not hasattr(self, '_image_manager') or not self._image_manager:
|
||||
self._image_manager = Registry().get('image_manager')
|
||||
return self._image_manager
|
||||
|
||||
@property
|
||||
def media_controller(self):
|
||||
"""
|
||||
|
@ -756,13 +756,13 @@ var Display = {
|
||||
* Set image slides
|
||||
* @param {Object[]} slides - A list of images to add as JS objects [{"path": "url/to/file"}]
|
||||
*/
|
||||
setImageSlides: function (slides) {
|
||||
setImageSlides: function (slides, background) {
|
||||
Display._clearSlidesList();
|
||||
var parentSection = document.createElement("section");
|
||||
slides.forEach(function (slide, index) {
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("id", index);
|
||||
section.setAttribute("data-background", "#000");
|
||||
section.setAttribute("data-background", background);
|
||||
section.setAttribute("style", "height: 100%; width: 100%;");
|
||||
var img = document.createElement('img');
|
||||
img.src = slide.path;
|
||||
|
@ -326,7 +326,9 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
||||
else:
|
||||
image['thumbnail'] = image['path']
|
||||
json_images = json.dumps(imagesr)
|
||||
self.run_javascript('Display.setImageSlides({images});'.format(images=json_images))
|
||||
background = self.settings.value('images/background color')
|
||||
self.run_javascript('Display.setImageSlides({images}, "{background}");'.format(images=json_images,
|
||||
background=background))
|
||||
|
||||
def load_video(self, video):
|
||||
"""
|
||||
|
@ -1,353 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# 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, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
"""
|
||||
Provides the store and management for Images automatically caching them and resizing them when needed. Only one copy of
|
||||
each image is needed in the system. A Thread is used to convert the image to a byte array so the user does not need to
|
||||
wait for the conversion to happen.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import time
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import image_to_byte, resize_image
|
||||
from openlp.core.threading import ThreadWorker, run_thread
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ImageWorker(ThreadWorker):
|
||||
"""
|
||||
A thread worker class to speed up the display of images. This is threaded so it loads the frames and generates
|
||||
byte stream in background.
|
||||
"""
|
||||
def __init__(self, manager):
|
||||
"""
|
||||
Constructor for the thread class.
|
||||
|
||||
``manager``
|
||||
The image manager.
|
||||
"""
|
||||
super().__init__()
|
||||
self.image_manager = manager
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the worker
|
||||
"""
|
||||
self.image_manager.process()
|
||||
self.quit.emit()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the worker
|
||||
"""
|
||||
self.image_manager.stop_manager = True
|
||||
|
||||
|
||||
class Priority(object):
|
||||
"""
|
||||
Enumeration class for different priorities.
|
||||
|
||||
``Lowest``
|
||||
Only the image's byte stream has to be generated. But neither the ``QImage`` nor the byte stream has been
|
||||
requested yet.
|
||||
|
||||
``Low``
|
||||
Only the image's byte stream has to be generated. Because the image's ``QImage`` has been requested previously
|
||||
it is reasonable to assume that the byte stream will be needed before the byte stream of other images whose
|
||||
``QImage`` were not generated due to a request.
|
||||
|
||||
``Normal``
|
||||
The image's byte stream as well as the image has to be generated. Neither the ``QImage`` nor the byte stream has
|
||||
been requested yet.
|
||||
|
||||
``High``
|
||||
The image's byte stream as well as the image has to be generated. The ``QImage`` for this image has been
|
||||
requested. **Note**, this priority is only set when the ``QImage`` has not been generated yet.
|
||||
|
||||
``Urgent``
|
||||
The image's byte stream as well as the image has to be generated. The byte stream for this image has been
|
||||
requested. **Note**, this priority is only set when the byte stream has not been generated yet.
|
||||
"""
|
||||
Lowest = 4
|
||||
Low = 3
|
||||
Normal = 2
|
||||
High = 1
|
||||
Urgent = 0
|
||||
|
||||
|
||||
class Image(object):
|
||||
"""
|
||||
This class represents an image. To mark an image as *dirty* call the :class:`ImageManager`'s ``_reset_image`` method
|
||||
with the Image instance as argument.
|
||||
"""
|
||||
secondary_priority = 0
|
||||
|
||||
def __init__(self, path, source, background, width=-1, height=-1):
|
||||
"""
|
||||
Create an image for the :class:`ImageManager`'s cache.
|
||||
|
||||
:param path: The image's file path. This should be an existing file path.
|
||||
:param source: The source describes the image's origin. Possible values are described in the
|
||||
:class:`~openlp.core.lib.ImageSource` class.
|
||||
:param background: A ``QtGui.QColor`` object specifying the colour to be used to fill the gabs if the image's
|
||||
ratio does not match with the display ratio.
|
||||
:param width: The width of the image, defaults to -1 meaning that the screen width will be used.
|
||||
:param height: The height of the image, defaults to -1 meaning that the screen height will be used.
|
||||
"""
|
||||
if not os.path.exists(path):
|
||||
raise FileNotFoundError('{path} not found'.format(path=path))
|
||||
self.path = path
|
||||
self.image = None
|
||||
self.image_bytes = None
|
||||
self.priority = Priority.Normal
|
||||
self.source = source
|
||||
self.background = background
|
||||
self.timestamp = 0
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.timestamp = os.stat(path).st_mtime
|
||||
self.secondary_priority = Image.secondary_priority
|
||||
Image.secondary_priority += 1
|
||||
|
||||
|
||||
class PriorityQueue(queue.PriorityQueue):
|
||||
"""
|
||||
Customised ``queue.PriorityQueue``.
|
||||
|
||||
Each item in the queue must be a tuple with three values. The first value is the :class:`Image`'s ``priority``
|
||||
attribute, the second value the :class:`Image`'s ``secondary_priority`` attribute. The last value the :class:`Image`
|
||||
instance itself::
|
||||
|
||||
(image.priority, image.secondary_priority, image)
|
||||
|
||||
Doing this, the :class:`Queue.PriorityQueue` will sort the images according to their priorities, but also according
|
||||
to there number. However, the number only has an impact on the result if there are more images with the same
|
||||
priority. In such case the image which has been added earlier is privileged.
|
||||
"""
|
||||
def modify_priority(self, image, new_priority):
|
||||
"""
|
||||
Modifies the priority of the given ``image``.
|
||||
|
||||
:param image: The image to remove. This should be an :class:`Image` instance.
|
||||
:param new_priority: The image's new priority. See the :class:`Priority` class for priorities.
|
||||
"""
|
||||
self.remove(image)
|
||||
image.priority = new_priority
|
||||
self.put((image.priority, image.secondary_priority, image))
|
||||
|
||||
def remove(self, image):
|
||||
"""
|
||||
Removes the given ``image`` from the queue.
|
||||
|
||||
:param image: The image to remove. This should be an ``Image`` instance.
|
||||
"""
|
||||
if (image.priority, image.secondary_priority, image) in self.queue:
|
||||
self.queue.remove((image.priority, image.secondary_priority, image))
|
||||
|
||||
|
||||
class ImageManager(QtCore.QObject):
|
||||
"""
|
||||
Image Manager handles the conversion and sizing of images.
|
||||
"""
|
||||
log.info('Image Manager loaded')
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Constructor for the image manager.
|
||||
"""
|
||||
super(ImageManager, self).__init__()
|
||||
Registry().register('image_manager', self)
|
||||
current_screen = ScreenList().current
|
||||
self.width = current_screen.display_geometry.width()
|
||||
self.height = current_screen.display_geometry.height()
|
||||
self._cache = {}
|
||||
self._conversion_queue = PriorityQueue()
|
||||
self.stop_manager = False
|
||||
Registry().register_function('images_regenerate', self.process_updates)
|
||||
|
||||
def update_display(self):
|
||||
"""
|
||||
Screen has changed size so rebuild the cache to new size.
|
||||
"""
|
||||
log.debug('update_display')
|
||||
current_screen = ScreenList().current
|
||||
self.width = current_screen.display_geometry.width()
|
||||
self.height = current_screen.display_geometry.height()
|
||||
# Mark the images as dirty for a rebuild by setting the image and byte stream to None.
|
||||
for image in list(self._cache.values()):
|
||||
self._reset_image(image)
|
||||
|
||||
def update_images_border(self, source, background):
|
||||
"""
|
||||
Border has changed so update all the images affected.
|
||||
"""
|
||||
log.debug('update_images_border')
|
||||
# Mark the images as dirty for a rebuild by setting the image and byte stream to None.
|
||||
for image in list(self._cache.values()):
|
||||
if image.source == source:
|
||||
image.background = background
|
||||
self._reset_image(image)
|
||||
|
||||
def update_image_border(self, path, source, background, width=-1, height=-1):
|
||||
"""
|
||||
Border has changed so update the image affected.
|
||||
"""
|
||||
log.debug('update_image_border')
|
||||
# Mark the image as dirty for a rebuild by setting the image and byte stream to None.
|
||||
image = self._cache[(path, source, width, height)]
|
||||
if image.source == source:
|
||||
image.background = background
|
||||
self._reset_image(image)
|
||||
|
||||
def _reset_image(self, image):
|
||||
"""
|
||||
Mark the given :class:`Image` instance as dirty by setting its ``image`` and ``image_bytes`` attributes to None.
|
||||
"""
|
||||
image.image = None
|
||||
image.image_bytes = None
|
||||
self._conversion_queue.modify_priority(image, Priority.Normal)
|
||||
|
||||
def process_updates(self):
|
||||
"""
|
||||
Flush the queue to updated any data to update
|
||||
"""
|
||||
try:
|
||||
worker = ImageWorker(self)
|
||||
run_thread(worker, 'image_manager')
|
||||
except KeyError:
|
||||
# run_thread() will throw a KeyError if this thread already exists, so ignore it so that we don't
|
||||
# try to start another thread when one is already running
|
||||
pass
|
||||
|
||||
def get_image(self, path, source, width=-1, height=-1):
|
||||
"""
|
||||
Return the ``QImage`` from the cache. If not present wait for the background thread to process it.
|
||||
|
||||
:param: path: The image path
|
||||
:param: source: The source of the image
|
||||
:param: background: The image background colour
|
||||
:param: width: The processed image width
|
||||
:param: height: The processed image height
|
||||
"""
|
||||
log.debug('get_image {path} {source} {width} {height}'.format(path=path, source=source,
|
||||
width=width, height=height))
|
||||
image = self._cache[(path, source, width, height)]
|
||||
if image.image is None:
|
||||
self._conversion_queue.modify_priority(image, Priority.High)
|
||||
# make sure we are running and if not give it a kick
|
||||
self.process_updates()
|
||||
while image.image is None:
|
||||
log.debug('getImage - waiting')
|
||||
time.sleep(0.1)
|
||||
elif image.image_bytes is None:
|
||||
# Set the priority to Low, because the image was requested but the byte stream was not generated yet.
|
||||
# However, we only need to do this, when the image was generated before it was requested (otherwise this is
|
||||
# already taken care of).
|
||||
self._conversion_queue.modify_priority(image, Priority.Low)
|
||||
return image.image
|
||||
|
||||
def get_image_bytes(self, path, source, width=-1, height=-1):
|
||||
"""
|
||||
Returns the byte string for an image. If not present wait for the background thread to process it.
|
||||
|
||||
:param: path: The image path
|
||||
:param: source: The source of the image
|
||||
:param: background: The image background colour
|
||||
:param: width: The processed image width
|
||||
:param: height: The processed image height
|
||||
"""
|
||||
log.debug('get_image_bytes {path} {source} {width} {height}'.format(path=path, source=source,
|
||||
width=width, height=height))
|
||||
image = self._cache[(path, source, width, height)]
|
||||
if image.image_bytes is None:
|
||||
self._conversion_queue.modify_priority(image, Priority.Urgent)
|
||||
# make sure we are running and if not give it a kick
|
||||
self.process_updates()
|
||||
while image.image_bytes is None:
|
||||
log.debug('getImageBytes - waiting')
|
||||
time.sleep(0.1)
|
||||
return image.image_bytes
|
||||
|
||||
def add_image(self, path, source, background, width=-1, height=-1):
|
||||
"""
|
||||
Add image to cache if it is not already there.
|
||||
|
||||
:param: path: The image path
|
||||
:param: source: The source of the image
|
||||
:param: background: The image background colour
|
||||
:param: width: The processed image width
|
||||
:param: height: The processed image height
|
||||
"""
|
||||
log.debug('add_image {path} {source} {width} {height}'.format(path=path, source=source,
|
||||
width=width, height=height))
|
||||
if not (path, source, width, height) in self._cache:
|
||||
image = Image(path, source, background, width, height)
|
||||
self._cache[(path, source, width, height)] = image
|
||||
self._conversion_queue.put((image.priority, image.secondary_priority, image))
|
||||
# Check if the there are any images with the same path and check if the timestamp has changed.
|
||||
for image in list(self._cache.values()):
|
||||
if os.path.exists(path):
|
||||
if image.path == path and image.timestamp != os.stat(path).st_mtime:
|
||||
image.timestamp = os.stat(path).st_mtime
|
||||
self._reset_image(image)
|
||||
self.process_updates()
|
||||
|
||||
def process(self):
|
||||
"""
|
||||
Controls the processing called from a ``QtCore.QThread``.
|
||||
"""
|
||||
log.debug('process - started')
|
||||
while not self._conversion_queue.empty() and not self.stop_manager:
|
||||
self._process_cache()
|
||||
log.debug('_process - ended')
|
||||
|
||||
def _process_cache(self):
|
||||
"""
|
||||
Actually does the work.
|
||||
"""
|
||||
log.debug('_processCache')
|
||||
image = self._conversion_queue.get()[2]
|
||||
# Generate the QImage for the image.
|
||||
if image.image is None:
|
||||
# Let's see if the image was requested with specific dimensions
|
||||
width = self.width if image.width == -1 else image.width
|
||||
height = self.height if image.height == -1 else image.height
|
||||
image.image = resize_image(image.path, width, height, image.background,
|
||||
Registry().get('settings').value('advanced/ignore aspect ratio'))
|
||||
# Set the priority to Lowest and stop here as we need to process more important images first.
|
||||
if image.priority == Priority.Normal:
|
||||
self._conversion_queue.modify_priority(image, Priority.Lowest)
|
||||
return
|
||||
# For image with high priority we set the priority to Low, as the byte stream might be needed earlier the
|
||||
# byte stream of image with Normal priority. We stop here as we need to process more important images first.
|
||||
elif image.priority == Priority.High:
|
||||
self._conversion_queue.modify_priority(image, Priority.Low)
|
||||
return
|
||||
# Generate the byte stream for the image.
|
||||
if image.image_bytes is None:
|
||||
image.image_bytes = image_to_byte(image.image)
|
@ -47,7 +47,6 @@ class PluginManager(RegistryBase, LogMixin, RegistryProperties):
|
||||
super(PluginManager, self).__init__(parent)
|
||||
self.log_info('Plugin manager Initialising')
|
||||
self.log_debug('Base path {path}'.format(path=AppLocation.get_directory(AppLocation.PluginsDir)))
|
||||
self.plugins = []
|
||||
self.log_info('Plugin manager Initialised')
|
||||
|
||||
def bootstrap_initialise(self):
|
||||
|
@ -96,7 +96,6 @@ class ServiceItem(RegistryProperties):
|
||||
self.end_time = 0
|
||||
self.media_length = 0
|
||||
self.from_service = False
|
||||
self.image_border = '#000000'
|
||||
self.background_audio = []
|
||||
self.theme_overwritten = False
|
||||
self.temporary_edit = False
|
||||
@ -279,17 +278,15 @@ class ServiceItem(RegistryProperties):
|
||||
self._print_slides.append(slide)
|
||||
return self._print_slides
|
||||
|
||||
def add_from_image(self, path, title, background=None, thumbnail=None, file_hash=None):
|
||||
def add_from_image(self, path, title, thumbnail=None, file_hash=None):
|
||||
"""
|
||||
Add an image slide to the service item.
|
||||
|
||||
:param path: The directory in which the image file is located.
|
||||
:param title: A title for the slide in the service item.
|
||||
:param background: The background colour
|
||||
:param thumbnail: Optional alternative thumbnail, used for remote thumbnails.
|
||||
:param file_hash: Unique Reference to file .
|
||||
"""
|
||||
if background:
|
||||
self.image_border = background
|
||||
self.service_item_type = ServiceItemType.Image
|
||||
if not file_hash:
|
||||
file_hash = sha256_file_hash(path)
|
||||
@ -297,7 +294,6 @@ class ServiceItem(RegistryProperties):
|
||||
if thumbnail:
|
||||
slide['thumbnail'] = thumbnail
|
||||
self.slides.append(slide)
|
||||
# self.image_manager.add_image(path, ImageSource.ImagePlugin, self.image_border)
|
||||
self._new_item()
|
||||
|
||||
def add_from_text(self, text, verse_tag=None):
|
||||
@ -346,8 +342,6 @@ class ServiceItem(RegistryProperties):
|
||||
ntpath.basename(image)
|
||||
self.slides.append({'title': file_name, 'image': image, 'path': path, 'display_title': display_title,
|
||||
'notes': notes, 'thumbnail': image})
|
||||
# if self.is_capable(ItemCapabilities.HasThumbnails):
|
||||
# self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000')
|
||||
self._new_item()
|
||||
|
||||
def get_service_repr(self, lite_save):
|
||||
@ -496,8 +490,6 @@ class ServiceItem(RegistryProperties):
|
||||
self.add_from_text(slide['raw_slide'], slide['verseTag'])
|
||||
self._create_slides()
|
||||
elif self.service_item_type == ServiceItemType.Image:
|
||||
settings_section = service_item['serviceitem']['header']['name']
|
||||
background = QtGui.QColor(self.settings.value(settings_section + '/background color'))
|
||||
if path:
|
||||
self.has_original_file_path = False
|
||||
for text_image in service_item['serviceitem']['data']:
|
||||
@ -522,7 +514,7 @@ class ServiceItem(RegistryProperties):
|
||||
test_thumb = AppLocation.get_section_data_path(self.name) / 'thumbnails' / new_file
|
||||
if test_thumb.exists():
|
||||
thumbnail = test_thumb
|
||||
self.add_from_image(file_path, text_image, background, thumbnail=thumbnail, file_hash=file_hash)
|
||||
self.add_from_image(file_path, text_image, thumbnail=thumbnail, file_hash=file_hash)
|
||||
else:
|
||||
for text_image in service_item['serviceitem']['data']:
|
||||
file_hash = None
|
||||
@ -540,7 +532,7 @@ class ServiceItem(RegistryProperties):
|
||||
test_thumb = AppLocation.get_section_data_path(self.name) / 'thumbnails' / new_file
|
||||
if test_thumb.exists():
|
||||
thumbnail = test_thumb
|
||||
self.add_from_image(file_path, text, background, thumbnail=thumbnail, file_hash=file_hash)
|
||||
self.add_from_image(file_path, text, thumbnail=thumbnail, file_hash=file_hash)
|
||||
elif self.service_item_type == ServiceItemType.Command:
|
||||
if version < 3:
|
||||
# If this is an old servicefile with files included, we need to rename the bundled files to match
|
||||
|
@ -991,7 +991,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
||||
The screen has changed so we have to update components such as the renderer.
|
||||
"""
|
||||
self.application.set_busy_cursor()
|
||||
# self.image_manager.update_display()
|
||||
self.renderer.resize(self.live_controller.screens.current.display_geometry.size())
|
||||
self.preview_controller.screen_size_changed()
|
||||
self.live_controller.setup_displays()
|
||||
|
@ -553,7 +553,6 @@ class ImageMediaItem(MediaManagerItem):
|
||||
:param context: Why is it being generated
|
||||
:param kwargs: Consume other unused args specified by the base implementation, but not use by this one.
|
||||
"""
|
||||
background = QtGui.QColor(self.settings.value('images/background color'))
|
||||
if item:
|
||||
items = [item]
|
||||
else:
|
||||
@ -611,7 +610,7 @@ class ImageMediaItem(MediaManagerItem):
|
||||
for image in images:
|
||||
name = image.file_path.name
|
||||
thumbnail_path = self.generate_thumbnail_path(image)
|
||||
service_item.add_from_image(image.file_path, name, background, thumbnail_path)
|
||||
service_item.add_from_image(image.file_path, name, thumbnail_path)
|
||||
return True
|
||||
|
||||
def check_group_exists(self, new_group):
|
||||
|
@ -231,13 +231,13 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
|
||||
filters += '{text} (*)'.format(text=UiStrings().AllFiles)
|
||||
file_paths, filter_used = FileDialog.getOpenFileNames(
|
||||
self, title,
|
||||
self.settings.value('presentations/last directory import'), filters)
|
||||
self.settings.value('songs/last directory import'), filters)
|
||||
for file_path in file_paths:
|
||||
list_item = QtWidgets.QListWidgetItem(str(file_path))
|
||||
list_item.setData(QtCore.Qt.UserRole, file_path)
|
||||
listbox.addItem(list_item)
|
||||
if file_paths:
|
||||
self.settings.setValue('song/last directory import', file_paths[0].parent)
|
||||
self.settings.setValue('songs/last directory import', file_paths[0].parent)
|
||||
|
||||
def get_list_of_paths(self, list_box):
|
||||
"""
|
||||
@ -348,7 +348,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
|
||||
:rtype: None
|
||||
"""
|
||||
file_path, filter_used = FileDialog.getSaveFileName(
|
||||
self, self.settings.value(self.plugin.settings_section + '/last directory import'))
|
||||
self, self.settings.value('songs/last directory import'))
|
||||
if file_path is None:
|
||||
return
|
||||
file_path.write_text(self.error_report_text_edit.toPlainText(), encoding='utf-8')
|
||||
@ -399,7 +399,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
|
||||
path_edit.filters = filters + ';;' + path_edit.filters
|
||||
else:
|
||||
path_edit.filters = filters
|
||||
path_edit.path = self.settings.value(self.plugin.settings_section + '/last directory import')
|
||||
path_edit.path = self.settings.value('songs/last directory import')
|
||||
file_path_layout.addWidget(path_edit)
|
||||
import_layout.addLayout(file_path_layout)
|
||||
import_layout.addSpacerItem(self.stack_spacer)
|
||||
|
@ -1,298 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2020 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, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# 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, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui package.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
from threading import Lock
|
||||
from unittest import TestCase, skip
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtGui
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib.imagemanager import ImageManager, ImageWorker, Priority, PriorityQueue
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from tests.utils.constants import RESOURCE_PATH
|
||||
|
||||
|
||||
TEST_PATH = str(RESOURCE_PATH)
|
||||
|
||||
|
||||
@skip('Probably not going to use ImageManager')
|
||||
class TestImageWorker(TestCase, TestMixin):
|
||||
"""
|
||||
Test all the methods in the ImageWorker class
|
||||
"""
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the constructor of the ImageWorker
|
||||
"""
|
||||
# GIVEN: An ImageWorker class and a mocked ImageManager
|
||||
mocked_image_manager = MagicMock()
|
||||
|
||||
# WHEN: Creating the ImageWorker
|
||||
worker = ImageWorker(mocked_image_manager)
|
||||
|
||||
# THEN: The image_manager attribute should be set correctly
|
||||
assert worker.image_manager is mocked_image_manager, \
|
||||
'worker.image_manager should have been the mocked_image_manager'
|
||||
|
||||
@patch('openlp.core.lib.imagemanager.ThreadWorker.quit')
|
||||
def test_start(self, mocked_quit):
|
||||
"""
|
||||
Test that the start() method of the image worker calls the process method and then emits quit.
|
||||
"""
|
||||
# GIVEN: A mocked image_manager and a new image worker
|
||||
mocked_image_manager = MagicMock()
|
||||
worker = ImageWorker(mocked_image_manager)
|
||||
|
||||
# WHEN: start() is called
|
||||
worker.start()
|
||||
|
||||
# THEN: process() should have been called and quit should have been emitted
|
||||
mocked_image_manager.process.assert_called_once_with()
|
||||
mocked_quit.emit.assert_called_once_with()
|
||||
|
||||
def test_stop(self):
|
||||
"""
|
||||
Test that the stop method does the right thing
|
||||
"""
|
||||
# GIVEN: A mocked image_manager and a worker
|
||||
mocked_image_manager = MagicMock()
|
||||
worker = ImageWorker(mocked_image_manager)
|
||||
|
||||
# WHEN: The stop() method is called
|
||||
worker.stop()
|
||||
|
||||
# THEN: The stop_manager attrivute should have been set to True
|
||||
assert mocked_image_manager.stop_manager is True, 'mocked_image_manager.stop_manager should have been True'
|
||||
|
||||
|
||||
@skip('Probably not going to use ImageManager')
|
||||
class TestPriorityQueue(TestCase, TestMixin):
|
||||
"""
|
||||
Test the PriorityQueue class
|
||||
"""
|
||||
@patch('openlp.core.lib.imagemanager.PriorityQueue.remove')
|
||||
@patch('openlp.core.lib.imagemanager.PriorityQueue.put')
|
||||
def test_modify_priority(self, mocked_put, mocked_remove):
|
||||
"""
|
||||
Test the modify_priority() method of PriorityQueue
|
||||
"""
|
||||
# GIVEN: An instance of a PriorityQueue and a mocked image
|
||||
mocked_image = MagicMock()
|
||||
mocked_image.priority = Priority.Normal
|
||||
mocked_image.secondary_priority = Priority.Low
|
||||
queue = PriorityQueue()
|
||||
|
||||
# WHEN: modify_priority is called with a mocked image and a new priority
|
||||
queue.modify_priority(mocked_image, Priority.High)
|
||||
|
||||
# THEN: The remove() method should have been called, image priority updated and put() called
|
||||
mocked_remove.assert_called_once_with(mocked_image)
|
||||
assert mocked_image.priority == Priority.High, 'The priority should have been Priority.High'
|
||||
mocked_put.assert_called_once_with((Priority.High, Priority.Low, mocked_image))
|
||||
|
||||
def test_remove(self):
|
||||
"""
|
||||
Test the remove() method of PriorityQueue
|
||||
"""
|
||||
# GIVEN: A PriorityQueue instance with a mocked image and queue
|
||||
mocked_image = MagicMock()
|
||||
mocked_image.priority = Priority.High
|
||||
mocked_image.secondary_priority = Priority.Normal
|
||||
queue = PriorityQueue()
|
||||
|
||||
# WHEN: An image is removed
|
||||
with patch.object(queue, 'queue') as mocked_queue:
|
||||
mocked_queue.__contains__.return_value = True
|
||||
queue.remove(mocked_image)
|
||||
|
||||
# THEN: The mocked queue.remove() method should have been called
|
||||
mocked_queue.remove.assert_called_once_with((Priority.High, Priority.Normal, mocked_image))
|
||||
|
||||
|
||||
@skip('Probably not going to use ImageManager')
|
||||
class TestImageManager(TestCase, TestMixin):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
Registry.create()
|
||||
self.setup_application()
|
||||
ScreenList.create(self.app.desktop())
|
||||
self.image_manager = ImageManager()
|
||||
self.lock = Lock()
|
||||
self.sleep_time = 0.1
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Delete all the C++ objects at the end so that we don't have a segfault
|
||||
"""
|
||||
self.image_manager.stop_manager = True
|
||||
del self.app
|
||||
|
||||
@patch('openlp.core.lib.imagemanager.run_thread')
|
||||
def test_basic_image_manager(self, mocked_run_thread):
|
||||
"""
|
||||
Test the Image Manager setup basic functionality
|
||||
"""
|
||||
# GIVEN: the an image add to the image manager
|
||||
full_path = os.path.normpath(os.path.join(TEST_PATH, 'church.jpg'))
|
||||
self.image_manager.add_image(full_path, 'church.jpg', None)
|
||||
|
||||
# WHEN the image is retrieved
|
||||
image = self.image_manager.get_image(full_path, 'church.jpg')
|
||||
|
||||
# THEN returned record is a type of image
|
||||
assert isinstance(image, QtGui.QImage), 'The returned object should be a QImage'
|
||||
|
||||
# WHEN: The image bytes are requested.
|
||||
byte_array = self.image_manager.get_image_bytes(full_path, 'church.jpg')
|
||||
|
||||
# THEN: Type should be a str.
|
||||
assert isinstance(byte_array, str), 'The returned object should be a str'
|
||||
|
||||
# WHEN the image is retrieved has not been loaded
|
||||
# THEN a KeyError is thrown
|
||||
with self.assertRaises(KeyError) as context:
|
||||
self.image_manager.get_image(TEST_PATH, 'church1.jpg')
|
||||
assert context.exception != '', 'KeyError exception should have been thrown for missing image'
|
||||
|
||||
@patch('openlp.core.lib.imagemanager.run_thread')
|
||||
def test_different_dimension_image(self, mocked_run_thread):
|
||||
"""
|
||||
Test the Image Manager with dimensions
|
||||
"""
|
||||
# GIVEN: add an image with specific dimensions
|
||||
full_path = os.path.normpath(os.path.join(TEST_PATH, 'church.jpg'))
|
||||
self.image_manager.add_image(full_path, 'church.jpg', None, 80, 80)
|
||||
|
||||
# WHEN: the image is retrieved
|
||||
image = self.image_manager.get_image(full_path, 'church.jpg', 80, 80)
|
||||
|
||||
# THEN: The return should be of type image
|
||||
assert isinstance(image, QtGui.QImage), 'The returned object should be a QImage'
|
||||
|
||||
# WHEN: adding the same image with different dimensions
|
||||
self.image_manager.add_image(full_path, 'church.jpg', None, 100, 100)
|
||||
|
||||
# THEN: the cache should contain two pictures
|
||||
assert len(self.image_manager._cache) == 2, \
|
||||
'Image manager should consider two dimensions of the same picture as different'
|
||||
|
||||
# WHEN: adding the same image with first dimensions
|
||||
self.image_manager.add_image(full_path, 'church.jpg', None, 80, 80)
|
||||
|
||||
# THEN: the cache should still contain only two pictures
|
||||
assert len(self.image_manager._cache) == 2, 'Same dimensions should not be added again'
|
||||
|
||||
# WHEN: calling with correct image, but wrong dimensions
|
||||
with self.assertRaises(KeyError) as context:
|
||||
self.image_manager.get_image(full_path, 'church.jpg', 120, 120)
|
||||
assert context.exception != '', 'KeyError exception should have been thrown for missing dimension'
|
||||
|
||||
@patch('openlp.core.lib.imagemanager.resize_image')
|
||||
@patch('openlp.core.lib.imagemanager.image_to_byte')
|
||||
@patch('openlp.core.lib.imagemanager.run_thread')
|
||||
def test_process_cache(self, mocked_run_thread, mocked_image_to_byte, mocked_resize_image):
|
||||
"""
|
||||
Test the process_cache method
|
||||
"""
|
||||
# GIVEN: Mocked functions
|
||||
mocked_resize_image.side_effect = self.mocked_resize_image
|
||||
mocked_image_to_byte.side_effect = self.mocked_image_to_byte
|
||||
image1 = 'church.jpg'
|
||||
image2 = 'church2.jpg'
|
||||
image3 = 'church3.jpg'
|
||||
image4 = 'church4.jpg'
|
||||
|
||||
# WHEN: Add the images. Then get the lock (=queue can not be processed).
|
||||
self.lock.acquire()
|
||||
self.image_manager.add_image(TEST_PATH, image1, None)
|
||||
self.image_manager.add_image(TEST_PATH, image2, None)
|
||||
|
||||
# THEN: All images have been added to the queue, and only the first image is not be in the list anymore, but
|
||||
# is being processed (see mocked methods/functions).
|
||||
# Note: Priority.Normal means, that the resize_image() was not completed yet (because afterwards the #
|
||||
# priority is adjusted to Priority.Lowest).
|
||||
assert self.get_image_priority(image1) == Priority.Normal, "image1's priority should be 'Priority.Normal'"
|
||||
assert self.get_image_priority(image2) == Priority.Normal, "image2's priority should be 'Priority.Normal'"
|
||||
|
||||
# WHEN: Add more images.
|
||||
self.image_manager.add_image(TEST_PATH, image3, None)
|
||||
self.image_manager.add_image(TEST_PATH, image4, None)
|
||||
# Allow the queue to process.
|
||||
self.lock.release()
|
||||
# Request some "data".
|
||||
self.image_manager.get_image_bytes(TEST_PATH, image4)
|
||||
self.image_manager.get_image(TEST_PATH, image3)
|
||||
# Now the mocked methods/functions do not have to sleep anymore.
|
||||
self.sleep_time = 0
|
||||
# Wait for the queue to finish.
|
||||
while not self.image_manager._conversion_queue.empty():
|
||||
time.sleep(0.1)
|
||||
# Because empty() is not reliable, wait a litte; just to make sure.
|
||||
time.sleep(0.1)
|
||||
# THEN: The images' priority reflect how they were processed.
|
||||
assert self.image_manager._conversion_queue.qsize() == 0, "The queue should be empty."
|
||||
assert self.get_image_priority(image1) == Priority.Lowest, \
|
||||
"The image should have not been requested (=Lowest)"
|
||||
assert self.get_image_priority(image2) == Priority.Lowest, \
|
||||
"The image should have not been requested (=Lowest)"
|
||||
assert self.get_image_priority(image3) == Priority.Low, \
|
||||
"Only the QImage should have been requested (=Low)."
|
||||
assert self.get_image_priority(image4) == Priority.Urgent, \
|
||||
"The image bytes should have been requested (=Urgent)."
|
||||
|
||||
def get_image_priority(self, image):
|
||||
"""
|
||||
This is a help method to get the priority of the given image out of the image_manager's cache.
|
||||
|
||||
NOTE: This requires, that the image has been added to the image manager using the *TEST_PATH*.
|
||||
|
||||
:param image: The name of the image. E. g. ``image1``
|
||||
"""
|
||||
return self.image_manager._cache[(TEST_PATH, image, -1, -1)].priority
|
||||
|
||||
def mocked_resize_image(self, *args):
|
||||
"""
|
||||
This is a mocked method, so that we can control the work flow of the image manager.
|
||||
"""
|
||||
self.lock.acquire()
|
||||
self.lock.release()
|
||||
# The sleep time is adjusted in the test case.
|
||||
time.sleep(self.sleep_time)
|
||||
return QtGui.QImage()
|
||||
|
||||
def mocked_image_to_byte(self, *args):
|
||||
"""
|
||||
This is a mocked method, so that we can control the work flow of the image manager.
|
||||
"""
|
||||
self.lock.acquire()
|
||||
self.lock.release()
|
||||
# The sleep time is adjusted in the test case.
|
||||
time.sleep(self.sleep_time)
|
||||
return ''
|
@ -150,8 +150,6 @@ def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(registry, state
|
||||
# THEN: The create_settings_tab() method should not have been called, but the plugins lists should be the same
|
||||
assert 0 == mocked_plugin.create_settings_tab.call_count, \
|
||||
'The create_media_manager_item() method should not have been called.'
|
||||
assert mocked_settings_form.plugin_manager.plugins == plugin_manager.plugins, \
|
||||
'The plugins on the settings form should be the same as the plugins in the plugin manager'
|
||||
|
||||
|
||||
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(registry, state):
|
||||
@ -175,8 +173,6 @@ def test_hook_settings_tabs_with_active_plugin_and_mocked_form(registry, state):
|
||||
# THEN: The create_media_manager_item() method should have been called with the mocked settings form
|
||||
assert 1 == mocked_plugin.create_settings_tab.call_count, \
|
||||
'The create_media_manager_item() method should have been called once.'
|
||||
assert plugin_manager.plugins == mocked_settings_form.plugin_manager.plugins, \
|
||||
'The plugins on the settings form should be the same as the plugins in the plugin manager'
|
||||
|
||||
|
||||
def test_hook_settings_tabs_with_active_plugin_and_no_form(plugin_manager_env):
|
||||
|
@ -72,7 +72,6 @@ def service_item_env(state):
|
||||
mocked_slide_formater = MagicMock(side_effect=side_effect_return_arg)
|
||||
mocked_renderer.format_slide = mocked_slide_formater
|
||||
Registry().register('renderer', mocked_renderer)
|
||||
Registry().register('image_manager', MagicMock())
|
||||
|
||||
|
||||
def test_service_item_basic(settings):
|
||||
@ -266,11 +265,10 @@ def test_add_from_command_without_display_title_and_notes():
|
||||
assert service_item.get_frames()[0] == frame, 'Frames should match'
|
||||
|
||||
|
||||
@patch('openlp.core.lib.serviceitem.ServiceItem.image_manager')
|
||||
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
|
||||
def test_add_from_command_for_a_presentation_thumb(mocked_get_section_data_path, mocked_image_manager):
|
||||
def test_add_from_command_for_a_presentation_thumb(mocked_get_section_data_path):
|
||||
"""
|
||||
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
|
||||
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb
|
||||
"""
|
||||
# GIVEN: A service item, a mocked AppLocation and presentation data
|
||||
mocked_get_section_data_path.return_value = Path('mocked') / 'section' / 'path'
|
||||
@ -294,7 +292,6 @@ def test_add_from_command_for_a_presentation_thumb(mocked_get_section_data_path,
|
||||
# THEN: verify that it is setup as a Command and that the frame data matches
|
||||
assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
|
||||
assert service_item.get_frames()[0] == frame, 'Frames should match'
|
||||
# assert 1 == mocked_image_manager.add_image.call_count, 'image_manager should be used'
|
||||
|
||||
|
||||
def test_service_item_load_optical_media_from_service(state_media):
|
||||
|
@ -815,21 +815,18 @@ def test_on_preview_double_click_add_to_service(mock_settings):
|
||||
assert 1 == slide_controller.on_preview_add_to_service.call_count, 'Should have been called once.'
|
||||
|
||||
|
||||
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
|
||||
@patch(u'PyQt5.QtCore.QTimer.singleShot')
|
||||
def test_update_preview_live(mocked_singleShot, mocked_image_manager, registry):
|
||||
def test_update_preview_live(mocked_singleShot, registry):
|
||||
"""
|
||||
Test that the preview screen is updated with a screen grab for live service items
|
||||
"""
|
||||
# GIVEN: A mocked live service item, a mocked image_manager, a mocked Registry,
|
||||
# GIVEN: A mocked live service item, a mocked Registry,
|
||||
# and a slide controller with many mocks.
|
||||
# Mocked Live Item
|
||||
mocked_live_item = MagicMock()
|
||||
mocked_live_item.get_rendered_frame.return_value = ''
|
||||
mocked_live_item.is_capable = MagicMock()
|
||||
mocked_live_item.is_capable.side_effect = [True, True]
|
||||
# Mock image_manager
|
||||
mocked_image_manager.get_image.return_value = QtGui.QImage()
|
||||
mocked_main_window = MagicMock()
|
||||
Registry().register('main_window', mocked_main_window)
|
||||
# Mock SlideController
|
||||
@ -853,24 +850,20 @@ def test_update_preview_live(mocked_singleShot, mocked_image_manager, registry):
|
||||
assert 0 == slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called'
|
||||
assert 0 == slide_controller.display.preview.call_count, 'display.preview() should not be called'
|
||||
assert 2 == mocked_singleShot.call_count, 'Timer to display_maindisplay should have been called 2 times'
|
||||
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager not be called'
|
||||
|
||||
|
||||
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
|
||||
@patch(u'PyQt5.QtCore.QTimer.singleShot')
|
||||
def test_update_preview_pres(mocked_singleShot, mocked_image_manager, registry):
|
||||
def test_update_preview_pres(mocked_singleShot, registry):
|
||||
"""
|
||||
Test that the preview screen is updated with the correct preview for presentation service items
|
||||
"""
|
||||
# GIVEN: A mocked presentation service item, a mocked image_manager, a mocked Registry,
|
||||
# GIVEN: A mocked presentation service item, a mocked Registry,
|
||||
# and a slide controller with many mocks.
|
||||
# Mocked Presentation Item
|
||||
mocked_pres_item = MagicMock()
|
||||
mocked_pres_item.get_rendered_frame.return_value = ''
|
||||
mocked_pres_item.is_capable = MagicMock()
|
||||
mocked_pres_item.is_capable.side_effect = [True, True]
|
||||
# Mock image_manager
|
||||
mocked_image_manager.get_image.return_value = QtGui.QImage()
|
||||
mocked_main_window = MagicMock()
|
||||
Registry().register('main_window', mocked_main_window)
|
||||
# Mock SlideController
|
||||
@ -891,26 +884,23 @@ def test_update_preview_pres(mocked_singleShot, mocked_image_manager, registry):
|
||||
# WHEN: update_preview is called
|
||||
slide_controller.update_preview()
|
||||
|
||||
# THEN: setPixmap and the image_manager should have been called
|
||||
# THEN: setPixmap should have been called
|
||||
assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called'
|
||||
assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
|
||||
|
||||
|
||||
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
|
||||
@patch(u'PyQt5.QtCore.QTimer.singleShot')
|
||||
def test_update_preview_media(mocked_singleShot, mocked_image_manager, registry):
|
||||
def test_update_preview_media(mocked_singleShot, registry):
|
||||
"""
|
||||
Test that the preview screen is updated with the correct preview for media service items
|
||||
"""
|
||||
# GIVEN: A mocked media service item, a mocked image_manager, a mocked Registry,
|
||||
# GIVEN: A mocked media service item, a mocked Registry,
|
||||
# and a slide controller with many mocks.
|
||||
# Mocked Media Item
|
||||
mocked_media_item = MagicMock()
|
||||
mocked_media_item.get_rendered_frame.return_value = ''
|
||||
mocked_media_item.is_capable = MagicMock()
|
||||
mocked_media_item.is_capable.side_effect = [True, False]
|
||||
# Mock image_manager
|
||||
mocked_image_manager.get_image.return_value = QtGui.QImage()
|
||||
# Mock Registry
|
||||
mocked_main_window = MagicMock()
|
||||
Registry().register('main_window', mocked_main_window)
|
||||
@ -935,24 +925,20 @@ def test_update_preview_media(mocked_singleShot, mocked_image_manager, registry)
|
||||
# THEN: setPixmap should have been called
|
||||
assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called'
|
||||
assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
|
||||
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called'
|
||||
|
||||
|
||||
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
|
||||
@patch(u'PyQt5.QtCore.QTimer.singleShot')
|
||||
def test_update_preview_image(mocked_singleShot, mocked_image_manager, registry):
|
||||
def test_update_preview_image(mocked_singleShot, registry):
|
||||
"""
|
||||
Test that the preview screen is updated with the correct preview for image service items
|
||||
"""
|
||||
# GIVEN: A mocked image service item, a mocked image_manager, a mocked Registry,
|
||||
# GIVEN: A mocked image service item, a mocked Registry,
|
||||
# and a slide controller with many mocks.
|
||||
# Mocked Image Item
|
||||
mocked_img_item = MagicMock()
|
||||
mocked_img_item.get_rendered_frame.return_value = ''
|
||||
mocked_img_item.is_capable = MagicMock()
|
||||
mocked_img_item.is_capable.side_effect = [False, True]
|
||||
# Mock image_manager
|
||||
mocked_image_manager.get_image.return_value = QtGui.QImage()
|
||||
# Mock Registry
|
||||
mocked_main_window = MagicMock()
|
||||
Registry().register('main_window', mocked_main_window)
|
||||
@ -976,7 +962,6 @@ def test_update_preview_image(mocked_singleShot, mocked_image_manager, registry)
|
||||
# THEN: setPixmap and display.preview should have been called
|
||||
assert 1 == slide_controller.preview_display.go_to_slide.call_count, 'go_to_slide should be called'
|
||||
assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
|
||||
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called'
|
||||
|
||||
|
||||
@patch(u'openlp.core.ui.slidecontroller.image_to_byte')
|
||||
|
@ -26,7 +26,6 @@ import pytest
|
||||
from types import GeneratorType
|
||||
from unittest.mock import MagicMock, call, patch
|
||||
|
||||
from PyQt5 import QtGui
|
||||
|
||||
from openlp.core.common.i18n import UiStrings
|
||||
from openlp.core.widgets.views import ListPreviewWidget, ListWidgetWithDnD, TreeWidgetWithDnD, handle_mime_data_urls
|
||||
@ -119,10 +118,9 @@ def test_new_list_preview_widget(preview_widget_env, mock_settings):
|
||||
assert list_preview_widget.screen_ratio == 1, 'Should not be called'
|
||||
|
||||
|
||||
@patch(u'openlp.core.widgets.views.ListPreviewWidget.image_manager')
|
||||
@patch(u'openlp.core.widgets.views.ListPreviewWidget.resizeRowsToContents')
|
||||
@patch(u'openlp.core.widgets.views.ListPreviewWidget.setRowHeight')
|
||||
def test_replace_service_item_thumbs(mocked_setRowHeight, mocked_resizeRowsToContents, mocked_image_manager,
|
||||
def test_replace_service_item_thumbs(mocked_setRowHeight, mocked_resizeRowsToContents,
|
||||
preview_widget_env, mock_settings):
|
||||
"""
|
||||
Test that thubmails for different slides are loaded properly in replace_service_item.
|
||||
@ -151,8 +149,6 @@ def test_replace_service_item_thumbs(mocked_setRowHeight, mocked_resizeRowsToCon
|
||||
mocked_cmd_service_item.is_capable.return_value = True
|
||||
mocked_cmd_service_item.get_frames.return_value = [{'title': None, 'path': 'FAIL', 'image': 'TEST3'},
|
||||
{'title': None, 'path': 'FAIL', 'image': 'TEST4'}]
|
||||
# Mock image_manager
|
||||
mocked_image_manager.get_image.return_value = QtGui.QImage()
|
||||
|
||||
# init ListPreviewWidget and load service item
|
||||
list_preview_widget = ListPreviewWidget(None, 1)
|
||||
@ -160,11 +156,6 @@ def test_replace_service_item_thumbs(mocked_setRowHeight, mocked_resizeRowsToCon
|
||||
# WHEN: replace_service_item is called
|
||||
list_preview_widget.replace_service_item(mocked_img_service_item, 200, 0)
|
||||
list_preview_widget.replace_service_item(mocked_cmd_service_item, 200, 0)
|
||||
# THEN: The ImageManager should be called in the appriopriate manner for each service item.
|
||||
# assert mocked_image_manager.get_image.call_count == 4, 'Should be called once for each slide'
|
||||
# calls = [call('TEST1', ImageSource.ImagePlugin), call('TEST2', ImageSource.ImagePlugin),
|
||||
# call('TEST3', ImageSource.CommandPlugins), call('TEST4', ImageSource.CommandPlugins)]
|
||||
# mocked_image_manager.get_image.assert_has_calls(calls)
|
||||
|
||||
|
||||
@patch(u'openlp.core.widgets.views.ListPreviewWidget.resizeRowsToContents')
|
||||
|
@ -26,7 +26,6 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtTest
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.ui.settingsform import SettingsForm
|
||||
|
||||
|
||||
@ -111,62 +110,3 @@ def test_register_multiple_functions(form):
|
||||
# WHEN testing the processing stack
|
||||
# THEN the processing stack should still have two items
|
||||
assert len(form.processes) == 2, 'No new processes should have been added to the stack'
|
||||
|
||||
|
||||
def test_register_image_manager_trigger_one(form, dummy):
|
||||
"""
|
||||
Test the triggering of the image manager rebuild event from image background change
|
||||
"""
|
||||
# GIVEN: Three functions registered to be call
|
||||
Registry().register_function('images_config_updated', dummy[0])
|
||||
Registry().register_function('config_screen_changed', dummy[1])
|
||||
Registry().register_function('images_regenerate', dummy[2])
|
||||
|
||||
# WHEN: The Images have been changed and the form submitted
|
||||
form.register_post_process('images_config_updated')
|
||||
form.accept()
|
||||
|
||||
# THEN: images_regenerate should have been added.
|
||||
assert dummy[0].call_count == 1, 'dummy1 should have been called once'
|
||||
assert dummy[1].call_count == 0, 'dummy2 should not have been called at all'
|
||||
assert dummy[2].call_count == 1, 'dummy3 should have been called once'
|
||||
|
||||
|
||||
def test_register_image_manager_trigger_two(form, dummy):
|
||||
"""
|
||||
Test the triggering of the image manager rebuild event from screen dimension change
|
||||
"""
|
||||
# GIVEN: Three functions registered to be call
|
||||
Registry().register_function('images_config_updated', dummy[0])
|
||||
Registry().register_function('config_screen_changed', dummy[1])
|
||||
Registry().register_function('images_regenerate', dummy[2])
|
||||
|
||||
# WHEN: The Images have been changed and the form submitted
|
||||
form.register_post_process('config_screen_changed')
|
||||
form.accept()
|
||||
|
||||
# THEN: images_regenerate should have been added.
|
||||
assert dummy[0].call_count == 0, 'dummy1 should not have been called at all'
|
||||
assert dummy[1].call_count == 1, 'dummy2 should have been called once'
|
||||
assert dummy[2].call_count == 1, 'dummy3 should have been called once'
|
||||
|
||||
|
||||
def test_register_image_manager_trigger_three(form, dummy):
|
||||
"""
|
||||
Test the triggering of the image manager rebuild event from image background change and a change to the
|
||||
screen dimension.
|
||||
"""
|
||||
# GIVEN: Three functions registered to be call
|
||||
Registry().register_function('images_config_updated', dummy[0])
|
||||
Registry().register_function('config_screen_changed', dummy[1])
|
||||
Registry().register_function('images_regenerate', dummy[2])
|
||||
|
||||
# WHEN: The Images have been changed and the form submitted
|
||||
form.register_post_process('config_screen_changed')
|
||||
form.register_post_process('images_config_updated')
|
||||
form.accept()
|
||||
|
||||
# THEN: Images_regenerate should have been added.
|
||||
assert dummy[0].call_count == 1, 'dummy1 should have been called once'
|
||||
assert dummy[1].call_count == 1, 'dummy2 should have been called once'
|
||||
assert dummy[2].call_count == 1, 'dummy3 should have been called once'
|
||||
|
Loading…
Reference in New Issue
Block a user