This commit is contained in:
Tim Bentley 2013-05-26 18:03:14 +01:00
commit 6cca9d536b
18 changed files with 249 additions and 69 deletions

View File

@ -58,8 +58,7 @@ class ItemCapabilities(object):
Provides an enumeration of a service item's capabilities
``CanPreview``
The capability to allow the ServiceManager to add to the preview
tab when making the previous item live.
The capability to allow the ServiceManager to add to the preview tab when making the previous item live.
``CanEdit``
The capability to allow the ServiceManager to allow the item to be edited
@ -71,8 +70,7 @@ class ItemCapabilities(object):
Determines is the service_item needs a Media Player
``CanLoop``
The capability to allow the SlideController to allow the loop
processing.
The capability to allow the SlideController to allow the loop processing.
``CanAppend``
The capability to allow the ServiceManager to add leaves to the
@ -82,22 +80,19 @@ class ItemCapabilities(object):
The capability to remove lines breaks in the renderer
``OnLoadUpdate``
The capability to update MediaManager when a service Item is
loaded.
The capability to update MediaManager when a service Item is loaded.
``AddIfNewItem``
Not Used
``ProvidesOwnDisplay``
The capability to tell the SlideController the service Item has a
different display.
The capability to tell the SlideController the service Item has a different display.
``HasDetailedTitleDisplay``
ServiceItem provides a title
Being Removed and decommissioned.
``HasVariableStartTime``
The capability to tell the ServiceManager that a change to start
time is possible.
The capability to tell the ServiceManager that a change to start time is possible.
``CanSoftBreak``
The capability to tell the renderer that Soft Break is allowed
@ -149,7 +144,7 @@ class ServiceItem(object):
if plugin:
self.name = plugin.name
self.title = u''
self.shortname = u''
self.processor = None
self.audit = u''
self.items = []
self.iconic_representation = None
@ -353,7 +348,8 @@ class ServiceItem(object):
u'media_length': self.media_length,
u'background_audio': self.background_audio,
u'theme_overwritten': self.theme_overwritten,
u'will_auto_start': self.will_auto_start
u'will_auto_start': self.will_auto_start,
u'processor': self.processor
}
service_data = []
if self.service_item_type == ServiceItemType.Text:
@ -387,7 +383,6 @@ class ServiceItem(object):
self.title = header[u'title']
self.name = header[u'name']
self.service_item_type = header[u'type']
self.shortname = header[u'plugin']
self.theme = header[u'theme']
self.add_icon(header[u'icon'])
self.raw_footer = header[u'footer']
@ -406,7 +401,13 @@ class ServiceItem(object):
self.auto_play_slides_loop = header.get(u'auto_play_slides_loop', False)
self.timed_slide_interval = header.get(u'timed_slide_interval', 0)
self.will_auto_start = header.get(u'will_auto_start', False)
self.processor = header.get(u'processor', None)
self.has_original_files = True
#TODO Remove me in 2,3 build phase
if self.is_capable(ItemCapabilities.HasDetailedTitleDisplay):
self.capabilities.remove(ItemCapabilities.HasDetailedTitleDisplay)
self.processor = self.title
self.title = None
if u'background_audio' in header:
self.background_audio = []
for filename in header[u'background_audio']:
@ -429,6 +430,8 @@ class ServiceItem(object):
self.add_from_image(text_image[u'path'], text_image[u'title'], background)
elif self.service_item_type == ServiceItemType.Command:
for text_image in serviceitem[u'serviceitem'][u'data']:
if not self.title:
self.title = text_image[u'title']
if path:
self.has_original_files = False
self.add_from_command(path, text_image[u'title'], text_image[u'image'])
@ -443,9 +446,7 @@ class ServiceItem(object):
if self.is_text():
return self.title
else:
if ItemCapabilities.HasDetailedTitleDisplay in self.capabilities:
return self._raw_frames[0][u'title']
elif len(self._raw_frames) > 1:
if len(self._raw_frames) > 1:
return self.title
else:
return self._raw_frames[0][u'title']

View File

@ -466,8 +466,8 @@ class MediaController(object):
The ServiceItem containing the details to be played.
"""
used_players = get_media_players()[0]
if service_item.title != UiStrings().Automatic:
used_players = [service_item.title.lower()]
if service_item.processor != UiStrings().Automatic:
used_players = [service_item.processor.lower()]
if controller.media_info.file_info.isFile():
suffix = u'*.%s' % controller.media_info.file_info.suffix().lower()
for title in used_players:

View File

@ -511,7 +511,7 @@ class BibleImportForm(OpenLPWizard):
name = bible[u'abbreviation']
self.web_bible_list[download_type][version] = name.strip()
def preWizard(self):
def pre_wizard(self):
"""
Prepare the UI for the import.
"""

View File

@ -105,7 +105,7 @@ class BibleUpgradeForm(OpenLPWizard):
Perform necessary functions depending on which wizard page is active.
"""
if self.page(pageId) == self.progress_page:
self.preWizard()
self.pre_wizard()
self.performWizard()
self.post_wizard()
elif self.page(pageId) == self.selectPage and not self.files:
@ -329,7 +329,7 @@ class BibleUpgradeForm(OpenLPWizard):
self.cancel_button.setVisible(True)
settings.endGroup()
def preWizard(self):
def pre_wizard(self):
"""
Prepare the UI for the upgrade.
"""

View File

@ -50,6 +50,7 @@ class ChooseGroupForm(QtGui.QDialog, Ui_ChooseGroupDialog):
``selected_group``
The ID of the group that should be selected by default when showing the dialog.
"""
self.new_group_edit.clear()
if selected_group is not None:
for index in range(self.group_combobox.count()):
if self.group_combobox.itemData(index) == selected_group:

View File

@ -32,7 +32,6 @@ from PyQt4 import QtGui
from openlp.core.lib import Registry, SettingsTab, Settings, UiStrings, translate
class ImageTab(SettingsTab):
"""
ImageTab is the images settings tab in the settings dialog.

View File

@ -391,6 +391,7 @@ class ImageMediaItem(MediaManagerItem):
``initial_load``
When set to False, the busy cursor and progressbar will be shown while loading images
"""
parent_group = None
if target_group is None:
# Find out if a group must be pre-selected
preselect_group = None
@ -436,6 +437,8 @@ class ImageMediaItem(MediaManagerItem):
parent_group.parent_id = 0
parent_group.group_name = self.choose_group_form.new_group_edit.text()
self.manager.save_object(parent_group)
self.fill_groups_combobox(self.choose_group_form.group_combobox)
self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
else:
parent_group = target_group.data(0, QtCore.Qt.UserRole)
if isinstance(parent_group, ImageFilenames):
@ -550,28 +553,25 @@ class ImageMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.CanAppend)
# force a nonexistent theme
service_item.theme = -1
missing_items = []
missing_items_filenames = []
images_filenames = []
# Expand groups to images
for bitem in items:
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()):
if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
items.append(bitem.child(index))
items.remove(bitem)
images_filenames.append(bitem.child(index).data(0, QtCore.Qt.UserRole).filename)
elif isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames):
images_filenames.append(bitem.data(0, QtCore.Qt.UserRole).filename)
# Don't try to display empty groups
if not items:
if not images_filenames:
return False
# Find missing files
for bitem in items:
filename = bitem.data(0, QtCore.Qt.UserRole).filename
for filename in images_filenames:
if not os.path.exists(filename):
missing_items.append(bitem)
missing_items_filenames.append(filename)
for item in missing_items:
items.remove(item)
# We cannot continue, as all images do not exist.
if not items:
if not images_filenames:
if not remote:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
@ -579,15 +579,14 @@ class ImageMediaItem(MediaManagerItem):
u'\n'.join(missing_items_filenames))
return False
# We have missing as well as existing images. We ask what to do.
elif missing_items and QtGui.QMessageBox.question(self,
elif missing_items_filenames and QtGui.QMessageBox.question(self,
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n'
'Do you want to add the other images anyway?') % u'\n'.join(missing_items_filenames),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
return False
# Continue with the existing images.
for bitem in items:
filename = bitem.data(0, QtCore.Qt.UserRole).filename
for filename in images_filenames:
name = os.path.split(filename)[1]
service_item.add_from_image(filename, name, background)
return True

View File

@ -155,7 +155,7 @@ class MediaMediaItem(MediaManagerItem):
if os.path.exists(filename):
service_item = ServiceItem()
service_item.title = u'webkit'
service_item.shortname = service_item.title
service_item.processor = u'webkit'
(path, name) = os.path.split(filename)
service_item.add_from_command(path, name,CLAPPERBOARD)
if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True):
@ -185,9 +185,9 @@ class MediaMediaItem(MediaManagerItem):
translate('MediaPlugin.MediaItem', 'Missing Media File'),
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename)
return False
service_item.title = self.display_type_combo_box.currentText()
service_item.shortname = service_item.title
(path, name) = os.path.split(filename)
service_item.title = name
service_item.processor = self.display_type_combo_box.currentText()
service_item.add_from_command(path, name, CLAPPERBOARD)
# Only get start and end times if going to a service
if context == ServiceItemContext.Service:
@ -196,7 +196,6 @@ class MediaMediaItem(MediaManagerItem):
return False
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
service_item.add_capability(ItemCapabilities.RequiresMedia)
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
if Settings().value(self.settings_section + u'/media auto start') == QtCore.Qt.Checked:
service_item.will_auto_start = True
# force a non-existent theme
@ -260,8 +259,7 @@ class MediaMediaItem(MediaManagerItem):
Settings().setValue(self.settings_section + u'/media files', self.get_file_list())
def load_list(self, media, target_group=None):
# Sort the media by its filename considering language specific
# characters.
# Sort the media by its filename considering language specific characters.
media.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
for track in media:
track_info = QtCore.QFileInfo(track)

View File

@ -244,22 +244,20 @@ class PresentationMediaItem(MediaManagerItem):
items = self.list_view.selectedItems()
if len(items) > 1:
return False
service_item.title = self.display_type_combo_box.currentText()
service_item.shortname = self.display_type_combo_box.currentText()
service_item.processor = self.display_type_combo_box.currentText()
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
shortname = service_item.shortname
if not shortname:
if not self.display_type_combo_box.currentText():
return False
for bitem in items:
filename = bitem.data(QtCore.Qt.UserRole)
(path, name) = os.path.split(filename)
service_item.title = name
if os.path.exists(filename):
if shortname == self.Automatic:
service_item.shortname = self.findControllerByType(filename)
if not service_item.shortname:
if service_item.processor == self.Automatic:
service_item.processor = self.findControllerByType(filename)
if not service_item.processor:
return False
controller = self.controllers[service_item.shortname]
(path, name) = os.path.split(filename)
controller = self.controllers[service_item.processor]
doc = controller.add_document(filename)
if doc.get_thumbnail_path(1, True) is None:
doc.load_presentation()

View File

@ -315,7 +315,7 @@ class MessageListener(object):
item = message[0]
hide_mode = message[2]
file = item.get_frame_path()
self.handler = item.title
self.handler = item.processor
if self.handler == self.media_item.Automatic:
self.handler = self.media_item.findControllerByType(file)
if not self.handler:

View File

@ -38,6 +38,7 @@ from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
class PresentationDocument(object):
"""
Base class for presentation documents to inherit from. Loads and closes the presentation as well as triggering the
@ -322,7 +323,7 @@ class PresentationController(object):
``supports``
The primary native file types this application supports.
``alsosupports``
``also_supports``
Other file types the application can import, although not necessarily the first choice due to potential
incompatibilities.
@ -358,7 +359,7 @@ class PresentationController(object):
Name of the application, to appear in the application
"""
self.supports = []
self.alsosupports = []
self.also_supports = []
self.docs = []
self.plugin = plugin
self.name = name

View File

@ -49,7 +49,7 @@ __default_settings__ = {
u'presentations/Powerpoint': QtCore.Qt.Checked,
u'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
u'presentations/presentations files': []
}
}
class PresentationPlugin(Plugin):

View File

@ -235,7 +235,7 @@ class SongExportForm(OpenLPWizard):
self.availableListWidget.addItem(item)
self.application.set_normal_cursor()
def preWizard(self):
def pre_wizard(self):
"""
Perform pre export tasks.
"""

View File

@ -325,7 +325,7 @@ class SongImportForm(OpenLPWizard):
self.error_copy_to_button.setHidden(True)
self.error_save_to_button.setHidden(True)
def preWizard(self):
def pre_wizard(self):
"""
Perform pre import tasks
"""

View File

@ -132,8 +132,8 @@ class SongMediaItem(MediaManagerItem):
"""
Initialise variables when they cannot be initialised in the constructor.
"""
self.songMaintenanceForm = SongMaintenanceForm(self.plugin.manager, self)
self.editSongForm = EditSongForm(self, self.main_window, self.plugin.manager)
self.song_maintenance_form = SongMaintenanceForm(self.plugin.manager, self)
self.edit_song_form = EditSongForm(self, self.main_window, self.plugin.manager)
self.openLyrics = OpenLyrics(self.plugin.manager)
self.search_text_edit.set_search_types([
(SongSearch.Entire, u':/songs/song_search_all.png',

View File

@ -210,7 +210,6 @@ class TestServiceItem(TestCase):
# THEN: We should get back a valid service item
assert service_item.is_valid is True, u'The new service item should be valid'
print service_item.get_rendered_frame(0)
assert service_item.get_rendered_frame(0) == test_file, u'The first frame should match the path to the image'
assert service_item.get_frames()[0] == frame_array, u'The return should match frame array1'
assert service_item.get_frame_path(0) == test_file, u'The frame path should match the full path to the image'
@ -268,6 +267,26 @@ class TestServiceItem(TestCase):
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
u'This service item should be able to have new items added to it'
def serviceitem_migrate_test_20_22(self):
"""
Test the Service Item - migrating a media only service item from 2.0 to 2.2 format
"""
# GIVEN: A new service item and a mocked add icon function
service_item = ServiceItem(None)
service_item.add_icon = MagicMock()
# WHEN: adding an media from a saved Service and mocked exists
line = self.convert_file_service_item(u'migrate_video_20_22.osd')
with patch('os.path.exists'):
service_item.set_from_service(line, TEST_PATH)
# THEN: We should get back a converted service item
assert service_item.is_valid is True, u'The new service item should be valid'
assert service_item.processor is None, u'The Processor should have been set'
assert service_item.title is None, u'The title should be set to a value'
assert service_item.is_capable(ItemCapabilities.HasDetailedTitleDisplay) is False, \
u'The Capability should have been removed'
def convert_file_service_item(self, name):
service_file = os.path.join(TEST_PATH, name)
try:

View File

@ -9,7 +9,7 @@ from unittest import TestCase
from mock import MagicMock, patch
from openlp.core.lib import Registry
from openlp.plugins.images.lib.db import ImageFilenames
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
from openlp.plugins.images.lib.mediaitem import ImageMediaItem
@ -23,6 +23,7 @@ class TestImageMediaItem(TestCase):
Registry.create()
Registry().register(u'service_list', MagicMock())
Registry().register(u'main_window', self.mocked_main_window)
Registry().register(u'live_controller', MagicMock())
mocked_parent = MagicMock()
mocked_plugin = MagicMock()
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.__init__') as mocked_init:
@ -35,7 +36,7 @@ class TestImageMediaItem(TestCase):
"""
# GIVEN: An empty image_list
image_list = []
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_loadFullList:
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock()
# WHEN: We run save_new_images_list with the empty list
@ -51,7 +52,7 @@ class TestImageMediaItem(TestCase):
"""
# GIVEN: A list with 1 image
image_list = [ u'test_image.jpg' ]
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_loadFullList:
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
ImageFilenames.filename = ''
self.media_item.manager = MagicMock()
@ -59,7 +60,7 @@ class TestImageMediaItem(TestCase):
self.media_item.save_new_images_list(image_list, reload_list=True)
# THEN: load_full_list() should have been called
assert mocked_loadFullList.call_count == 1, u'load_full_list() should have been called'
assert mocked_load_full_list.call_count == 1, u'load_full_list() should have been called'
# CLEANUP: Remove added attribute from ImageFilenames
delattr(ImageFilenames, 'filename')
@ -70,14 +71,14 @@ class TestImageMediaItem(TestCase):
"""
# GIVEN: A list with 1 image
image_list = [ u'test_image.jpg' ]
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_loadFullList:
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock()
# WHEN: We run save_new_images_list with reload_list=False
self.media_item.save_new_images_list(image_list, reload_list=False)
# THEN: load_full_list() should not have been called
assert mocked_loadFullList.call_count == 0, u'load_full_list() should not have been called'
assert mocked_load_full_list.call_count == 0, u'load_full_list() should not have been called'
def save_new_images_list_multiple_images_test(self):
"""
@ -85,7 +86,7 @@ class TestImageMediaItem(TestCase):
"""
# GIVEN: A list with 3 images
image_list = [ u'test_image_1.jpg', u'test_image_2.jpg', u'test_image_3.jpg' ]
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_loadFullList:
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock()
# WHEN: We run save_new_images_list with the list of 3 images
@ -101,7 +102,7 @@ class TestImageMediaItem(TestCase):
"""
# GIVEN: A list with images and objects
image_list = [ u'test_image_1.jpg', None, True, ImageFilenames(), 'test_image_2.jpg' ]
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_loadFullList:
with patch(u'openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') as mocked_load_full_list:
self.media_item.manager = MagicMock()
# WHEN: We run save_new_images_list with the list of images and objects
@ -110,3 +111,68 @@ class TestImageMediaItem(TestCase):
# THEN: load_full_list() should not have been called
assert self.media_item.manager.save_object.call_count == 2, \
u'load_full_list() should have been called only once'
def on_reset_click_test(self):
"""
Test that on_reset_click() actually resets the background
"""
# GIVEN: A mocked version of reset_action
self.media_item.reset_action = MagicMock()
# WHEN: on_reset_click is called
self.media_item.on_reset_click()
# THEN: the reset_action should be set visible, and the image should be reset
self.media_item.reset_action.setVisible.assert_called_with(False)
self.media_item.live_controller.display.reset_image.assert_called_with()
def _recursively_delete_group_side_effect(*args, **kwargs):
"""
Side effect method that creates custom retun values for the recursively_delete_group method
"""
if args[1] == ImageFilenames and args[2]:
# Create some fake objects that should be removed
returned_object1 = ImageFilenames()
returned_object1.id = 1
returned_object1.filename = u'/tmp/test_file_1.jpg'
returned_object2 = ImageFilenames()
returned_object2.id = 2
returned_object2.filename = u'/tmp/test_file_2.jpg'
returned_object3 = ImageFilenames()
returned_object3.id = 3
returned_object3.filename = u'/tmp/test_file_3.jpg'
return [returned_object1, returned_object2, returned_object3]
if args[1] == ImageGroups and args[2]:
# Change the parent_id that is matched so we don't get into an endless loop
ImageGroups.parent_id = 0
# Create a fake group that will be used in the next run
returned_object1 = ImageGroups()
returned_object1.id = 1
return [returned_object1]
return []
def recursively_delete_group_test(self):
"""
Test that recursively_delete_group() works
"""
# GIVEN: An ImageGroups object and mocked functions
with patch(u'openlp.core.utils.delete_file') as mocked_delete_file:
ImageFilenames.group_id = 1
ImageGroups.parent_id = 1
self.media_item.manager = MagicMock()
self.media_item.manager.get_all_objects.side_effect = self._recursively_delete_group_side_effect
self.media_item.servicePath = ""
test_group = ImageGroups()
test_group.id = 1
# WHEN: recursively_delete_group() is called
self.media_item.recursively_delete_group(test_group)
# THEN:
assert mocked_delete_file.call_count == 0, u'delete_file() should not be called'
assert self.media_item.manager.delete_object.call_count == 7, \
u'manager.delete_object() should be called exactly 7 times'
# CLEANUP: Remove added attribute from ImageFilenames and ImageGroups
delattr(ImageFilenames, 'group_id')
delattr(ImageGroups, 'parent_id')

View File

@ -0,0 +1,98 @@
(lp1
(dp2
Vserviceitem
p3
(dp4
Vheader
p5
(dp6
Vxml_version
p7
NsVauto_play_slides_loop
p8
I00
sVauto_play_slides_once
p9
I00
sVwill_auto_start
p10
I01
sVtitle
p11
VVLC
p12
sVcapabilities
p13
(lp14
I12
aI16
aI4
aI11
asVtheme
p15
I-1
sVbackground_audio
p16
(lp17
sVicon
p18
V:/plugins/plugin_media.png
p19
sVtype
p20
I3
sVstart_time
p21
I0
sVfrom_plugin
p22
I00
sVmedia_length
p23
I144
sVdata
p24
V
sVtimed_slide_interval
p25
I0
sVaudit
p26
V
sVsearch
p27
V
sVname
p28
Vmedia
p29
sVfooter
p30
(lp31
sVnotes
p32
V
sVplugin
p33
g29
sVtheme_overwritten
p34
I00
sVend_time
p35
I0
ssg24
(lp36
(dp37
Vpath
p38
V/home/tim/Videos/puppets
p39
sVimage
p40
V:/media/slidecontroller_multimedia.png
p41
sg11
VMVI_3405.MOV
p42
sassa.