Fixes #1414585 Thumbnail of images isn't shown in stage view and remote control

and #1414585 2.1.2 Traceback on Presentations for MAC

bzr-revno: 2494
This commit is contained in:
Philip Ridout 2015-02-01 19:51:54 +00:00 committed by Tim Bentley
commit cfa8e4f2df
3 changed files with 91 additions and 25 deletions

View File

@ -314,6 +314,16 @@ class ImageMediaItem(MediaManagerItem):
return True return True
return return_value return return_value
def generate_thumbnail_path(self, image):
"""
Generate a path to the thumbnail
:param image: An instance of ImageFileNames
:return: A path to the thumbnail of type str
"""
ext = os.path.splitext(image.filename)[1].lower()
return os.path.join(self.service_path, '{}{}'.format(str(image.id), ext))
def load_full_list(self, images, initial_load=False, open_group=None): def load_full_list(self, images, initial_load=False, open_group=None):
""" """
Replace the list of images and groups in the interface. Replace the list of images and groups in the interface.
@ -335,27 +345,26 @@ class ImageMediaItem(MediaManagerItem):
# Sort the images by its filename considering language specific. # Sort the images by its filename considering language specific.
# characters. # characters.
images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1])) images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1]))
for imageFile in images: for image_file in images:
log.debug('Loading image: %s', imageFile.filename) log.debug('Loading image: %s', image_file.filename)
filename = os.path.split(imageFile.filename)[1] filename = os.path.split(image_file.filename)[1]
ext = os.path.splitext(imageFile.filename)[1].lower() thumb = self.generate_thumbnail_path(image_file)
thumb = os.path.join(self.service_path, "%s%s" % (str(imageFile.id), ext)) if not os.path.exists(image_file.filename):
if not os.path.exists(imageFile.filename):
icon = build_icon(':/general/general_delete.png') icon = build_icon(':/general/general_delete.png')
else: else:
if validate_thumb(imageFile.filename, thumb): if validate_thumb(image_file.filename, thumb):
icon = build_icon(thumb) icon = build_icon(thumb)
else: else:
icon = create_thumb(imageFile.filename, thumb) icon = create_thumb(image_file.filename, thumb)
item_name = QtGui.QTreeWidgetItem([filename]) item_name = QtGui.QTreeWidgetItem([filename])
item_name.setText(0, filename) item_name.setText(0, filename)
item_name.setIcon(0, icon) item_name.setIcon(0, icon)
item_name.setToolTip(0, imageFile.filename) item_name.setToolTip(0, image_file.filename)
item_name.setData(0, QtCore.Qt.UserRole, imageFile) item_name.setData(0, QtCore.Qt.UserRole, image_file)
if imageFile.group_id == 0: if image_file.group_id == 0:
self.list_view.addTopLevelItem(item_name) self.list_view.addTopLevelItem(item_name)
else: else:
group_items[imageFile.group_id].addChild(item_name) group_items[image_file.group_id].addChild(item_name)
if not initial_load: if not initial_load:
self.main_window.increment_progress_bar() self.main_window.increment_progress_bar()
if not initial_load: if not initial_load:
@ -549,24 +558,24 @@ class ImageMediaItem(MediaManagerItem):
# force a nonexistent theme # force a nonexistent theme
service_item.theme = -1 service_item.theme = -1
missing_items_file_names = [] missing_items_file_names = []
images_file_names = [] images = []
# Expand groups to images # Expand groups to images
for bitem in items: for bitem in items:
if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None: if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None:
for index in range(0, bitem.childCount()): for index in range(0, bitem.childCount()):
if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames): if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
images_file_names.append(bitem.child(index).data(0, QtCore.Qt.UserRole).filename) images.append(bitem.child(index).data(0, QtCore.Qt.UserRole))
elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames): elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
images_file_names.append(bitem.data(0, QtCore.Qt.UserRole).filename) images.append(bitem.data(0, QtCore.Qt.UserRole))
# Don't try to display empty groups # Don't try to display empty groups
if not images_file_names: if not images:
return False return False
# Find missing files # Find missing files
for filename in images_file_names: for image in images:
if not os.path.exists(filename): if not os.path.exists(image.filename):
missing_items_file_names.append(filename) missing_items_file_names.append(image.filename)
# We cannot continue, as all images do not exist. # We cannot continue, as all images do not exist.
if not images_file_names: if not images:
if not remote: if not remote:
critical_error_message_box( critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'), translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
@ -582,9 +591,10 @@ class ImageMediaItem(MediaManagerItem):
QtGui.QMessageBox.No: QtGui.QMessageBox.No:
return False return False
# Continue with the existing images. # Continue with the existing images.
for filename in images_file_names: for image in images:
name = os.path.split(filename)[1] name = os.path.split(image.filename)[1]
service_item.add_from_image(filename, name, background, os.path.join(self.service_path, name)) thumbnail = self.generate_thumbnail_path(image)
service_item.add_from_image(image.filename, name, background, thumbnail)
return True return True
def check_group_exists(self, new_group): def check_group_exists(self, new_group):

View File

@ -143,7 +143,10 @@ class PresentationPlugin(Plugin):
super().app_startup() super().app_startup()
files_from_config = Settings().value('presentations/presentations files') files_from_config = Settings().value('presentations/presentations files')
for file in files_from_config: for file in files_from_config:
try:
self.media_item.clean_up_thumbnails(file) self.media_item.clean_up_thumbnails(file)
except AttributeError:
pass
self.media_item.list_view.clear() self.media_item.list_view.clear()
Settings().setValue('presentations/thumbnail_scheme', 'md5') Settings().setValue('presentations/thumbnail_scheme', 'md5')
self.media_item.validate_and_load(files_from_config) self.media_item.validate_and_load(files_from_config)

View File

@ -25,7 +25,7 @@ Functional tests to test the AppLocation class and related methods.
import os import os
from unittest import TestCase from unittest import TestCase
from openlp.core.utils import clean_filename, get_filesystem_encoding, get_locale_key, \ from openlp.core.utils import clean_filename, delete_file, get_filesystem_encoding, get_locale_key, \
get_natural_key, split_filename, _get_user_agent, get_web_page, get_uno_instance, add_actions get_natural_key, split_filename, _get_user_agent, get_web_page, get_uno_instance, add_actions
from tests.functional import MagicMock, patch from tests.functional import MagicMock, patch
@ -184,6 +184,59 @@ class TestUtils(TestCase):
# THEN: The file name should be cleaned. # THEN: The file name should be cleaned.
self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.') self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.')
def delete_file_no_path_test(self):
""""
Test the delete_file function when called with out a valid path
"""
# GIVEN: A blank path
# WEHN: Calling delete_file
result = delete_file('')
# THEN: delete_file should return False
self.assertFalse(result, "delete_file should return False when called with ''")
def delete_file_path_success_test(self):
""""
Test the delete_file function when it successfully deletes a file
"""
# GIVEN: A mocked os which returns True when os.path.exists is called
with patch('openlp.core.utils.os', **{'path.exists.return_value': False}):
# WHEN: Calling delete_file with a file path
result = delete_file('path/file.ext')
# THEN: delete_file should return True
self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
def delete_file_path_no_file_exists_test(self):
""""
Test the delete_file function when the file to remove does not exist
"""
# GIVEN: A mocked os which returns False when os.path.exists is called
with patch('openlp.core.utils.os', **{'path.exists.return_value': False}):
# WHEN: Calling delete_file with a file path
result = delete_file('path/file.ext')
# THEN: delete_file should return True
self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
def delete_file_path_exception_test(self):
""""
Test the delete_file function when os.remove raises an exception
"""
# GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is
# called.
with patch('openlp.core.utils.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \
patch('openlp.core.utils.log') as mocked_log:
# WHEN: Calling delete_file with a file path
result = delete_file('path/file.ext')
# THEN: delete_file should log and exception and return False
self.assertEqual(mocked_log.exception.call_count, 1)
self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError')
def get_locale_key_test(self): def get_locale_key_test(self):
""" """
Test the get_locale_key(string) function Test the get_locale_key(string) function