r2154 + fixed trunk

This commit is contained in:
Andreas Preikschat 2013-01-21 20:47:53 +01:00
commit d0c9c35deb
10 changed files with 292 additions and 14 deletions

View File

@ -23,3 +23,5 @@ resources/windows/warnOpenLP.txt
openlp.cfg
.idea
openlp.pro
.kdev4
tests.kdev4

View File

@ -183,6 +183,9 @@ class ServiceItem(object):
self.background_audio = []
self.theme_overwritten = False
self.temporary_edit = False
self.auto_play_slides_once = False
self.auto_play_slides_loop = False
self.timed_slide_interval = 0
self.will_auto_start = False
self.has_original_files = True
self._new_item()
@ -344,6 +347,9 @@ class ServiceItem(object):
u'search': self.search_string,
u'data': self.data_string,
u'xml_version': self.xml_version,
u'auto_play_slides_once': self.auto_play_slides_once,
u'auto_play_slides_loop': self.auto_play_slides_loop,
u'timed_slide_interval': self.timed_slide_interval,
u'start_time': self.start_time,
u'end_time': self.end_time,
u'media_length': self.media_length,
@ -398,6 +404,9 @@ class ServiceItem(object):
self.start_time = header.get(u'start_time', 0)
self.end_time = header.get(u'end_time', 0)
self.media_length = header.get(u'media_length', 0)
self.auto_play_slides_once = header.get(u'auto_play_slides_once', False)
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.has_original_files = True
if u'background_audio' in header:
@ -427,7 +436,6 @@ class ServiceItem(object):
self.add_from_command(path, text_image[u'title'], text_image[u'image'])
else:
self.add_from_command(text_image[u'path'], text_image[u'title'], text_image[u'image'])
self._new_item()
def get_display_title(self):

View File

@ -257,6 +257,20 @@ class ServiceManager(QtGui.QWidget):
text=translate('OpenLP.ServiceManager', 'Create New &Custom Slide'),
icon=u':/general/general_edit.png', triggers=self.create_custom)
self.menu.addSeparator()
# Add AutoPlay menu actions
self.autoPlaySlidesGroup = QtGui.QMenu(translate('OpenLP.ServiceManager', '&Auto play slides'))
self.menu.addMenu(self.autoPlaySlidesGroup)
self.autoPlaySlidesLoop = create_widget_action(self.autoPlaySlidesGroup,
text=translate('OpenLP.ServiceManager', 'Auto play slides &Loop'),
checked=False, triggers=self.toggleAutoPlaySlidesLoop)
self.autoPlaySlidesOnce = create_widget_action(self.autoPlaySlidesGroup,
text=translate('OpenLP.ServiceManager', 'Auto play slides &Once'),
checked=False, triggers=self.toggleAutoPlaySlidesOnce)
self.autoPlaySlidesGroup.addSeparator()
self.timedSlideInterval = create_widget_action(self.autoPlaySlidesGroup,
text=translate('OpenLP.ServiceManager', '&Delay between slides'),
checked=False, triggers=self.onTimedSlideInterval)
self.menu.addSeparator()
self.previewAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'),
icon=u':/general/general_preview.png', triggers=self.makePreview)
# Add already existing make live action to the menu.
@ -762,6 +776,22 @@ class ServiceManager(QtGui.QWidget):
self.maintainAction.setVisible(True)
if item.parent() is None:
self.notesAction.setVisible(True)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanLoop) and \
len(serviceItem[u'service_item'].get_frames()) > 1:
self.autoPlaySlidesGroup.menuAction().setVisible(True)
self.autoPlaySlidesOnce.setChecked(serviceItem[u'service_item'].auto_play_slides_once)
self.autoPlaySlidesLoop.setChecked(serviceItem[u'service_item'].auto_play_slides_loop)
self.timedSlideInterval.setChecked(serviceItem[u'service_item'].timed_slide_interval > 0)
if serviceItem[u'service_item'].timed_slide_interval > 0:
delay_suffix = u' '
delay_suffix += unicode(serviceItem[u'service_item'].timed_slide_interval)
delay_suffix += u' s'
else:
delay_suffix = u' ...'
self.timedSlideInterval.setText(translate('OpenLP.ServiceManager', '&Delay between slides') + delay_suffix)
# TODO for future: make group explains itself more visually
else:
self.autoPlaySlidesGroup.menuAction().setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
self.timeAction.setVisible(True)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
@ -807,6 +837,59 @@ class ServiceManager(QtGui.QWidget):
if self.startTimeForm.exec_():
self.repaintServiceList(item, -1)
def toggleAutoPlaySlidesOnce(self):
"""
Toggle Auto play slide once.
Inverts auto play once option for the item
"""
item = self.findServiceItem()[0]
service_item = self.serviceItems[item][u'service_item']
service_item.auto_play_slides_once = not service_item.auto_play_slides_once
if service_item.auto_play_slides_once:
service_item.auto_play_slides_loop = False
self.autoPlaySlidesLoop.setChecked(False)
if service_item.auto_play_slides_once and service_item.timed_slide_interval == 0:
service_item.timed_slide_interval = Settings().value(u'loop delay')
self.setModified()
def toggleAutoPlaySlidesLoop(self):
"""
Toggle Auto play slide loop.
"""
item = self.findServiceItem()[0]
service_item = self.serviceItems[item][u'service_item']
service_item.auto_play_slides_loop = not service_item.auto_play_slides_loop
if service_item.auto_play_slides_loop:
service_item.auto_play_slides_once = False
self.autoPlaySlidesOnce.setChecked(False)
if service_item.auto_play_slides_loop and service_item.timed_slide_interval == 0:
service_item.timed_slide_interval = Settings().value(u'loop delay')
self.setModified()
def onTimedSlideInterval(self):
"""
on set times slide interval.
Shows input dialog for enter interval in seconds for delay
"""
item = self.findServiceItem()[0]
service_item = self.serviceItems[item][u'service_item']
if service_item.timed_slide_interval == 0:
timed_slide_interval = Settings().value(u'loop delay')
else:
timed_slide_interval = service_item.timed_slide_interval
timed_slide_interval, ok = QtGui.QInputDialog.getInteger(self, translate('OpenLP.ServiceManager',
'Input delay'), translate('OpenLP.ServiceManager', 'Delay between slides in seconds.'),
timed_slide_interval, 0, 180, 1)
if ok:
service_item.timed_slide_interval = timed_slide_interval
if service_item.timed_slide_interval <> 0 and not service_item.auto_play_slides_loop\
and not service_item.auto_play_slides_once:
service_item.auto_play_slides_loop = True
elif service_item.timed_slide_interval == 0:
service_item.auto_play_slides_loop = False
service_item.auto_play_slides_once = False
self.setModified()
def onAutoStart(self):
"""
Toggles to Auto Start Setting.
@ -1287,6 +1370,8 @@ class ServiceManager(QtGui.QWidget):
if self.serviceItems and item < len(self.serviceItems) and \
self.serviceItems[item][u'service_item'].is_capable(ItemCapabilities.CanPreview):
self.mainwindow.previewController.addServiceManagerItem(self.serviceItems[item][u'service_item'], 0)
next_item = self.serviceManagerList.topLevelItem(item)
self.serviceManagerList.setCurrentItem(next_item)
self.mainwindow.liveController.previewListWidget.setFocus()
else:
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),

View File

@ -689,6 +689,14 @@ class SlideController(DisplayController):
self.slideSelected()
else:
self._processItem(item, slidenum)
if self.isLive and item.auto_play_slides_loop and item.timed_slide_interval > 0:
self.playSlidesLoop.setChecked(item.auto_play_slides_loop)
self.delaySpinBox.setValue(int(item.timed_slide_interval))
self.onPlaySlidesLoop()
elif self.isLive and item.auto_play_slides_once and item.timed_slide_interval > 0:
self.playSlidesOnce.setChecked(item.auto_play_slides_once)
self.delaySpinBox.setValue(int(item.timed_slide_interval))
self.onPlaySlidesOnce()
def _processItem(self, serviceItem, slideno):
"""
@ -877,6 +885,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
self.onToggleLoop()
def onThemeDisplay(self, checked=None):
"""
@ -895,6 +904,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
self.onToggleLoop()
def onHideDisplay(self, checked=None):
"""
@ -913,6 +923,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.hidePlugin(checked)
self.updatePreview()
self.onToggleLoop()
def blankPlugin(self):
"""
@ -1088,7 +1099,8 @@ class SlideController(DisplayController):
"""
Toggles the loop state.
"""
if self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked():
hide_mode = self.hideMode()
if hide_mode is None and (self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked()):
self.onStartLoop()
else:
self.onStopLoop()
@ -1122,11 +1134,11 @@ class SlideController(DisplayController):
self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop)
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd)
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
self.playSlidesOnce.setChecked(False)
else:
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop)
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
self.playSlidesOnce.setChecked(False)
self.onToggleLoop()
def onPlaySlidesOnce(self, checked=None):
@ -1143,11 +1155,11 @@ class SlideController(DisplayController):
self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd)
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop)
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesLoop.setChecked(False)
else:
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time'))
self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd)
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesLoop.setChecked(False)
self.onToggleLoop()
def setAudioItemsVisibility(self, visible):

View File

@ -2,10 +2,12 @@
Package to test the openlp.core.lib package.
"""
from unittest import TestCase
from datetime import datetime, timedelta
from mock import MagicMock, patch
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \
image_to_byte, check_item_selected, validate_thumb
class TestLib(TestCase):
@ -197,3 +199,163 @@ class TestLib(TestCase):
"""
assert True, u'Impossible to test due to conflicts when mocking out the "open" function'
def build_icon_with_qicon_test(self):
"""
Test the build_icon() function with a QIcon instance
"""
with patch(u'openlp.core.lib.QtGui') as MockedQtGui:
# GIVEN: A mocked QIcon
MockedQtGui.QIcon = MagicMock
mocked_icon = MockedQtGui.QIcon()
# WHEN: We pass a QIcon instance in
result = build_icon(mocked_icon)
# THEN: The result should be our mocked QIcon
assert result is mocked_icon, u'The result should be the mocked QIcon'
def build_icon_with_resource_test(self):
"""
Test the build_icon() function with a resource URI
"""
with patch(u'openlp.core.lib.QtGui') as MockedQtGui, \
patch(u'openlp.core.lib.QtGui.QPixmap') as MockedQPixmap:
# GIVEN: A mocked QIcon and a mocked QPixmap
MockedQtGui.QIcon = MagicMock
MockedQtGui.QIcon.Normal = 1
MockedQtGui.QIcon.Off = 2
MockedQPixmap.return_value = u'mocked_pixmap'
resource_uri = u':/resource/uri'
# WHEN: We pass a QIcon instance in
result = build_icon(resource_uri)
# THEN: The result should be our mocked QIcon
MockedQPixmap.assert_called_with(resource_uri)
# There really should be more assert statements here but due to type checking and things they all break. The
# best we can do is to assert that we get back a MagicMock object.
assert isinstance(result, MagicMock), u'The result should be a MagicMock, because we mocked it out'
def image_to_byte_test(self):
"""
Test the image_to_byte() function
"""
with patch(u'openlp.core.lib.QtCore') as MockedQtCore:
# GIVEN: A set of mocked-out Qt classes
mocked_byte_array = MagicMock()
MockedQtCore.QByteArray.return_value = mocked_byte_array
mocked_byte_array.toBase64.return_value = u'base64mock'
mocked_buffer = MagicMock()
MockedQtCore.QBuffer.return_value = mocked_buffer
MockedQtCore.QIODevice.WriteOnly = u'writeonly'
mocked_image = MagicMock()
# WHEN: We convert an image to a byte array
result = image_to_byte(mocked_image)
# THEN: We should receive a value of u'base64mock'
MockedQtCore.QByteArray.assert_called_with()
MockedQtCore.QBuffer.assert_called_with(mocked_byte_array)
mocked_buffer.open.assert_called_with(u'writeonly')
mocked_image.save.assert_called_with(mocked_buffer, "PNG")
mocked_byte_array.toBase64.assert_called_with()
assert result == u'base64mock', u'The result should be the return value of the mocked out base64 method'
def check_item_selected_true_test(self):
"""
Test that the check_item_selected() function returns True when there are selected indexes.
"""
# GIVEN: A mocked out QtGui module and a list widget with selected indexes
MockedQtGui = patch(u'openlp.core.lib.QtGui')
mocked_list_widget = MagicMock()
mocked_list_widget.selectedIndexes.return_value = True
message = u'message'
# WHEN: We check if there are selected items
result = check_item_selected(mocked_list_widget, message)
# THEN: The selectedIndexes function should have been called and the result should be true
mocked_list_widget.selectedIndexes.assert_called_with()
assert result, u'The result should be True'
def check_item_selected_false_test(self):
"""
Test that the check_item_selected() function returns False when there are no selected indexes.
"""
# GIVEN: A mocked out QtGui module and a list widget with selected indexes
with patch(u'openlp.core.lib.QtGui') as MockedQtGui, \
patch(u'openlp.core.lib.translate') as mocked_translate:
mocked_translate.return_value = u'mocked translate'
mocked_list_widget = MagicMock()
mocked_list_widget.selectedIndexes.return_value = False
mocked_list_widget.parent.return_value = u'parent'
message = u'message'
# WHEN: We check if there are selected items
result = check_item_selected(mocked_list_widget, message)
# THEN: The selectedIndexes function should have been called and the result should be true
mocked_list_widget.selectedIndexes.assert_called_with()
MockedQtGui.QMessageBox.information.assert_called_with(u'parent', u'mocked translate', 'message')
assert not result, u'The result should be False'
def validate_thumb_file_does_not_exist_test(self):
"""
Test the validate_thumb() function when the thumbnail does not exist
"""
# GIVEN: A mocked out os module, with path.exists returning False, and fake paths to a file and a thumb
with patch(u'openlp.core.lib.os') as mocked_os:
file_path = u'path/to/file'
thumb_path = u'path/to/thumb'
mocked_os.path.exists.return_value = False
# WHEN: we run the validate_thumb() function
result = validate_thumb(file_path, thumb_path)
# THEN: we should have called a few functions, and the result should be False
mocked_os.path.exists.assert_called_with(thumb_path)
assert result is False, u'The result should be False'
def validate_thumb_file_exists_and_newer_test(self):
"""
Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file
"""
# GIVEN: A mocked out os module, functions rigged to work for us, and fake paths to a file and a thumb
with patch(u'openlp.core.lib.os') as mocked_os:
file_path = u'path/to/file'
thumb_path = u'path/to/thumb'
file_mocked_stat = MagicMock()
file_mocked_stat.st_mtime = datetime.now()
thumb_mocked_stat = MagicMock()
thumb_mocked_stat.st_mtime = datetime.now() + timedelta(seconds=10)
mocked_os.path.exists.return_value = True
mocked_os.stat.side_effect = [file_mocked_stat, thumb_mocked_stat]
# WHEN: we run the validate_thumb() function
# THEN: we should have called a few functions, and the result should be True
#mocked_os.path.exists.assert_called_with(thumb_path)
def validate_thumb_file_exists_and_older_test(self):
"""
Test the validate_thumb() function when the thumbnail exists but is older than the file
"""
# GIVEN: A mocked out os module, functions rigged to work for us, and fake paths to a file and a thumb
with patch(u'openlp.core.lib.os') as mocked_os:
file_path = u'path/to/file'
thumb_path = u'path/to/thumb'
file_mocked_stat = MagicMock()
file_mocked_stat.st_mtime = datetime.now()
thumb_mocked_stat = MagicMock()
thumb_mocked_stat.st_mtime = datetime.now() - timedelta(seconds=10)
mocked_os.path.exists.return_value = True
mocked_os.stat.side_effect = [file_mocked_stat, thumb_mocked_stat]
# WHEN: we run the validate_thumb() function
result = validate_thumb(file_path, thumb_path)
# THEN: we should have called a few functions, and the result should be False
mocked_os.path.exists.assert_called_with(thumb_path)
mocked_os.stat.assert_any_call(file_path)
mocked_os.stat.assert_any_call(thumb_path)
assert result is False, u'The result should be False'

View File

@ -16,7 +16,7 @@ VERSE = u'The Lord said to {r}Noah{/r}: \n'\
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'resources'))
TESTPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
class TestServiceItem(TestCase):

View File

@ -2,9 +2,10 @@
Package to test the openlp.core.ui package.
"""
import sys
from unittest import TestCase
from mock import MagicMock
from openlp.core.ui import starttimeform
from PyQt4 import QtCore, QtGui, QtTest
@ -14,10 +15,18 @@ class TestStartTimeDialog(TestCase):
"""
Create the UI
"""
self.app = QtGui.QApplication(sys.argv)
self.app = QtGui.QApplication([])
self.window = QtGui.QMainWindow()
self.form = starttimeform.StartTimeForm(self.window)
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.form
del self.window
del self.app
def ui_defaults_test(self):
"""
Test StartTimeDialog defaults

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

View File

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 213 KiB