forked from openlp/openlp
Merged with Tim's refactoring changes
This commit is contained in:
commit
d2782e099f
@ -137,6 +137,7 @@ class OpenLP(QtGui.QApplication):
|
|||||||
self.main_window = MainWindow()
|
self.main_window = MainWindow()
|
||||||
Registry().execute('bootstrap_initialise')
|
Registry().execute('bootstrap_initialise')
|
||||||
Registry().execute('bootstrap_post_set_up')
|
Registry().execute('bootstrap_post_set_up')
|
||||||
|
Registry().initialise = False
|
||||||
self.main_window.show()
|
self.main_window.show()
|
||||||
if show_splash:
|
if show_splash:
|
||||||
# now kill the splashscreen
|
# now kill the splashscreen
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
# Copyright (c) 2008-2014 Raoul Snyman #
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||||
@ -33,7 +33,7 @@ import logging
|
|||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from openlp.core.common import trace_error_handler
|
from openlp.core.common import trace_error_handler
|
||||||
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent']
|
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event']
|
||||||
|
|
||||||
|
|
||||||
class OpenLPMixin(object):
|
class OpenLPMixin(object):
|
||||||
@ -68,13 +68,13 @@ class OpenLPMixin(object):
|
|||||||
|
|
||||||
def log_debug(self, message):
|
def log_debug(self, message):
|
||||||
"""
|
"""
|
||||||
Common log debug handler which prints the calling path
|
Common log debug handler
|
||||||
"""
|
"""
|
||||||
self.logger.debug(message)
|
self.logger.debug(message)
|
||||||
|
|
||||||
def log_info(self, message):
|
def log_info(self, message):
|
||||||
"""
|
"""
|
||||||
Common log info handler which prints the calling path
|
Common log info handler
|
||||||
"""
|
"""
|
||||||
self.logger.info(message)
|
self.logger.info(message)
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ class Registry(object):
|
|||||||
registry.service_list = {}
|
registry.service_list = {}
|
||||||
registry.functions_list = {}
|
registry.functions_list = {}
|
||||||
registry.running_under_test = False
|
registry.running_under_test = False
|
||||||
|
registry.initialising = True
|
||||||
# Allow the tests to remove Registry entries but not the live system
|
# Allow the tests to remove Registry entries but not the live system
|
||||||
if 'nose' in sys.argv[0]:
|
if 'nose' in sys.argv[0]:
|
||||||
registry.running_under_test = True
|
registry.running_under_test = True
|
||||||
@ -78,9 +79,10 @@ class Registry(object):
|
|||||||
if key in self.service_list:
|
if key in self.service_list:
|
||||||
return self.service_list[key]
|
return self.service_list[key]
|
||||||
else:
|
else:
|
||||||
|
if not self.initialising:
|
||||||
trace_error_handler(log)
|
trace_error_handler(log)
|
||||||
log.error('Service %s not found in list' % key)
|
log.error('Service %s not found in list' % key)
|
||||||
#raise KeyError('Service %s not found in list' % key)
|
raise KeyError('Service %s not found in list' % key)
|
||||||
|
|
||||||
def register(self, key, reference):
|
def register(self, key, reference):
|
||||||
"""
|
"""
|
||||||
@ -170,5 +172,5 @@ class Registry(object):
|
|||||||
log.exception('Exception for function %s', function)
|
log.exception('Exception for function %s', function)
|
||||||
else:
|
else:
|
||||||
trace_error_handler(log)
|
trace_error_handler(log)
|
||||||
log.error("Event %s not called by not registered" % event)
|
log.error("Event %s called but not registered" % event)
|
||||||
return results
|
return results
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
# Copyright (c) 2008-2014 Raoul Snyman #
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||||
|
@ -386,7 +386,7 @@ class Settings(QtCore.QSettings):
|
|||||||
"""
|
"""
|
||||||
if self.group():
|
if self.group():
|
||||||
key = self.group() + '/' + key
|
key = self.group() + '/' + key
|
||||||
return Settings.__default_settings__[key]
|
return Settings.__default_settings__.get(key, '')
|
||||||
|
|
||||||
def remove_obsolete_settings(self):
|
def remove_obsolete_settings(self):
|
||||||
"""
|
"""
|
||||||
@ -424,9 +424,9 @@ class Settings(QtCore.QSettings):
|
|||||||
"""
|
"""
|
||||||
# if group() is not empty the group has not been specified together with the key.
|
# if group() is not empty the group has not been specified together with the key.
|
||||||
if self.group():
|
if self.group():
|
||||||
default_value = Settings.__default_settings__[self.group() + '/' + key]
|
default_value = Settings.__default_settings__.get(self.group() + '/' + key, '')
|
||||||
else:
|
else:
|
||||||
default_value = Settings.__default_settings__[key]
|
default_value = Settings.__default_settings__.get(key, '')
|
||||||
setting = super(Settings, self).value(key, default_value)
|
setting = super(Settings, self).value(key, default_value)
|
||||||
return self._convert_value(setting, default_value)
|
return self._convert_value(setting, default_value)
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ def get_text_file_string(text_file):
|
|||||||
returns False. If there is an error loading the file or the content can't be decoded then the function will return
|
returns False. If there is an error loading the file or the content can't be decoded then the function will return
|
||||||
None.
|
None.
|
||||||
|
|
||||||
``textfile``
|
:param text_file: The name of the file.
|
||||||
The name of the file.
|
:return The file as a single string
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(text_file):
|
if not os.path.isfile(text_file):
|
||||||
return False
|
return False
|
||||||
@ -114,8 +114,8 @@ def str_to_bool(string_value):
|
|||||||
"""
|
"""
|
||||||
Convert a string version of a boolean into a real boolean.
|
Convert a string version of a boolean into a real boolean.
|
||||||
|
|
||||||
``string_value``
|
:param string_value: The string value to examine and convert to a boolean type.
|
||||||
The string value to examine and convert to a boolean type.
|
:return The correct boolean value
|
||||||
"""
|
"""
|
||||||
if isinstance(string_value, bool):
|
if isinstance(string_value, bool):
|
||||||
return string_value
|
return string_value
|
||||||
@ -127,9 +127,10 @@ def build_icon(icon):
|
|||||||
Build a QIcon instance from an existing QIcon, a resource location, or a physical file location. If the icon is a
|
Build a QIcon instance from an existing QIcon, a resource location, or a physical file location. If the icon is a
|
||||||
QIcon instance, that icon is simply returned. If not, it builds a QIcon instance from the resource or file name.
|
QIcon instance, that icon is simply returned. If not, it builds a QIcon instance from the resource or file name.
|
||||||
|
|
||||||
``icon``
|
:param icon:
|
||||||
The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file
|
The icon to build. This can be a QIcon, a resource string in the form ``:/resource/file.png``, or a file
|
||||||
location like ``/path/to/file.png``. However, the **recommended** way is to specify a resource string.
|
location like ``/path/to/file.png``. However, the **recommended** way is to specify a resource string.
|
||||||
|
:return The build icon.
|
||||||
"""
|
"""
|
||||||
button_icon = QtGui.QIcon()
|
button_icon = QtGui.QIcon()
|
||||||
if isinstance(icon, QtGui.QIcon):
|
if isinstance(icon, QtGui.QIcon):
|
||||||
@ -148,11 +149,8 @@ def image_to_byte(image, base_64=True):
|
|||||||
"""
|
"""
|
||||||
Resize an image to fit on the current screen for the web and returns it as a byte stream.
|
Resize an image to fit on the current screen for the web and returns it as a byte stream.
|
||||||
|
|
||||||
``image``
|
:param image: The image to converted.
|
||||||
The image to converted.
|
:param base_64: If True returns the image as Base64 bytes, otherwise the image is returned as a byte array.
|
||||||
|
|
||||||
``base_64``
|
|
||||||
If True returns the image as Base64 bytes, otherwise the image is returned as a byte array
|
|
||||||
To preserve original intention, this defaults to True
|
To preserve original intention, this defaults to True
|
||||||
"""
|
"""
|
||||||
log.debug('image_to_byte - start')
|
log.debug('image_to_byte - start')
|
||||||
@ -172,18 +170,12 @@ def create_thumb(image_path, thumb_path, return_icon=True, size=None):
|
|||||||
"""
|
"""
|
||||||
Create a thumbnail from the given image path and depending on ``return_icon`` it returns an icon from this thumb.
|
Create a thumbnail from the given image path and depending on ``return_icon`` it returns an icon from this thumb.
|
||||||
|
|
||||||
``image_path``
|
:param image_path: The image file to create the icon from.
|
||||||
The image file to create the icon from.
|
:param thumb_path: The filename to save the thumbnail to.
|
||||||
|
:param return_icon: States if an icon should be build and returned from the thumb. Defaults to ``True``.
|
||||||
``thumb_path``
|
:param size: Allows to state a own size (QtCore.QSize) to use. Defaults to ``None``, which means that a default
|
||||||
The filename to save the thumbnail to.
|
height of 88 is used.
|
||||||
|
:return The final icon.
|
||||||
``return_icon``
|
|
||||||
States if an icon should be build and returned from the thumb. Defaults to ``True``.
|
|
||||||
|
|
||||||
``size``
|
|
||||||
Allows to state a own size (QtCore.QSize) to use. Defaults to ``None``, which means that a default height of 88
|
|
||||||
is used.
|
|
||||||
"""
|
"""
|
||||||
ext = os.path.splitext(thumb_path)[1].lower()
|
ext = os.path.splitext(thumb_path)[1].lower()
|
||||||
reader = QtGui.QImageReader(image_path)
|
reader = QtGui.QImageReader(image_path)
|
||||||
@ -207,11 +199,9 @@ def validate_thumb(file_path, thumb_path):
|
|||||||
Validates whether an file's thumb still exists and if is up to date. **Note**, you must **not** call this function,
|
Validates whether an file's thumb still exists and if is up to date. **Note**, you must **not** call this function,
|
||||||
before checking the existence of the file.
|
before checking the existence of the file.
|
||||||
|
|
||||||
``file_path``
|
:param file_path: The path to the file. The file **must** exist!
|
||||||
The path to the file. The file **must** exist!
|
:param thumb_path: The path to the thumb.
|
||||||
|
:return True, False if the image has changed since the thumb was created.
|
||||||
``thumb_path``
|
|
||||||
The path to the thumb.
|
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(thumb_path):
|
if not os.path.exists(thumb_path):
|
||||||
return False
|
return False
|
||||||
@ -224,19 +214,12 @@ def resize_image(image_path, width, height, background='#000000'):
|
|||||||
"""
|
"""
|
||||||
Resize an image to fit on the current screen.
|
Resize an image to fit on the current screen.
|
||||||
|
|
||||||
``image_path``
|
|
||||||
The path to the image to resize.
|
|
||||||
|
|
||||||
``width``
|
|
||||||
The new image width.
|
|
||||||
|
|
||||||
``height``
|
|
||||||
The new image height.
|
|
||||||
|
|
||||||
``background``
|
|
||||||
The background colour. Defaults to black.
|
|
||||||
|
|
||||||
DO NOT REMOVE THE DEFAULT BACKGROUND VALUE!
|
DO NOT REMOVE THE DEFAULT BACKGROUND VALUE!
|
||||||
|
|
||||||
|
:param image_path: The path to the image to resize.
|
||||||
|
:param width: The new image width.
|
||||||
|
:param height: The new image height.
|
||||||
|
:param background: The background colour. Defaults to black.
|
||||||
"""
|
"""
|
||||||
log.debug('resize_image - start')
|
log.debug('resize_image - start')
|
||||||
reader = QtGui.QImageReader(image_path)
|
reader = QtGui.QImageReader(image_path)
|
||||||
@ -271,11 +254,8 @@ def check_item_selected(list_widget, message):
|
|||||||
"""
|
"""
|
||||||
Check if a list item is selected so an action may be performed on it
|
Check if a list item is selected so an action may be performed on it
|
||||||
|
|
||||||
``list_widget``
|
:param list_widget: The list to check for selected items
|
||||||
The list to check for selected items
|
:param message: The message to give the user if no item is selected
|
||||||
|
|
||||||
``message``
|
|
||||||
The message to give the user if no item is selected
|
|
||||||
"""
|
"""
|
||||||
if not list_widget.selectedIndexes():
|
if not list_widget.selectedIndexes():
|
||||||
QtGui.QMessageBox.information(list_widget.parent(),
|
QtGui.QMessageBox.information(list_widget.parent(),
|
||||||
@ -287,6 +267,8 @@ def check_item_selected(list_widget, message):
|
|||||||
def clean_tags(text):
|
def clean_tags(text):
|
||||||
"""
|
"""
|
||||||
Remove Tags from text for display
|
Remove Tags from text for display
|
||||||
|
|
||||||
|
:param text: Text to be cleaned
|
||||||
"""
|
"""
|
||||||
text = text.replace('<br>', '\n')
|
text = text.replace('<br>', '\n')
|
||||||
text = text.replace('{br}', '\n')
|
text = text.replace('{br}', '\n')
|
||||||
@ -300,6 +282,8 @@ def clean_tags(text):
|
|||||||
def expand_tags(text):
|
def expand_tags(text):
|
||||||
"""
|
"""
|
||||||
Expand tags HTML for display
|
Expand tags HTML for display
|
||||||
|
|
||||||
|
:param text: The text to be expanded.
|
||||||
"""
|
"""
|
||||||
for tag in FormattingTags.get_html_tags():
|
for tag in FormattingTags.get_html_tags():
|
||||||
text = text.replace(tag['start tag'], tag['start html'])
|
text = text.replace(tag['start tag'], tag['start html'])
|
||||||
@ -310,11 +294,11 @@ def expand_tags(text):
|
|||||||
def create_separated_list(string_list):
|
def create_separated_list(string_list):
|
||||||
"""
|
"""
|
||||||
Returns a string that represents a join of a list of strings with a localized separator. This function corresponds
|
Returns a string that represents a join of a list of strings with a localized separator. This function corresponds
|
||||||
|
|
||||||
to QLocale::createSeparatedList which was introduced in Qt 4.8 and implements the algorithm from
|
to QLocale::createSeparatedList which was introduced in Qt 4.8 and implements the algorithm from
|
||||||
http://www.unicode.org/reports/tr35/#ListPatterns
|
http://www.unicode.org/reports/tr35/#ListPatterns
|
||||||
|
|
||||||
``string_list``
|
:param string_list: List of unicode strings
|
||||||
List of unicode strings
|
|
||||||
"""
|
"""
|
||||||
if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion('4.9') and \
|
if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion('4.9') and \
|
||||||
LooseVersion(Qt.qVersion()) >= LooseVersion('4.8'):
|
LooseVersion(Qt.qVersion()) >= LooseVersion('4.8'):
|
||||||
|
@ -133,7 +133,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit):
|
|||||||
"""
|
"""
|
||||||
self.dictionary = enchant.Dict(action.text())
|
self.dictionary = enchant.Dict(action.text())
|
||||||
self.highlighter.spelling_dictionary = self.dictionary
|
self.highlighter.spelling_dictionary = self.dictionary
|
||||||
self.highlighter.highlight_block(self.toPlainText())
|
self.highlighter.highlightBlock(self.toPlainText())
|
||||||
self.highlighter.rehighlight()
|
self.highlighter.rehighlight()
|
||||||
|
|
||||||
def correct_word(self, word):
|
def correct_word(self, word):
|
||||||
@ -180,9 +180,11 @@ class Highlighter(QtGui.QSyntaxHighlighter):
|
|||||||
super(Highlighter, self).__init__(*args)
|
super(Highlighter, self).__init__(*args)
|
||||||
self.spelling_dictionary = None
|
self.spelling_dictionary = None
|
||||||
|
|
||||||
def highlight_block(self, text):
|
def highlightBlock(self, text):
|
||||||
"""
|
"""
|
||||||
Highlight misspelt words in a block of text.
|
Highlight misspelt words in a block of text.
|
||||||
|
|
||||||
|
Note, this is a Qt hook.
|
||||||
"""
|
"""
|
||||||
if not self.spelling_dictionary:
|
if not self.spelling_dictionary:
|
||||||
return
|
return
|
||||||
|
@ -342,18 +342,16 @@ def create_valign_selection_widgets(parent):
|
|||||||
return label, combo_box
|
return label, combo_box
|
||||||
|
|
||||||
|
|
||||||
def find_and_set_in_combo_box(combo_box, value_to_find):
|
def find_and_set_in_combo_box(combo_box, value_to_find, set_missing=True):
|
||||||
"""
|
"""
|
||||||
Find a string in a combo box and set it as the selected item if present
|
Find a string in a combo box and set it as the selected item if present
|
||||||
|
|
||||||
``combo_box``
|
:param combo_box: The combo box to check for selected items
|
||||||
The combo box to check for selected items
|
:param value_to_find: The value to find
|
||||||
|
:param set_missing: if not found leave value as current
|
||||||
``value_to_find``
|
|
||||||
The value to find
|
|
||||||
"""
|
"""
|
||||||
index = combo_box.findText(value_to_find, QtCore.Qt.MatchExactly)
|
index = combo_box.findText(value_to_find, QtCore.Qt.MatchExactly)
|
||||||
if index == -1:
|
if index == -1:
|
||||||
# Not Found.
|
# Not Found.
|
||||||
index = 0
|
index = 0 if set_missing else combo_box.currentIndex()
|
||||||
combo_box.setCurrentIndex(index)
|
combo_box.setCurrentIndex(index)
|
||||||
|
@ -99,11 +99,10 @@ from .formattingtagcontroller import FormattingTagController
|
|||||||
from .shortcutlistform import ShortcutListForm
|
from .shortcutlistform import ShortcutListForm
|
||||||
from .mediadockmanager import MediaDockManager
|
from .mediadockmanager import MediaDockManager
|
||||||
from .servicemanager import ServiceManager
|
from .servicemanager import ServiceManager
|
||||||
from .thememanagerhelper import ThemeManagerHelper
|
|
||||||
from .thememanager import ThemeManager
|
from .thememanager import ThemeManager
|
||||||
|
|
||||||
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
|
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
|
||||||
'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
|
'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
|
||||||
'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
|
'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
|
||||||
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
|
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
|
||||||
'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'ThemeManagerHelper']
|
'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController']
|
||||||
|
@ -94,8 +94,8 @@ class ListPreviewWidget(QtGui.QTableWidget):
|
|||||||
Displays the given slide.
|
Displays the given slide.
|
||||||
"""
|
"""
|
||||||
self.service_item = service_item
|
self.service_item = service_item
|
||||||
self.clear()
|
|
||||||
self.setRowCount(0)
|
self.setRowCount(0)
|
||||||
|
self.clear()
|
||||||
self.setColumnWidth(0, width)
|
self.setColumnWidth(0, width)
|
||||||
row = 0
|
row = 0
|
||||||
text = []
|
text = []
|
||||||
|
@ -35,7 +35,7 @@ import os
|
|||||||
import datetime
|
import datetime
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.common import Registry, Settings, UiStrings, translate
|
from openlp.core.common import Registry, RegistryMixin, Settings, UiStrings, translate
|
||||||
from openlp.core.lib import OpenLPToolbar
|
from openlp.core.lib import OpenLPToolbar
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players
|
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players
|
||||||
@ -99,7 +99,7 @@ class MediaController(object):
|
|||||||
Constructor
|
Constructor
|
||||||
"""
|
"""
|
||||||
Registry().register('media_controller', self)
|
Registry().register('media_controller', self)
|
||||||
Registry().register_function('bootstrap_initialise', self.check_available_media_players)
|
Registry().register_function('bootstrap_initialise', self.bootstrap_initialise)
|
||||||
self.media_players = {}
|
self.media_players = {}
|
||||||
self.display_controllers = {}
|
self.display_controllers = {}
|
||||||
self.current_media_players = {}
|
self.current_media_players = {}
|
||||||
@ -134,20 +134,22 @@ class MediaController(object):
|
|||||||
"""
|
"""
|
||||||
Set the active players and available media files
|
Set the active players and available media files
|
||||||
"""
|
"""
|
||||||
|
suffix_list = []
|
||||||
self.audio_extensions_list = []
|
self.audio_extensions_list = []
|
||||||
for player in list(self.media_players.values()):
|
for player in list(self.media_players.values()):
|
||||||
if player.is_active:
|
if player.is_active:
|
||||||
for item in player.audio_extensions_list:
|
for item in player.audio_extensions_list:
|
||||||
if not item in self.audio_extensions_list:
|
if not item in self.audio_extensions_list:
|
||||||
self.audio_extensions_list.append(item)
|
self.audio_extensions_list.append(item)
|
||||||
self.service_manager.supported_suffixes(item[2:])
|
suffix_list.append(item[2:])
|
||||||
self.video_extensions_list = []
|
self.video_extensions_list = []
|
||||||
for player in list(self.media_players.values()):
|
for player in list(self.media_players.values()):
|
||||||
if player.is_active:
|
if player.is_active:
|
||||||
for item in player.video_extensions_list:
|
for item in player.video_extensions_list:
|
||||||
if item not in self.video_extensions_list:
|
if item not in self.video_extensions_list:
|
||||||
self.video_extensions_list.extend(item)
|
self.video_extensions_list.extend(item)
|
||||||
self.service_manager.supported_suffixes(item[2:])
|
suffix_list.append(item[2:])
|
||||||
|
self.service_manager.supported_suffixes(suffix_list)
|
||||||
|
|
||||||
def register_players(self, player):
|
def register_players(self, player):
|
||||||
"""
|
"""
|
||||||
@ -159,7 +161,7 @@ class MediaController(object):
|
|||||||
"""
|
"""
|
||||||
self.media_players[player.name] = player
|
self.media_players[player.name] = player
|
||||||
|
|
||||||
def check_available_media_players(self):
|
def bootstrap_initialise(self):
|
||||||
"""
|
"""
|
||||||
Check to see if we have any media Player's available.
|
Check to see if we have any media Player's available.
|
||||||
"""
|
"""
|
||||||
@ -169,27 +171,28 @@ class MediaController(object):
|
|||||||
if filename.endswith('player.py') and not filename == 'mediaplayer.py':
|
if filename.endswith('player.py') and not filename == 'mediaplayer.py':
|
||||||
path = os.path.join(controller_dir, filename)
|
path = os.path.join(controller_dir, filename)
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
modulename = 'openlp.core.ui.media.' + os.path.splitext(filename)[0]
|
module_name = 'openlp.core.ui.media.' + os.path.splitext(filename)[0]
|
||||||
log.debug('Importing controller %s', modulename)
|
log.debug('Importing controller %s', module_name)
|
||||||
try:
|
try:
|
||||||
__import__(modulename, globals(), locals(), [])
|
__import__(module_name, globals(), locals(), [])
|
||||||
# On some platforms importing vlc.py might cause
|
# On some platforms importing vlc.py might cause
|
||||||
# also OSError exceptions. (e.g. Mac OS X)
|
# also OSError exceptions. (e.g. Mac OS X)
|
||||||
except (ImportError, OSError):
|
except (ImportError, OSError):
|
||||||
log.warn('Failed to import %s on path %s', modulename, path)
|
log.warn('Failed to import %s on path %s', module_name, path)
|
||||||
player_classes = MediaPlayer.__subclasses__()
|
player_classes = MediaPlayer.__subclasses__()
|
||||||
for player_class in player_classes:
|
for player_class in player_classes:
|
||||||
player = player_class(self)
|
player = player_class(self)
|
||||||
self.register_players(player)
|
self.register_players(player)
|
||||||
if not self.media_players:
|
if not self.media_players:
|
||||||
return False
|
return False
|
||||||
savedPlayers, overriddenPlayer = get_media_players()
|
saved_players, overridden_player = get_media_players()
|
||||||
invalid_media_players = [mediaPlayer for mediaPlayer in savedPlayers
|
invalid_media_players = \
|
||||||
if not mediaPlayer in self.media_players or not self.media_players[mediaPlayer].check_available()]
|
[mediaPlayer for mediaPlayer in saved_players if not mediaPlayer in self.media_players or
|
||||||
|
not self.media_players[mediaPlayer].check_available()]
|
||||||
if invalid_media_players:
|
if invalid_media_players:
|
||||||
for invalidPlayer in invalid_media_players:
|
for invalidPlayer in invalid_media_players:
|
||||||
savedPlayers.remove(invalidPlayer)
|
saved_players.remove(invalidPlayer)
|
||||||
set_media_players(savedPlayers, overriddenPlayer)
|
set_media_players(saved_players, overridden_player)
|
||||||
self._set_active_players()
|
self._set_active_players()
|
||||||
self._generate_extensions_lists()
|
self._generate_extensions_lists()
|
||||||
return True
|
return True
|
||||||
@ -271,13 +274,16 @@ class MediaController(object):
|
|||||||
controller.mediabar = OpenLPToolbar(controller)
|
controller.mediabar = OpenLPToolbar(controller)
|
||||||
controller.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play',
|
controller.mediabar.add_toolbar_action('playbackPlay', text='media_playback_play',
|
||||||
icon=':/slides/media_playback_start.png',
|
icon=':/slides/media_playback_start.png',
|
||||||
tooltip=translate('OpenLP.SlideController', 'Start playing media.'), triggers=controller.send_to_plugins)
|
tooltip=translate('OpenLP.SlideController', 'Start playing media.'),
|
||||||
|
triggers=controller.send_to_plugins)
|
||||||
controller.mediabar.add_toolbar_action('playbackPause', text='media_playback_pause',
|
controller.mediabar.add_toolbar_action('playbackPause', text='media_playback_pause',
|
||||||
icon=':/slides/media_playback_pause.png',
|
icon=':/slides/media_playback_pause.png',
|
||||||
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'), triggers=controller.send_to_plugins)
|
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
|
||||||
|
triggers=controller.send_to_plugins)
|
||||||
controller.mediabar.add_toolbar_action('playbackStop', text='media_playback_stop',
|
controller.mediabar.add_toolbar_action('playbackStop', text='media_playback_stop',
|
||||||
icon=':/slides/media_playback_stop.png',
|
icon=':/slides/media_playback_stop.png',
|
||||||
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.send_to_plugins)
|
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
|
||||||
|
triggers=controller.send_to_plugins)
|
||||||
# Build the seek_slider.
|
# Build the seek_slider.
|
||||||
controller.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
|
controller.seek_slider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
|
||||||
controller.seek_slider.setMaximum(1000)
|
controller.seek_slider.setMaximum(1000)
|
||||||
|
@ -37,8 +37,7 @@ from openlp.core.ui.media import MediaState
|
|||||||
|
|
||||||
class MediaPlayer(object):
|
class MediaPlayer(object):
|
||||||
"""
|
"""
|
||||||
This is the base class media Player class to provide OpenLP with a
|
This is the base class media Player class to provide OpenLP with a pluggable media display framework.
|
||||||
pluggable media display framework.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent, name='media_player'):
|
def __init__(self, parent, name='media_player'):
|
||||||
|
@ -80,12 +80,12 @@ class PhononPlayer(MediaPlayer):
|
|||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.additional_extensions = ADDITIONAL_EXT
|
self.additional_extensions = ADDITIONAL_EXT
|
||||||
mimetypes.init()
|
mimetypes.init()
|
||||||
for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
|
for mime_type in Phonon.BackendCapabilities.availableMimeTypes():
|
||||||
mimetype = str(mimetype)
|
mime_type = str(mime_type)
|
||||||
if mimetype.startswith('audio/'):
|
if mime_type.startswith('audio/'):
|
||||||
self._addToList(self.audio_extensions_list, mimetype)
|
self._addToList(self.audio_extensions_list, mime_type)
|
||||||
elif mimetype.startswith('video/'):
|
elif mime_type.startswith('video/'):
|
||||||
self._addToList(self.video_extensions_list, mimetype)
|
self._addToList(self.video_extensions_list, mime_type)
|
||||||
|
|
||||||
def _addToList(self, mimetype_list, mimetype):
|
def _addToList(self, mimetype_list, mimetype):
|
||||||
"""
|
"""
|
||||||
@ -144,14 +144,14 @@ class PhononPlayer(MediaPlayer):
|
|||||||
self.volume(display, volume)
|
self.volume(display, volume)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def media_state_wait(self, display, mediaState):
|
def media_state_wait(self, display, media_state):
|
||||||
"""
|
"""
|
||||||
Wait for the video to change its state
|
Wait for the video to change its state
|
||||||
Wait no longer than 5 seconds.
|
Wait no longer than 5 seconds.
|
||||||
"""
|
"""
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
current_state = display.media_object.state()
|
current_state = display.media_object.state()
|
||||||
while current_state != mediaState:
|
while current_state != media_state:
|
||||||
current_state = display.media_object.state()
|
current_state = display.media_object.state()
|
||||||
if current_state == Phonon.ErrorState:
|
if current_state == Phonon.ErrorState:
|
||||||
return False
|
return False
|
||||||
@ -172,8 +172,7 @@ class PhononPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
start_time = 0
|
start_time = 0
|
||||||
if display.media_object.state() != Phonon.PausedState and \
|
if display.media_object.state() != Phonon.PausedState and controller.media_info.start_time > 0:
|
||||||
controller.media_info.start_time > 0:
|
|
||||||
start_time = controller.media_info.start_time
|
start_time = controller.media_info.start_time
|
||||||
display.media_object.play()
|
display.media_object.play()
|
||||||
if not self.media_state_wait(display, Phonon.PlayingState):
|
if not self.media_state_wait(display, Phonon.PlayingState):
|
||||||
|
@ -39,13 +39,13 @@ from openlp.core.ui.media import get_media_players, set_media_players
|
|||||||
|
|
||||||
class MediaQCheckBox(QtGui.QCheckBox):
|
class MediaQCheckBox(QtGui.QCheckBox):
|
||||||
"""
|
"""
|
||||||
MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
|
MediaQCheckBox adds an extra property, player_name to the QCheckBox class.
|
||||||
"""
|
"""
|
||||||
def set_player_name(self, name):
|
def set_player_name(self, name):
|
||||||
"""
|
"""
|
||||||
Set the player name
|
Set the player name
|
||||||
"""
|
"""
|
||||||
self.playerName = name
|
self.player_name = name
|
||||||
|
|
||||||
|
|
||||||
class PlayerTab(SettingsTab):
|
class PlayerTab(SettingsTab):
|
||||||
@ -136,7 +136,7 @@ class PlayerTab(SettingsTab):
|
|||||||
self.background_color_label.setText(UiStrings().DefaultColor)
|
self.background_color_label.setText(UiStrings().DefaultColor)
|
||||||
self.information_label.setText(translate('OpenLP.PlayerTab',
|
self.information_label.setText(translate('OpenLP.PlayerTab',
|
||||||
'Visible background for videos with aspect ratio different to screen.'))
|
'Visible background for videos with aspect ratio different to screen.'))
|
||||||
self.retranslatePlayers()
|
self.retranslate_players()
|
||||||
|
|
||||||
def on_background_color_button_clicked(self):
|
def on_background_color_button_clicked(self):
|
||||||
"""
|
"""
|
||||||
@ -151,7 +151,7 @@ class PlayerTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
Add or remove players depending on their status
|
Add or remove players depending on their status
|
||||||
"""
|
"""
|
||||||
player = self.sender().playerName
|
player = self.sender().player_name
|
||||||
if check_state == QtCore.Qt.Checked:
|
if check_state == QtCore.Qt.Checked:
|
||||||
if player not in self.used_players:
|
if player not in self.used_players:
|
||||||
self.used_players.append(player)
|
self.used_players.append(player)
|
||||||
@ -249,9 +249,9 @@ class PlayerTab(SettingsTab):
|
|||||||
else:
|
else:
|
||||||
checkbox.setChecked(False)
|
checkbox.setChecked(False)
|
||||||
self.update_player_list()
|
self.update_player_list()
|
||||||
self.retranslatePlayers()
|
self.retranslate_players()
|
||||||
|
|
||||||
def retranslatePlayers(self):
|
def retranslate_players(self):
|
||||||
"""
|
"""
|
||||||
Translations for players is dependent on their setup as well
|
Translations for players is dependent on their setup as well
|
||||||
"""
|
"""
|
||||||
|
@ -118,35 +118,35 @@ class VlcPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
Set up the media player
|
Set up the media player
|
||||||
"""
|
"""
|
||||||
display.vlcWidget = QtGui.QFrame(display)
|
display.vlc_widget = QtGui.QFrame(display)
|
||||||
display.vlcWidget.setFrameStyle(QtGui.QFrame.NoFrame)
|
display.vlc_widget.setFrameStyle(QtGui.QFrame.NoFrame)
|
||||||
# creating a basic vlc instance
|
# creating a basic vlc instance
|
||||||
command_line_options = '--no-video-title-show'
|
command_line_options = '--no-video-title-show'
|
||||||
if not display.has_audio:
|
if not display.has_audio:
|
||||||
command_line_options += ' --no-audio --no-video-title-show'
|
command_line_options += ' --no-audio --no-video-title-show'
|
||||||
if Settings().value('advanced/hide mouse') and display.controller.is_live:
|
if Settings().value('advanced/hide mouse') and display.controller.is_live:
|
||||||
command_line_options += ' --mouse-hide-timeout=0'
|
command_line_options += ' --mouse-hide-timeout=0'
|
||||||
display.vlcInstance = vlc.Instance(command_line_options)
|
display.vlc_instance = vlc.Instance(command_line_options)
|
||||||
# creating an empty vlc media player
|
# creating an empty vlc media player
|
||||||
display.vlcMediaPlayer = display.vlcInstance.media_player_new()
|
display.vlc_media_player = display.vlc_instance.media_player_new()
|
||||||
display.vlcWidget.resize(display.size())
|
display.vlc_widget.resize(display.size())
|
||||||
display.vlcWidget.raise_()
|
display.vlc_widget.raise_()
|
||||||
display.vlcWidget.hide()
|
display.vlc_widget.hide()
|
||||||
# The media player has to be 'connected' to the QFrame.
|
# The media player has to be 'connected' to the QFrame.
|
||||||
# (otherwise a video would be displayed in it's own window)
|
# (otherwise a video would be displayed in it's own window)
|
||||||
# This is platform specific!
|
# This is platform specific!
|
||||||
# You have to give the id of the QFrame (or similar object)
|
# You have to give the id of the QFrame (or similar object)
|
||||||
# to vlc, different platforms have different functions for this.
|
# to vlc, different platforms have different functions for this.
|
||||||
win_id = int(display.vlcWidget.winId())
|
win_id = int(display.vlc_widget.winId())
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
display.vlcMediaPlayer.set_hwnd(win_id)
|
display.vlc_media_player.set_hwnd(win_id)
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
# We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa
|
# We have to use 'set_nsobject' since Qt4 on OSX uses Cocoa
|
||||||
# framework and not the old Carbon.
|
# framework and not the old Carbon.
|
||||||
display.vlcMediaPlayer.set_nsobject(win_id)
|
display.vlc_media_player.set_nsobject(win_id)
|
||||||
else:
|
else:
|
||||||
# for Linux using the X Server
|
# for Linux using the X Server
|
||||||
display.vlcMediaPlayer.set_xwindow(win_id)
|
display.vlc_media_player.set_xwindow(win_id)
|
||||||
self.has_own_widget = True
|
self.has_own_widget = True
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
@ -165,18 +165,18 @@ class VlcPlayer(MediaPlayer):
|
|||||||
file_path = str(controller.media_info.file_info.absoluteFilePath())
|
file_path = str(controller.media_info.file_info.absoluteFilePath())
|
||||||
path = os.path.normcase(file_path)
|
path = os.path.normcase(file_path)
|
||||||
# create the media
|
# create the media
|
||||||
display.vlcMedia = display.vlcInstance.media_new_path(path)
|
display.vlc_media = display.vlc_instance.media_new_path(path)
|
||||||
# put the media in the media player
|
# put the media in the media player
|
||||||
display.vlcMediaPlayer.set_media(display.vlcMedia)
|
display.vlc_media_player.set_media(display.vlc_media)
|
||||||
# parse the metadata of the file
|
# parse the metadata of the file
|
||||||
display.vlcMedia.parse()
|
display.vlc_media.parse()
|
||||||
self.volume(display, volume)
|
self.volume(display, volume)
|
||||||
# We need to set media_info.length during load because we want
|
# We need to set media_info.length during load because we want
|
||||||
# to avoid start and stop the video twice. Once for real playback
|
# to avoid start and stop the video twice. Once for real playback
|
||||||
# and once to just get media length.
|
# and once to just get media length.
|
||||||
#
|
#
|
||||||
# Media plugin depends on knowing media length before playback.
|
# Media plugin depends on knowing media length before playback.
|
||||||
controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
|
controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def media_state_wait(self, display, media_state):
|
def media_state_wait(self, display, media_state):
|
||||||
@ -185,8 +185,8 @@ class VlcPlayer(MediaPlayer):
|
|||||||
Wait no longer than 60 seconds. (loading an iso file needs a long time)
|
Wait no longer than 60 seconds. (loading an iso file needs a long time)
|
||||||
"""
|
"""
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
while not media_state == display.vlcMedia.get_state():
|
while not media_state == display.vlc_media.get_state():
|
||||||
if display.vlcMedia.get_state() == vlc.State.Error:
|
if display.vlc_media.get_state() == vlc.State.Error:
|
||||||
return False
|
return False
|
||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
if (datetime.now() - start).seconds > 60:
|
if (datetime.now() - start).seconds > 60:
|
||||||
@ -197,7 +197,7 @@ class VlcPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
Resize the player
|
Resize the player
|
||||||
"""
|
"""
|
||||||
display.vlcWidget.resize(display.size())
|
display.vlc_widget.resize(display.size())
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
"""
|
"""
|
||||||
@ -207,25 +207,25 @@ class VlcPlayer(MediaPlayer):
|
|||||||
start_time = 0
|
start_time = 0
|
||||||
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
|
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
|
||||||
start_time = controller.media_info.start_time
|
start_time = controller.media_info.start_time
|
||||||
display.vlcMediaPlayer.play()
|
display.vlc_media_player.play()
|
||||||
if not self.media_state_wait(display, vlc.State.Playing):
|
if not self.media_state_wait(display, vlc.State.Playing):
|
||||||
return False
|
return False
|
||||||
self.volume(display, controller.media_info.volume)
|
self.volume(display, controller.media_info.volume)
|
||||||
if start_time > 0:
|
if start_time > 0:
|
||||||
self.seek(display, controller.media_info.start_time * 1000)
|
self.seek(display, controller.media_info.start_time * 1000)
|
||||||
controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
|
controller.media_info.length = int(display.vlc_media_player.get_media().get_duration() / 1000)
|
||||||
controller.seek_slider.setMaximum(controller.media_info.length * 1000)
|
controller.seek_slider.setMaximum(controller.media_info.length * 1000)
|
||||||
self.state = MediaState.Playing
|
self.state = MediaState.Playing
|
||||||
display.vlcWidget.raise_()
|
display.vlc_widget.raise_()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self, display):
|
def pause(self, display):
|
||||||
"""
|
"""
|
||||||
Pause the current item
|
Pause the current item
|
||||||
"""
|
"""
|
||||||
if display.vlcMedia.get_state() != vlc.State.Playing:
|
if display.vlc_media.get_state() != vlc.State.Playing:
|
||||||
return
|
return
|
||||||
display.vlcMediaPlayer.pause()
|
display.vlc_media_player.pause()
|
||||||
if self.media_state_wait(display, vlc.State.Paused):
|
if self.media_state_wait(display, vlc.State.Paused):
|
||||||
self.state = MediaState.Paused
|
self.state = MediaState.Paused
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ class VlcPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
Stop the current item
|
Stop the current item
|
||||||
"""
|
"""
|
||||||
display.vlcMediaPlayer.stop()
|
display.vlc_media_player.stop()
|
||||||
self.state = MediaState.Stopped
|
self.state = MediaState.Stopped
|
||||||
|
|
||||||
def volume(self, display, vol):
|
def volume(self, display, vol):
|
||||||
@ -241,21 +241,21 @@ class VlcPlayer(MediaPlayer):
|
|||||||
Set the volume
|
Set the volume
|
||||||
"""
|
"""
|
||||||
if display.has_audio:
|
if display.has_audio:
|
||||||
display.vlcMediaPlayer.audio_set_volume(vol)
|
display.vlc_media_player.audio_set_volume(vol)
|
||||||
|
|
||||||
def seek(self, display, seek_value):
|
def seek(self, display, seek_value):
|
||||||
"""
|
"""
|
||||||
Go to a particular position
|
Go to a particular position
|
||||||
"""
|
"""
|
||||||
if display.vlcMediaPlayer.is_seekable():
|
if display.vlc_media_player.is_seekable():
|
||||||
display.vlcMediaPlayer.set_time(seek_value)
|
display.vlc_media_player.set_time(seek_value)
|
||||||
|
|
||||||
def reset(self, display):
|
def reset(self, display):
|
||||||
"""
|
"""
|
||||||
Reset the player
|
Reset the player
|
||||||
"""
|
"""
|
||||||
display.vlcMediaPlayer.stop()
|
display.vlc_media_player.stop()
|
||||||
display.vlcWidget.setVisible(False)
|
display.vlc_widget.setVisible(False)
|
||||||
self.state = MediaState.Off
|
self.state = MediaState.Off
|
||||||
|
|
||||||
def set_visible(self, display, status):
|
def set_visible(self, display, status):
|
||||||
@ -263,23 +263,23 @@ class VlcPlayer(MediaPlayer):
|
|||||||
Set the visibility
|
Set the visibility
|
||||||
"""
|
"""
|
||||||
if self.has_own_widget:
|
if self.has_own_widget:
|
||||||
display.vlcWidget.setVisible(status)
|
display.vlc_widget.setVisible(status)
|
||||||
|
|
||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
Update the UI
|
Update the UI
|
||||||
"""
|
"""
|
||||||
# Stop video if playback is finished.
|
# Stop video if playback is finished.
|
||||||
if display.vlcMedia.get_state() == vlc.State.Ended:
|
if display.vlc_media.get_state() == vlc.State.Ended:
|
||||||
self.stop(display)
|
self.stop(display)
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
if controller.media_info.end_time > 0:
|
if controller.media_info.end_time > 0:
|
||||||
if display.vlcMediaPlayer.get_time() > controller.media_info.end_time * 1000:
|
if display.vlc_media_player.get_time() > controller.media_info.end_time * 1000:
|
||||||
self.stop(display)
|
self.stop(display)
|
||||||
self.set_visible(display, False)
|
self.set_visible(display, False)
|
||||||
if not controller.seek_slider.isSliderDown():
|
if not controller.seek_slider.isSliderDown():
|
||||||
controller.seek_slider.blockSignals(True)
|
controller.seek_slider.blockSignals(True)
|
||||||
controller.seek_slider.setSliderPosition(display.vlcMediaPlayer.get_time())
|
controller.seek_slider.setSliderPosition(display.vlc_media_player.get_time())
|
||||||
controller.seek_slider.blockSignals(False)
|
controller.seek_slider.blockSignals(False)
|
||||||
|
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
|
@ -376,9 +376,9 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
else:
|
else:
|
||||||
is_visible = "hidden"
|
is_visible = "hidden"
|
||||||
if controller.media_info.is_flash:
|
if controller.media_info.is_flash:
|
||||||
display.frame.evaluateJavaScript('show_flash("setVisible", null, null, "%s");' % (is_visible))
|
display.frame.evaluateJavaScript('show_flash("setVisible", null, null, "%s");' % is_visible)
|
||||||
else:
|
else:
|
||||||
display.frame.evaluateJavaScript('show_video("setVisible", null, null, null, "%s");' % (is_visible))
|
display.frame.evaluateJavaScript('show_video("setVisible", null, null, null, "%s");' % is_visible)
|
||||||
|
|
||||||
def update_ui(self, display):
|
def update_ui(self, display):
|
||||||
"""
|
"""
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
# Copyright (c) 2008-2014 Raoul Snyman #
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||||
@ -30,7 +30,6 @@
|
|||||||
The service manager sets up, loads, saves and manages services.
|
The service manager sets up, loads, saves and manages services.
|
||||||
"""
|
"""
|
||||||
import html
|
import html
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
@ -38,11 +37,10 @@ import json
|
|||||||
from tempfile import mkstemp
|
from tempfile import mkstemp
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.common import Registry, AppLocation, Settings, ThemeLevel, check_directory_exists, UiStrings, translate
|
from openlp.core.common import Registry, AppLocation, Settings, ThemeLevel, OpenLPMixin, RegistryMixin, \
|
||||||
|
check_directory_exists, UiStrings, translate
|
||||||
from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
|
from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
|
||||||
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
|
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
|
||||||
@ -65,6 +63,7 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
"""
|
"""
|
||||||
Capture Key press and respond accordingly.
|
Capture Key press and respond accordingly.
|
||||||
|
:param event:
|
||||||
"""
|
"""
|
||||||
if isinstance(event, QtGui.QKeyEvent):
|
if isinstance(event, QtGui.QKeyEvent):
|
||||||
# here accept the event and do something
|
# here accept the event and do something
|
||||||
@ -75,7 +74,7 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||||||
self.service_manager.on_move_selection_down()
|
self.service_manager.on_move_selection_down()
|
||||||
event.accept()
|
event.accept()
|
||||||
elif event.key() == QtCore.Qt.Key_Delete:
|
elif event.key() == QtCore.Qt.Key_Delete:
|
||||||
self.service_manager.onDeleteFromService()
|
self.service_manager.on_delete_from_service()
|
||||||
event.accept()
|
event.accept()
|
||||||
event.ignore()
|
event.ignore()
|
||||||
else:
|
else:
|
||||||
@ -85,6 +84,7 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||||||
"""
|
"""
|
||||||
Drag and drop event does not care what data is selected as the recipient will use events to request the data
|
Drag and drop event does not care what data is selected as the recipient will use events to request the data
|
||||||
move just tell it what plugin to call
|
move just tell it what plugin to call
|
||||||
|
:param event:
|
||||||
"""
|
"""
|
||||||
if event.buttons() != QtCore.Qt.LeftButton:
|
if event.buttons() != QtCore.Qt.LeftButton:
|
||||||
event.ignore()
|
event.ignore()
|
||||||
@ -99,16 +99,21 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
|||||||
drag.start(QtCore.Qt.CopyAction)
|
drag.start(QtCore.Qt.CopyAction)
|
||||||
|
|
||||||
|
|
||||||
class ServiceManagerDialog(object):
|
class Ui_ServiceManager(object):
|
||||||
"""
|
"""
|
||||||
UI part of the Service Manager
|
UI part of the Service Manager
|
||||||
"""
|
"""
|
||||||
def setup_ui(self, widget):
|
def setup_ui(self, widget):
|
||||||
"""
|
"""
|
||||||
Define the UI
|
Define the UI
|
||||||
|
:param widget:
|
||||||
"""
|
"""
|
||||||
|
# start with the layout
|
||||||
|
self.layout = QtGui.QVBoxLayout(widget)
|
||||||
|
self.layout.setSpacing(0)
|
||||||
|
self.layout.setMargin(0)
|
||||||
# Create the top toolbar
|
# Create the top toolbar
|
||||||
self.toolbar = OpenLPToolbar(self)
|
self.toolbar = OpenLPToolbar(widget)
|
||||||
self.toolbar.add_toolbar_action('newService', text=UiStrings().NewService, icon=':/general/general_new.png',
|
self.toolbar.add_toolbar_action('newService', text=UiStrings().NewService, icon=':/general/general_new.png',
|
||||||
tooltip=UiStrings().CreateService, triggers=self.on_new_service_clicked)
|
tooltip=UiStrings().CreateService, triggers=self.on_new_service_clicked)
|
||||||
self.toolbar.add_toolbar_action('openService', text=UiStrings().OpenService,
|
self.toolbar.add_toolbar_action('openService', text=UiStrings().OpenService,
|
||||||
@ -120,7 +125,7 @@ class ServiceManagerDialog(object):
|
|||||||
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
|
||||||
triggers=self.decide_save_method)
|
triggers=self.decide_save_method)
|
||||||
self.toolbar.addSeparator()
|
self.toolbar.addSeparator()
|
||||||
self.theme_label = QtGui.QLabel('%s:' % UiStrings().Theme, self)
|
self.theme_label = QtGui.QLabel('%s:' % UiStrings().Theme, widget)
|
||||||
self.theme_label.setMargin(3)
|
self.theme_label.setMargin(3)
|
||||||
self.theme_label.setObjectName('theme_label')
|
self.theme_label.setObjectName('theme_label')
|
||||||
self.toolbar.add_toolbar_widget(self.theme_label)
|
self.toolbar.add_toolbar_widget(self.theme_label)
|
||||||
@ -133,7 +138,7 @@ class ServiceManagerDialog(object):
|
|||||||
self.toolbar.setObjectName('toolbar')
|
self.toolbar.setObjectName('toolbar')
|
||||||
self.layout.addWidget(self.toolbar)
|
self.layout.addWidget(self.toolbar)
|
||||||
# Create the service manager list
|
# Create the service manager list
|
||||||
self.service_manager_list = ServiceManagerList(self)
|
self.service_manager_list = ServiceManagerList(widget)
|
||||||
self.service_manager_list.setEditTriggers(
|
self.service_manager_list.setEditTriggers(
|
||||||
QtGui.QAbstractItemView.CurrentChanged |
|
QtGui.QAbstractItemView.CurrentChanged |
|
||||||
QtGui.QAbstractItemView.DoubleClicked |
|
QtGui.QAbstractItemView.DoubleClicked |
|
||||||
@ -151,51 +156,61 @@ class ServiceManagerDialog(object):
|
|||||||
self.service_manager_list.__class__.dropEvent = self.drop_event
|
self.service_manager_list.__class__.dropEvent = self.drop_event
|
||||||
self.layout.addWidget(self.service_manager_list)
|
self.layout.addWidget(self.service_manager_list)
|
||||||
# Add the bottom toolbar
|
# Add the bottom toolbar
|
||||||
self.order_toolbar = OpenLPToolbar(self)
|
self.order_toolbar = OpenLPToolbar(widget)
|
||||||
action_list = ActionList.get_instance()
|
action_list = ActionList.get_instance()
|
||||||
action_list.add_category(UiStrings().Service, CategoryOrder.standard_toolbar)
|
action_list.add_category(UiStrings().Service, CategoryOrder.standard_toolbar)
|
||||||
self.service_manager_list.move_top = self.order_toolbar.add_toolbar_action('moveTop',
|
self.service_manager_list.move_top = self.order_toolbar.add_toolbar_action(
|
||||||
|
'moveTop',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=':/services/service_top.png',
|
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=':/services/service_top.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Move item to the top of the service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Move item to the top of the service.'),
|
||||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceTop)
|
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_top)
|
||||||
self.service_manager_list.move_up = self.order_toolbar.add_toolbar_action('moveUp',
|
self.service_manager_list.move_up = self.order_toolbar.add_toolbar_action(
|
||||||
|
'moveUp',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=':/services/service_up.png',
|
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=':/services/service_up.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'),
|
||||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceUp)
|
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_up)
|
||||||
self.service_manager_list.move_down = self.order_toolbar.add_toolbar_action('moveDown',
|
self.service_manager_list.move_down = self.order_toolbar.add_toolbar_action(
|
||||||
|
'moveDown',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=':/services/service_down.png',
|
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=':/services/service_down.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'),
|
||||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceDown)
|
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_down)
|
||||||
self.service_manager_list.move_bottom = self.order_toolbar.add_toolbar_action('moveBottom',
|
self.service_manager_list.move_bottom = self.order_toolbar.add_toolbar_action(
|
||||||
|
'moveBottom',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=':/services/service_bottom.png',
|
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=':/services/service_bottom.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'),
|
||||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceEnd)
|
can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_end)
|
||||||
self.service_manager_list.down = self.order_toolbar.add_toolbar_action('down',
|
self.service_manager_list.down = self.order_toolbar.add_toolbar_action(
|
||||||
|
'down',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move &down'), can_shortcuts=True,
|
text=translate('OpenLP.ServiceManager', 'Move &down'), can_shortcuts=True,
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection down the window.'), visible=False,
|
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection down the window.'), visible=False,
|
||||||
triggers=self.on_move_selection_down)
|
triggers=self.on_move_selection_down)
|
||||||
action_list.add_action(self.service_manager_list.down)
|
action_list.add_action(self.service_manager_list.down)
|
||||||
self.service_manager_list.up = self.order_toolbar.add_toolbar_action('up',
|
self.service_manager_list.up = self.order_toolbar.add_toolbar_action(
|
||||||
|
'up',
|
||||||
text=translate('OpenLP.ServiceManager', 'Move up'), can_shortcuts=True,
|
text=translate('OpenLP.ServiceManager', 'Move up'), can_shortcuts=True,
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection up the window.'), visible=False,
|
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection up the window.'), visible=False,
|
||||||
triggers=self.on_move_selection_up)
|
triggers=self.on_move_selection_up)
|
||||||
action_list.add_action(self.service_manager_list.up)
|
action_list.add_action(self.service_manager_list.up)
|
||||||
self.order_toolbar.addSeparator()
|
self.order_toolbar.addSeparator()
|
||||||
self.service_manager_list.delete = self.order_toolbar.add_toolbar_action('delete', can_shortcuts=True,
|
self.service_manager_list.delete = self.order_toolbar.add_toolbar_action(
|
||||||
|
'delete', can_shortcuts=True,
|
||||||
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=':/general/general_delete.png',
|
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=':/general/general_delete.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'),
|
||||||
triggers=self.onDeleteFromService)
|
triggers=self.on_delete_from_service)
|
||||||
self.order_toolbar.addSeparator()
|
self.order_toolbar.addSeparator()
|
||||||
self.service_manager_list.expand = self.order_toolbar.add_toolbar_action('expand', can_shortcuts=True,
|
self.service_manager_list.expand = self.order_toolbar.add_toolbar_action(
|
||||||
|
'expand', can_shortcuts=True,
|
||||||
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=':/services/service_expand_all.png',
|
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=':/services/service_expand_all.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
|
||||||
category=UiStrings().Service, triggers=self.on_expand_all)
|
category=UiStrings().Service, triggers=self.on_expand_all)
|
||||||
self.service_manager_list.collapse = self.order_toolbar.add_toolbar_action('collapse', can_shortcuts=True,
|
self.service_manager_list.collapse = self.order_toolbar.add_toolbar_action(
|
||||||
|
'collapse', can_shortcuts=True,
|
||||||
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=':/services/service_collapse_all.png',
|
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=':/services/service_collapse_all.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'),
|
||||||
category=UiStrings().Service, triggers=self.on_collapse_all)
|
category=UiStrings().Service, triggers=self.on_collapse_all)
|
||||||
self.order_toolbar.addSeparator()
|
self.order_toolbar.addSeparator()
|
||||||
self.service_manager_list.make_live = self.order_toolbar.add_toolbar_action('make_live', can_shortcuts=True,
|
self.service_manager_list.make_live = self.order_toolbar.add_toolbar_action(
|
||||||
|
'make_live', can_shortcuts=True,
|
||||||
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=':/general/general_live.png',
|
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=':/general/general_live.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
|
||||||
category=UiStrings().Service,
|
category=UiStrings().Service,
|
||||||
@ -286,13 +301,12 @@ class ServiceManagerDialog(object):
|
|||||||
"""
|
"""
|
||||||
Accept Drag events
|
Accept Drag events
|
||||||
|
|
||||||
``event``
|
:param event: Handle of the event passed
|
||||||
Handle of the event pint passed
|
|
||||||
"""
|
"""
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManager):
|
||||||
"""
|
"""
|
||||||
Manages the services. This involves taking text strings from plugins and adding them to the service. This service
|
Manages the services. This involves taking text strings from plugins and adding them to the service. This service
|
||||||
can then be zipped up with all the resources used into one OSZ or oszl file for use on any OpenLP v2 installation.
|
can then be zipped up with all the resources used into one OSZ or oszl file for use on any OpenLP v2 installation.
|
||||||
@ -305,7 +319,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
super(ServiceManager, self).__init__(parent)
|
super(ServiceManager, self).__init__(parent)
|
||||||
self.active = build_icon(':/media/auto-start_active.png')
|
self.active = build_icon(':/media/auto-start_active.png')
|
||||||
self.inactive = build_icon(':/media/auto-start_inactive.png')
|
self.inactive = build_icon(':/media/auto-start_inactive.png')
|
||||||
Registry().register('service_manager', self)
|
|
||||||
self.service_items = []
|
self.service_items = []
|
||||||
self.suffixes = []
|
self.suffixes = []
|
||||||
self.drop_position = 0
|
self.drop_position = 0
|
||||||
@ -314,20 +327,28 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self._modified = False
|
self._modified = False
|
||||||
self._file_name = ''
|
self._file_name = ''
|
||||||
self.service_has_all_original_files = True
|
self.service_has_all_original_files = True
|
||||||
self.service_note_form = ServiceNoteForm()
|
|
||||||
self.service_item_edit_form = ServiceItemEditForm()
|
def bootstrap_initialise(self):
|
||||||
self.start_time_form = StartTimeForm()
|
"""
|
||||||
# start with the layout
|
To be called as part of initialisation
|
||||||
self.layout = QtGui.QVBoxLayout(self)
|
"""
|
||||||
self.layout.setSpacing(0)
|
|
||||||
self.layout.setMargin(0)
|
|
||||||
self.setup_ui(self)
|
self.setup_ui(self)
|
||||||
# Need to use event as called across threads and UI is updated
|
# Need to use event as called across threads and UI is updated
|
||||||
QtCore.QObject.connect(self, QtCore.SIGNAL('servicemanager_set_item'), self.on_set_item)
|
QtCore.QObject.connect(self, QtCore.SIGNAL('servicemanager_set_item'), self.on_set_item)
|
||||||
|
|
||||||
|
def bootstrap_post_set_up(self):
|
||||||
|
"""
|
||||||
|
Can be set up as a late setup
|
||||||
|
"""
|
||||||
|
self.service_note_form = ServiceNoteForm()
|
||||||
|
self.service_item_edit_form = ServiceItemEditForm()
|
||||||
|
self.start_time_form = StartTimeForm()
|
||||||
|
|
||||||
def set_modified(self, modified=True):
|
def set_modified(self, modified=True):
|
||||||
"""
|
"""
|
||||||
Setter for property "modified". Sets whether or not the current service has been modified.
|
Setter for property "modified". Sets whether or not the current service has been modified.
|
||||||
|
|
||||||
|
:param modified: Indicates if the service has new or removed items. Used to trigger a remote update.
|
||||||
"""
|
"""
|
||||||
if modified:
|
if modified:
|
||||||
self.service_id += 1
|
self.service_id += 1
|
||||||
@ -344,6 +365,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def set_file_name(self, file_name):
|
def set_file_name(self, file_name):
|
||||||
"""
|
"""
|
||||||
Setter for service file.
|
Setter for service file.
|
||||||
|
|
||||||
|
:param file_name: The service file name
|
||||||
"""
|
"""
|
||||||
self._file_name = str(file_name)
|
self._file_name = str(file_name)
|
||||||
self.main_window.set_service_modified(self.is_modified(), self.short_file_name())
|
self.main_window.set_service_modified(self.is_modified(), self.short_file_name())
|
||||||
@ -369,19 +392,20 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
self.suffixes = []
|
self.suffixes = []
|
||||||
|
|
||||||
def supported_suffixes(self, suffix):
|
def supported_suffixes(self, suffix_list):
|
||||||
"""
|
"""
|
||||||
Adds Suffixes supported to the master list. Called from Plugins.
|
Adds Suffixes supported to the master list. Called from Plugins.
|
||||||
|
|
||||||
``suffix``
|
:param suffix_list: New Suffix's to be supported
|
||||||
New Suffix to be supported
|
|
||||||
"""
|
"""
|
||||||
|
for suffix in suffix_list:
|
||||||
if not suffix in self.suffixes:
|
if not suffix in self.suffixes:
|
||||||
self.suffixes.append(suffix)
|
self.suffixes.append(suffix)
|
||||||
|
|
||||||
def on_new_service_clicked(self):
|
def on_new_service_clicked(self, field=None):
|
||||||
"""
|
"""
|
||||||
Create a new service.
|
Create a new service.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
if self.is_modified():
|
if self.is_modified():
|
||||||
result = self.save_modified_service()
|
result = self.save_modified_service()
|
||||||
@ -396,8 +420,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Loads the service file and saves the existing one it there is one unchanged.
|
Loads the service file and saves the existing one it there is one unchanged.
|
||||||
|
|
||||||
``load_file``
|
:param load_file: The service file to the loaded. Will be None is from menu so selection will be required.
|
||||||
The service file to the loaded. Will be None is from menu so selection will be required.
|
|
||||||
"""
|
"""
|
||||||
if self.is_modified():
|
if self.is_modified():
|
||||||
result = self.save_modified_service()
|
result = self.save_modified_service()
|
||||||
@ -432,9 +455,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard |
|
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard |
|
||||||
QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save)
|
QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save)
|
||||||
|
|
||||||
def on_recent_service_clicked(self):
|
def on_recent_service_clicked(self, field=None):
|
||||||
"""
|
"""
|
||||||
Load a recent file as the service triggered by mainwindow recent service list.
|
Load a recent file as the service triggered by mainwindow recent service list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
sender = self.sender()
|
sender = self.sender()
|
||||||
self.load_file(sender.data())
|
self.load_file(sender.data())
|
||||||
@ -451,6 +475,19 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
Settings().setValue('servicemanager/last file', '')
|
Settings().setValue('servicemanager/last file', '')
|
||||||
self.plugin_manager.new_service_created()
|
self.plugin_manager.new_service_created()
|
||||||
|
|
||||||
|
def create_basic_service(self):
|
||||||
|
"""
|
||||||
|
Create the initial service array with the base items to be saved.
|
||||||
|
|
||||||
|
:return service array
|
||||||
|
"""
|
||||||
|
service = []
|
||||||
|
core = {'lite-service': self._save_lite,
|
||||||
|
'service-theme': self.service_theme
|
||||||
|
}
|
||||||
|
service.append({'openlp_core': core})
|
||||||
|
return service
|
||||||
|
|
||||||
def save_file(self):
|
def save_file(self):
|
||||||
"""
|
"""
|
||||||
Save the current service file.
|
Save the current service file.
|
||||||
@ -464,14 +501,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
temp_file, temp_file_name = mkstemp('.osz', 'openlp_')
|
temp_file, temp_file_name = mkstemp('.osz', 'openlp_')
|
||||||
# We don't need the file handle.
|
# We don't need the file handle.
|
||||||
os.close(temp_file)
|
os.close(temp_file)
|
||||||
log.debug(temp_file_name)
|
self.log_debug(temp_file_name)
|
||||||
path_file_name = str(self.file_name())
|
path_file_name = str(self.file_name())
|
||||||
path, file_name = os.path.split(path_file_name)
|
path, file_name = os.path.split(path_file_name)
|
||||||
base_name = os.path.splitext(file_name)[0]
|
base_name = os.path.splitext(file_name)[0]
|
||||||
service_file_name = '%s.osj' % base_name
|
service_file_name = '%s.osj' % base_name
|
||||||
log.debug('ServiceManager.save_file - %s', path_file_name)
|
self.log_debug('ServiceManager.save_file - %s' % path_file_name)
|
||||||
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
|
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
|
||||||
service = []
|
service = self.create_basic_service()
|
||||||
write_list = []
|
write_list = []
|
||||||
missing_list = []
|
missing_list = []
|
||||||
audio_files = []
|
audio_files = []
|
||||||
@ -522,11 +559,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
for file_item in write_list:
|
for file_item in write_list:
|
||||||
file_size = os.path.getsize(file_item)
|
file_size = os.path.getsize(file_item)
|
||||||
total_size += file_size
|
total_size += file_size
|
||||||
log.debug('ServiceManager.save_file - ZIP contents size is %i bytes' % total_size)
|
self.log_debug('ServiceManager.save_file - ZIP contents size is %i bytes' % total_size)
|
||||||
service_content = json.dumps(service)
|
service_content = json.dumps(service)
|
||||||
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX.
|
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX.
|
||||||
allow_zip_64 = (total_size > 2147483648 + len(service_content))
|
allow_zip_64 = (total_size > 2147483648 + len(service_content))
|
||||||
log.debug('ServiceManager.save_file - allowZip64 is %s' % allow_zip_64)
|
self.log_debug('ServiceManager.save_file - allowZip64 is %s' % allow_zip_64)
|
||||||
zip_file = None
|
zip_file = None
|
||||||
success = True
|
success = True
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
@ -549,7 +586,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
shutil.copy(audio_from, save_file)
|
shutil.copy(audio_from, save_file)
|
||||||
zip_file.write(audio_from, audio_to)
|
zip_file.write(audio_from, audio_to)
|
||||||
except IOError:
|
except IOError:
|
||||||
log.exception('Failed to save service to disk: %s', temp_file_name)
|
self.log_exception('Failed to save service to disk: %s' % temp_file_name)
|
||||||
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
|
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
|
||||||
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
|
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
|
||||||
success = False
|
success = False
|
||||||
@ -578,14 +615,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
temp_file, temp_file_name = mkstemp('.oszl', 'openlp_')
|
temp_file, temp_file_name = mkstemp('.oszl', 'openlp_')
|
||||||
# We don't need the file handle.
|
# We don't need the file handle.
|
||||||
os.close(temp_file)
|
os.close(temp_file)
|
||||||
log.debug(temp_file_name)
|
self.log_debug(temp_file_name)
|
||||||
path_file_name = str(self.file_name())
|
path_file_name = str(self.file_name())
|
||||||
path, file_name = os.path.split(path_file_name)
|
path, file_name = os.path.split(path_file_name)
|
||||||
base_name = os.path.splitext(file_name)[0]
|
base_name = os.path.splitext(file_name)[0]
|
||||||
service_file_name = '%s.osj' % base_name
|
service_file_name = '%s.osj' % base_name
|
||||||
log.debug('ServiceManager.save_file - %s', path_file_name)
|
self.log_debug('ServiceManager.save_file - %s' % path_file_name)
|
||||||
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
|
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
|
||||||
service = []
|
service = self.create_basic_service()
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
# Number of items + 1 to zip it
|
# Number of items + 1 to zip it
|
||||||
self.main_window.display_progress_bar(len(self.service_items) + 1)
|
self.main_window.display_progress_bar(len(self.service_items) + 1)
|
||||||
@ -604,7 +641,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
# First we add service contents.
|
# First we add service contents.
|
||||||
zip_file.writestr(service_file_name, service_content)
|
zip_file.writestr(service_file_name, service_content)
|
||||||
except IOError:
|
except IOError:
|
||||||
log.exception('Failed to save service to disk: %s', temp_file_name)
|
self.log_exception('Failed to save service to disk: %s', temp_file_name)
|
||||||
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
|
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
|
||||||
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
|
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
|
||||||
success = False
|
success = False
|
||||||
@ -623,7 +660,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
delete_file(temp_file_name)
|
delete_file(temp_file_name)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def save_file_as(self):
|
def save_file_as(self, field=None):
|
||||||
"""
|
"""
|
||||||
Get a file name and then call :func:`ServiceManager.save_file` to save the file.
|
Get a file name and then call :func:`ServiceManager.save_file` to save the file.
|
||||||
"""
|
"""
|
||||||
@ -656,8 +693,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
'(*.oszl)'))
|
'(*.oszl)'))
|
||||||
else:
|
else:
|
||||||
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
|
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
|
||||||
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*'
|
translate('OpenLP.ServiceManager',
|
||||||
'.osz);;'))
|
'OpenLP Service Files (*.osz);;'))
|
||||||
if not file_name:
|
if not file_name:
|
||||||
return False
|
return False
|
||||||
if os.path.splitext(file_name)[1] == '':
|
if os.path.splitext(file_name)[1] == '':
|
||||||
@ -668,9 +705,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.set_file_name(file_name)
|
self.set_file_name(file_name)
|
||||||
self.decide_save_method()
|
self.decide_save_method()
|
||||||
|
|
||||||
def decide_save_method(self):
|
def decide_save_method(self, field=None):
|
||||||
"""
|
"""
|
||||||
Determine which type of save method to use.
|
Determine which type of save method to use.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
if not self.file_name():
|
if not self.file_name():
|
||||||
return self.save_file_as()
|
return self.save_file_as()
|
||||||
@ -682,6 +720,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def load_file(self, file_name):
|
def load_file(self, file_name):
|
||||||
"""
|
"""
|
||||||
Load an existing service file
|
Load an existing service file
|
||||||
|
:param file_name:
|
||||||
"""
|
"""
|
||||||
if not file_name:
|
if not file_name:
|
||||||
return False
|
return False
|
||||||
@ -697,14 +736,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
try:
|
try:
|
||||||
ucs_file = zip_info.filename
|
ucs_file = zip_info.filename
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
log.exception('file_name "%s" is not valid UTF-8' % zip_info.file_name)
|
self.log_exception('file_name "%s" is not valid UTF-8' % zip_info.file_name)
|
||||||
critical_error_message_box(message=translate('OpenLP.ServiceManager',
|
critical_error_message_box(message=translate('OpenLP.ServiceManager',
|
||||||
'File is not a valid service.\n The content encoding is not UTF-8.'))
|
'File is not a valid service.\n The content encoding is not UTF-8.'))
|
||||||
continue
|
continue
|
||||||
os_file = ucs_file.replace('/', os.path.sep)
|
os_file = ucs_file.replace('/', os.path.sep)
|
||||||
if not os_file.startswith('audio'):
|
if not os_file.startswith('audio'):
|
||||||
os_file = os.path.split(os_file)[1]
|
os_file = os.path.split(os_file)[1]
|
||||||
log.debug('Extract file: %s', os_file)
|
self.log_debug('Extract file: %s' % os_file)
|
||||||
zip_info.filename = os_file
|
zip_info.filename = os_file
|
||||||
zip_file.extract(zip_info, self.service_path)
|
zip_file.extract(zip_info, self.service_path)
|
||||||
if os_file.endswith('osj') or os_file.endswith('osd'):
|
if os_file.endswith('osj') or os_file.endswith('osd'):
|
||||||
@ -722,38 +761,26 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.new_file()
|
self.new_file()
|
||||||
self.set_file_name(file_name)
|
self.set_file_name(file_name)
|
||||||
self.main_window.display_progress_bar(len(items))
|
self.main_window.display_progress_bar(len(items))
|
||||||
for item in items:
|
self.process_service_items(items)
|
||||||
self.main_window.increment_progress_bar()
|
|
||||||
service_item = ServiceItem()
|
|
||||||
if self._save_lite:
|
|
||||||
service_item.set_from_service(item)
|
|
||||||
else:
|
|
||||||
service_item.set_from_service(item, self.service_path)
|
|
||||||
service_item.validate_item(self.suffixes)
|
|
||||||
if service_item.is_capable(ItemCapabilities.OnLoadUpdate):
|
|
||||||
new_item = Registry().get(service_item.name).service_load(service_item)
|
|
||||||
if new_item:
|
|
||||||
service_item = new_item
|
|
||||||
self.add_service_item(service_item, repaint=False)
|
|
||||||
delete_file(p_file)
|
delete_file(p_file)
|
||||||
self.main_window.add_recent_file(file_name)
|
self.main_window.add_recent_file(file_name)
|
||||||
self.set_modified(False)
|
self.set_modified(False)
|
||||||
Settings().setValue('servicemanager/last file', file_name)
|
Settings().setValue('servicemanager/last file', file_name)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
|
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
|
||||||
log.error('File contains no service data')
|
self.log_error('File contains no service data')
|
||||||
except (IOError, NameError, zipfile.BadZipfile):
|
except (IOError, NameError, zipfile.BadZipfile):
|
||||||
log.exception('Problem loading service file %s' % file_name)
|
self.log_exception('Problem loading service file %s' % file_name)
|
||||||
critical_error_message_box(message=translate('OpenLP.ServiceManager',
|
critical_error_message_box(message=translate('OpenLP.ServiceManager',
|
||||||
'File could not be opened because it is corrupt.'))
|
'File could not be opened because it is corrupt.'))
|
||||||
except zipfile.BadZipfile:
|
except zipfile.BadZipfile:
|
||||||
if os.path.getsize(file_name) == 0:
|
if os.path.getsize(file_name) == 0:
|
||||||
log.exception('Service file is zero sized: %s' % file_name)
|
self.log_exception('Service file is zero sized: %s' % file_name)
|
||||||
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
|
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
|
||||||
translate('OpenLP.ServiceManager', 'This service file does not contain '
|
translate('OpenLP.ServiceManager', 'This service file does not contain '
|
||||||
'any data.'))
|
'any data.'))
|
||||||
else:
|
else:
|
||||||
log.exception('Service file is cannot be extracted as zip: %s' % file_name)
|
self.log_exception('Service file is cannot be extracted as zip: %s' % file_name)
|
||||||
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
|
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
|
||||||
translate('OpenLP.ServiceManager',
|
translate('OpenLP.ServiceManager',
|
||||||
'This file is either corrupt or it is not an OpenLP 2 service file.'))
|
'This file is either corrupt or it is not an OpenLP 2 service file.'))
|
||||||
@ -768,6 +795,34 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
self.repaint_service_list(-1, -1)
|
self.repaint_service_list(-1, -1)
|
||||||
|
|
||||||
|
def process_service_items(self, service_items):
|
||||||
|
"""
|
||||||
|
Process all the array of service items loaded from the saved service
|
||||||
|
|
||||||
|
:param service_items: list of service_items
|
||||||
|
"""
|
||||||
|
for item in service_items:
|
||||||
|
self.main_window.increment_progress_bar()
|
||||||
|
service_item = ServiceItem()
|
||||||
|
if 'openlp_core' in item:
|
||||||
|
item = item.get('openlp_core')
|
||||||
|
theme = item.get('service-theme', None)
|
||||||
|
if theme:
|
||||||
|
find_and_set_in_combo_box(self.theme_combo_box, theme, set_missing=False)
|
||||||
|
if theme == self.theme_combo_box.currentText():
|
||||||
|
self.renderer.set_service_theme(theme)
|
||||||
|
else:
|
||||||
|
if self._save_lite:
|
||||||
|
service_item.set_from_service(item)
|
||||||
|
else:
|
||||||
|
service_item.set_from_service(item, self.service_path)
|
||||||
|
service_item.validate_item(self.suffixes)
|
||||||
|
if service_item.is_capable(ItemCapabilities.OnLoadUpdate):
|
||||||
|
new_item = Registry().get(service_item.name).service_load(service_item)
|
||||||
|
if new_item:
|
||||||
|
service_item = new_item
|
||||||
|
self.add_service_item(service_item, repaint=False)
|
||||||
|
|
||||||
def load_last_file(self):
|
def load_last_file(self):
|
||||||
"""
|
"""
|
||||||
Load the last service item from the service manager when the service was last closed. Can be blank if there was
|
Load the last service item from the service manager when the service was last closed. Can be blank if there was
|
||||||
@ -780,6 +835,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def context_menu(self, point):
|
def context_menu(self, point):
|
||||||
"""
|
"""
|
||||||
The Right click context menu from the Serviceitem list
|
The Right click context menu from the Serviceitem list
|
||||||
|
|
||||||
|
:param point: The location of the cursor.
|
||||||
"""
|
"""
|
||||||
item = self.service_manager_list.itemAt(point)
|
item = self.service_manager_list.itemAt(point)
|
||||||
if item is None:
|
if item is None:
|
||||||
@ -843,9 +900,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
theme_action.setChecked(True)
|
theme_action.setChecked(True)
|
||||||
self.menu.exec_(self.service_manager_list.mapToGlobal(point))
|
self.menu.exec_(self.service_manager_list.mapToGlobal(point))
|
||||||
|
|
||||||
def on_service_item_note_form(self):
|
def on_service_item_note_form(self, field=None):
|
||||||
"""
|
"""
|
||||||
Allow the service note to be edited
|
Allow the service note to be edited
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
self.service_note_form.text_edit.setPlainText(self.service_items[item]['service_item'].notes)
|
self.service_note_form.text_edit.setPlainText(self.service_items[item]['service_item'].notes)
|
||||||
@ -854,18 +912,21 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(item, -1)
|
self.repaint_service_list(item, -1)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def on_start_time_form(self):
|
def on_start_time_form(self, field=None):
|
||||||
"""
|
"""
|
||||||
Opens a dialog to type in service item notes.
|
Opens a dialog to type in service item notes.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
self.start_time_form.item = self.service_items[item]
|
self.start_time_form.item = self.service_items[item]
|
||||||
if self.start_time_form.exec_():
|
if self.start_time_form.exec_():
|
||||||
self.repaint_service_list(item, -1)
|
self.repaint_service_list(item, -1)
|
||||||
|
|
||||||
def toggle_auto_play_slides_once(self):
|
def toggle_auto_play_slides_once(self, field=None):
|
||||||
"""
|
"""
|
||||||
Toggle Auto play slide once. Inverts auto play once option for the item
|
Toggle Auto play slide once. Inverts auto play once option for the item
|
||||||
|
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
service_item = self.service_items[item]['service_item']
|
service_item = self.service_items[item]['service_item']
|
||||||
@ -878,9 +939,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.main_window.general_settings_section + '/loop delay')
|
self.main_window.general_settings_section + '/loop delay')
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def toggle_auto_play_slides_loop(self):
|
def toggle_auto_play_slides_loop(self, field=None):
|
||||||
"""
|
"""
|
||||||
Toggle Auto play slide loop.
|
Toggle Auto play slide loop.
|
||||||
|
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
service_item = self.service_items[item]['service_item']
|
service_item = self.service_items[item]['service_item']
|
||||||
@ -893,9 +956,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.main_window.general_settings_section + '/loop delay')
|
self.main_window.general_settings_section + '/loop delay')
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def on_timed_slide_interval(self):
|
def on_timed_slide_interval(self, field=None):
|
||||||
"""
|
"""
|
||||||
Shows input dialog for enter interval in seconds for delay
|
Shows input dialog for enter interval in seconds for delay
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
service_item = self.service_items[item]['service_item']
|
service_item = self.service_items[item]['service_item']
|
||||||
@ -926,9 +990,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.service_items[item]['service_item'].will_auto_start = \
|
self.service_items[item]['service_item'].will_auto_start = \
|
||||||
not self.service_items[item]['service_item'].will_auto_start
|
not self.service_items[item]['service_item'].will_auto_start
|
||||||
|
|
||||||
def on_service_item_edit_form(self):
|
def on_service_item_edit_form(self, field=None):
|
||||||
"""
|
"""
|
||||||
Opens a dialog to edit the service item and update the service display if changes are saved.
|
Opens a dialog to edit the service item and update the service display if changes are saved.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
self.service_item_edit_form.set_service_item(self.service_items[item]['service_item'])
|
self.service_item_edit_form.set_service_item(self.service_items[item]['service_item'])
|
||||||
@ -941,11 +1006,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
Called by the SlideController to request a preview item be made live and allows the next preview to be updated
|
Called by the SlideController to request a preview item be made live and allows the next preview to be updated
|
||||||
if relevant.
|
if relevant.
|
||||||
|
|
||||||
``unique_identifier``
|
:param unique_identifier: Reference to the service_item
|
||||||
Reference to the service_item
|
:param row: individual row number
|
||||||
|
|
||||||
``row``
|
|
||||||
individual row number
|
|
||||||
"""
|
"""
|
||||||
for sitem in self.service_items:
|
for sitem in self.service_items:
|
||||||
if sitem['service_item'].unique_identifier == unique_identifier:
|
if sitem['service_item'].unique_identifier == unique_identifier:
|
||||||
@ -958,9 +1020,9 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Called by the SlideController to select the next service item.
|
Called by the SlideController to select the next service item.
|
||||||
"""
|
"""
|
||||||
if not self.service_manager_list.selected_items():
|
if not self.service_manager_list.selectedItems():
|
||||||
return
|
return
|
||||||
selected = self.service_manager_list.selected_items()[0]
|
selected = self.service_manager_list.selectedItems()[0]
|
||||||
look_for = 0
|
look_for = 0
|
||||||
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
|
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
|
||||||
while service_iterator.value():
|
while service_iterator.value():
|
||||||
@ -976,13 +1038,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Called by the SlideController to select the previous service item.
|
Called by the SlideController to select the previous service item.
|
||||||
|
|
||||||
``last_slide``
|
:param last_slide: Is this the last slide in the service_item.
|
||||||
Is this the last slide in the service_item
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self.service_manager_list.selected_items():
|
if not self.service_manager_list.selectedItems():
|
||||||
return
|
return
|
||||||
selected = self.service_manager_list.selected_items()[0]
|
selected = self.service_manager_list.selectedItems()[0]
|
||||||
prev_item = None
|
prev_item = None
|
||||||
prev_item_last_slide = None
|
prev_item_last_slide = None
|
||||||
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
|
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
|
||||||
@ -1006,17 +1066,22 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
prev_item_last_slide = service_iterator.value()
|
prev_item_last_slide = service_iterator.value()
|
||||||
service_iterator += 1
|
service_iterator += 1
|
||||||
|
|
||||||
def on_set_item(self, message):
|
def on_set_item(self, message, field=None):
|
||||||
"""
|
"""
|
||||||
Called by a signal to select a specific item and make it live usually from remote.
|
Called by a signal to select a specific item and make it live usually from remote.
|
||||||
|
|
||||||
|
:param field:
|
||||||
|
:param message: The data passed in from a remove message
|
||||||
"""
|
"""
|
||||||
self.set_item(int(message))
|
self.set_item(int(message))
|
||||||
|
|
||||||
def set_item(self, index):
|
def set_item(self, index):
|
||||||
"""
|
"""
|
||||||
Makes a specific item in the service live.
|
Makes a specific item in the service live.
|
||||||
|
|
||||||
|
:param index: The index of the service item list to be actioned.
|
||||||
"""
|
"""
|
||||||
if index >= 0 and index < self.service_manager_list.topLevelItemCount():
|
if 0 >= index < self.service_manager_list.topLevelItemCount():
|
||||||
item = self.service_manager_list.topLevelItem(index)
|
item = self.service_manager_list.topLevelItem(index)
|
||||||
self.service_manager_list.setCurrentItem(item)
|
self.service_manager_list.setCurrentItem(item)
|
||||||
self.make_live()
|
self.make_live()
|
||||||
@ -1041,9 +1106,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
return
|
return
|
||||||
self.service_manager_list.setCurrentItem(item_after)
|
self.service_manager_list.setCurrentItem(item_after)
|
||||||
|
|
||||||
def on_collapse_all(self):
|
def on_collapse_all(self, field=None):
|
||||||
"""
|
"""
|
||||||
Collapse all the service items.
|
Collapse all the service items.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
for item in self.service_items:
|
for item in self.service_items:
|
||||||
item['expanded'] = False
|
item['expanded'] = False
|
||||||
@ -1052,13 +1118,16 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def collapsed(self, item):
|
def collapsed(self, item):
|
||||||
"""
|
"""
|
||||||
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
||||||
|
|
||||||
|
:param item: The service item to be checked
|
||||||
"""
|
"""
|
||||||
pos = item.data(0, QtCore.Qt.UserRole)
|
pos = item.data(0, QtCore.Qt.UserRole)
|
||||||
self.service_items[pos - 1]['expanded'] = False
|
self.service_items[pos - 1]['expanded'] = False
|
||||||
|
|
||||||
def on_expand_all(self):
|
def on_expand_all(self, field=None):
|
||||||
"""
|
"""
|
||||||
Collapse all the service items.
|
Collapse all the service items.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
for item in self.service_items:
|
for item in self.service_items:
|
||||||
item['expanded'] = True
|
item['expanded'] = True
|
||||||
@ -1067,13 +1136,16 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def expanded(self, item):
|
def expanded(self, item):
|
||||||
"""
|
"""
|
||||||
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
Record if an item is collapsed. Used when repainting the list to get the correct state.
|
||||||
|
|
||||||
|
:param item: The service item to be checked
|
||||||
"""
|
"""
|
||||||
pos = item.data(0, QtCore.Qt.UserRole)
|
pos = item.data(0, QtCore.Qt.UserRole)
|
||||||
self.service_items[pos - 1]['expanded'] = True
|
self.service_items[pos - 1]['expanded'] = True
|
||||||
|
|
||||||
def onServiceTop(self):
|
def on_service_top(self, field=None):
|
||||||
"""
|
"""
|
||||||
Move the current ServiceItem to the top of the list.
|
Move the current ServiceItem to the top of the list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
if item < len(self.service_items) and item != -1:
|
if item < len(self.service_items) and item != -1:
|
||||||
@ -1083,9 +1155,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(0, child)
|
self.repaint_service_list(0, child)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def onServiceUp(self):
|
def on_service_up(self, field=None):
|
||||||
"""
|
"""
|
||||||
Move the current ServiceItem one position up in the list.
|
Move the current ServiceItem one position up in the list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
if item > 0:
|
if item > 0:
|
||||||
@ -1095,9 +1168,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(item - 1, child)
|
self.repaint_service_list(item - 1, child)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def onServiceDown(self):
|
def on_service_down(self, field=None):
|
||||||
"""
|
"""
|
||||||
Move the current ServiceItem one position down in the list.
|
Move the current ServiceItem one position down in the list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
if item < len(self.service_items) and item != -1:
|
if item < len(self.service_items) and item != -1:
|
||||||
@ -1107,9 +1181,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(item + 1, child)
|
self.repaint_service_list(item + 1, child)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def onServiceEnd(self):
|
def on_service_end(self, field=None):
|
||||||
"""
|
"""
|
||||||
Move the current ServiceItem to the bottom of the list.
|
Move the current ServiceItem to the bottom of the list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
if item < len(self.service_items) and item != -1:
|
if item < len(self.service_items) and item != -1:
|
||||||
@ -1119,9 +1194,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(len(self.service_items) - 1, child)
|
self.repaint_service_list(len(self.service_items) - 1, child)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def onDeleteFromService(self):
|
def on_delete_from_service(self, field=None):
|
||||||
"""
|
"""
|
||||||
Remove the current ServiceItem from the list.
|
Remove the current ServiceItem from the list.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
if item != -1:
|
if item != -1:
|
||||||
@ -1134,11 +1210,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
Clear the existing service list and prepaint all the items. This is used when moving items as the move takes
|
Clear the existing service list and prepaint all the items. This is used when moving items as the move takes
|
||||||
place in a supporting list, and when regenerating all the items due to theme changes.
|
place in a supporting list, and when regenerating all the items due to theme changes.
|
||||||
|
|
||||||
``service_item``
|
:param service_item: The item which changed. (int)
|
||||||
The item which changed. (int)
|
:param service_item_child: The child of the ``service_item``, which will be selected. (int)
|
||||||
|
|
||||||
``service_item_child``
|
|
||||||
The child of the ``service_item``, which will be selected. (int)
|
|
||||||
"""
|
"""
|
||||||
# Correct order of items in array
|
# Correct order of items in array
|
||||||
count = 1
|
count = 1
|
||||||
@ -1218,18 +1291,18 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Empties the service_path of temporary files on system exit.
|
Empties the service_path of temporary files on system exit.
|
||||||
"""
|
"""
|
||||||
log.debug('Cleaning up service_path')
|
|
||||||
for file_name in os.listdir(self.service_path):
|
for file_name in os.listdir(self.service_path):
|
||||||
file_path = os.path.join(self.service_path, file_name)
|
file_path = os.path.join(self.service_path, file_name)
|
||||||
delete_file(file_path)
|
delete_file(file_path)
|
||||||
if os.path.exists(os.path.join(self.service_path, 'audio')):
|
if os.path.exists(os.path.join(self.service_path, 'audio')):
|
||||||
shutil.rmtree(os.path.join(self.service_path, 'audio'), True)
|
shutil.rmtree(os.path.join(self.service_path, 'audio'), True)
|
||||||
|
|
||||||
def on_theme_combo_box_selected(self, currentIndex):
|
def on_theme_combo_box_selected(self, current_index):
|
||||||
"""
|
"""
|
||||||
Set the theme for the current service.
|
Set the theme for the current service.
|
||||||
|
|
||||||
|
:param current_index: The combo box index for the selected item
|
||||||
"""
|
"""
|
||||||
log.debug('on_theme_combo_box_selected')
|
|
||||||
self.service_theme = self.theme_combo_box.currentText()
|
self.service_theme = self.theme_combo_box.currentText()
|
||||||
self.renderer.set_service_theme(self.service_theme)
|
self.renderer.set_service_theme(self.service_theme)
|
||||||
Settings().setValue(self.main_window.service_manager_settings_section + '/service theme', self.service_theme)
|
Settings().setValue(self.main_window.service_manager_settings_section + '/service theme', self.service_theme)
|
||||||
@ -1239,7 +1312,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state.
|
The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state.
|
||||||
"""
|
"""
|
||||||
log.debug('theme_change')
|
|
||||||
visible = self.renderer.theme_level == ThemeLevel.Global
|
visible = self.renderer.theme_level == ThemeLevel.Global
|
||||||
self.theme_label.setVisible(visible)
|
self.theme_label.setVisible(visible)
|
||||||
self.theme_combo_box.setVisible(visible)
|
self.theme_combo_box.setVisible(visible)
|
||||||
@ -1247,9 +1319,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def regenerate_service_items(self, changed=False):
|
def regenerate_service_items(self, changed=False):
|
||||||
"""
|
"""
|
||||||
Rebuild the service list as things have changed and a repaint is the easiest way to do this.
|
Rebuild the service list as things have changed and a repaint is the easiest way to do this.
|
||||||
|
|
||||||
|
:param changed: True if the list has changed for new / removed items. False for a theme change.
|
||||||
"""
|
"""
|
||||||
self.application.set_busy_cursor()
|
self.application.set_busy_cursor()
|
||||||
log.debug('regenerate_service_items')
|
|
||||||
# force reset of renderer as theme data has changed
|
# force reset of renderer as theme data has changed
|
||||||
self.service_has_all_original_files = True
|
self.service_has_all_original_files = True
|
||||||
if self.service_items:
|
if self.service_items:
|
||||||
@ -1281,46 +1354,49 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.repaint_service_list(-1, -1)
|
self.repaint_service_list(-1, -1)
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def replace_service_item(self, newItem):
|
def replace_service_item(self, new_item):
|
||||||
"""
|
"""
|
||||||
Using the service item passed replace the one with the same edit id if found.
|
Using the service item passed replace the one with the same edit id if found.
|
||||||
|
|
||||||
|
:param new_item: a new service item to up date an existing one.
|
||||||
"""
|
"""
|
||||||
for item_count, item in enumerate(self.service_items):
|
for item_count, item in enumerate(self.service_items):
|
||||||
if item['service_item'].edit_id == newItem.edit_id and item['service_item'].name == newItem.name:
|
if item['service_item'].edit_id == new_item.edit_id and item['service_item'].name == new_item.name:
|
||||||
newItem.render()
|
new_item.render()
|
||||||
newItem.merge(item['service_item'])
|
new_item.merge(item['service_item'])
|
||||||
item['service_item'] = newItem
|
item['service_item'] = new_item
|
||||||
self.repaint_service_list(item_count + 1, 0)
|
self.repaint_service_list(item_count + 1, 0)
|
||||||
self.live_controller.replace_service_manager_item(newItem)
|
self.live_controller.replace_service_manager_item(new_item)
|
||||||
self.set_modified()
|
self.set_modified()
|
||||||
|
|
||||||
def add_service_item(self, item, rebuild=False, expand=None, replace=False, repaint=True, selected=False):
|
def add_service_item(self, item, rebuild=False, expand=None, replace=False, repaint=True, selected=False):
|
||||||
"""
|
"""
|
||||||
Add a Service item to the list
|
Add a Service item to the list
|
||||||
|
|
||||||
``item``
|
:param item: Service Item to be added
|
||||||
Service Item to be added
|
:param rebuild: Do we need to rebuild the live display (Default False)
|
||||||
|
:param expand: Override the default expand settings. (Tristate)
|
||||||
``expand``
|
:param replace: Is the service item a replacement (Default False)
|
||||||
Override the default expand settings. (Tristate)
|
:param repaint: Do we need to repaint the service item list (Default True)
|
||||||
|
:param selected: Has the item been selected (Default False)
|
||||||
"""
|
"""
|
||||||
# if not passed set to config value
|
# if not passed set to config value
|
||||||
if expand is None:
|
if expand is None:
|
||||||
expand = Settings().value('advanced/expand service item')
|
expand = Settings().value('advanced/expand service item')
|
||||||
item.from_service = True
|
item.from_service = True
|
||||||
if replace:
|
if replace:
|
||||||
sitem, child = self.find_service_item()
|
s_item, child = self.find_service_item()
|
||||||
item.merge(self.service_items[sitem]['service_item'])
|
item.merge(self.service_items[s_item]['service_item'])
|
||||||
self.service_items[sitem]['service_item'] = item
|
self.service_items[s_item]['service_item'] = item
|
||||||
self.repaint_service_list(sitem, child)
|
self.repaint_service_list(s_item, child)
|
||||||
self.live_controller.replace_service_manager_item(item)
|
self.live_controller.replace_service_manager_item(item)
|
||||||
else:
|
else:
|
||||||
item.render()
|
item.render()
|
||||||
# nothing selected for dnd
|
# nothing selected for dnd
|
||||||
if self.drop_position == 0:
|
if self.drop_position == 0:
|
||||||
if isinstance(item, list):
|
if isinstance(item, list):
|
||||||
for inditem in item:
|
for ind_item in item:
|
||||||
self.service_items.append({'service_item': inditem,
|
self.service_items.append({'service_item': ind_item,
|
||||||
'order': len(self.service_items) + 1,
|
'order': len(self.service_items) + 1,
|
||||||
'expanded': expand, 'selected': selected})
|
'expanded': expand, 'selected': selected})
|
||||||
else:
|
else:
|
||||||
@ -1364,9 +1440,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
else:
|
else:
|
||||||
return self.service_items[item]['service_item']
|
return self.service_items[item]['service_item']
|
||||||
|
|
||||||
def on_make_live(self):
|
def on_make_live(self, field=None):
|
||||||
"""
|
"""
|
||||||
Send the current item to the Live slide controller but triggered by a tablewidget click event.
|
Send the current item to the Live slide controller but triggered by a tablewidget click event.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
self.make_live()
|
self.make_live()
|
||||||
|
|
||||||
@ -1374,8 +1451,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Send the current item to the Live slide controller
|
Send the current item to the Live slide controller
|
||||||
|
|
||||||
``row``
|
:param row: Row number to be displayed if from preview. -1 is passed if the value is not set
|
||||||
Row number to be displayed if from preview. -1 is passed if the value is not set
|
|
||||||
"""
|
"""
|
||||||
item, child = self.find_service_item()
|
item, child = self.find_service_item()
|
||||||
# No items in service
|
# No items in service
|
||||||
@ -1401,9 +1477,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
'is missing or inactive'))
|
'is missing or inactive'))
|
||||||
self.application.set_normal_cursor()
|
self.application.set_normal_cursor()
|
||||||
|
|
||||||
def remote_edit(self):
|
def remote_edit(self, field=None):
|
||||||
"""
|
"""
|
||||||
Triggers a remote edit to a plugin to allow item to be edited.
|
Triggers a remote edit to a plugin to allow item to be edited.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
if self.service_items[item]['service_item'].is_capable(ItemCapabilities.CanEdit):
|
if self.service_items[item]['service_item'].is_capable(ItemCapabilities.CanEdit):
|
||||||
@ -1412,9 +1489,10 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
if new_item:
|
if new_item:
|
||||||
self.add_service_item(new_item, replace=True)
|
self.add_service_item(new_item, replace=True)
|
||||||
|
|
||||||
def create_custom(self):
|
def create_custom(self, field=None):
|
||||||
"""
|
"""
|
||||||
Saves the current text item as a custom slide
|
Saves the current text item as a custom slide
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.find_service_item()[0]
|
item = self.find_service_item()[0]
|
||||||
Registry().execute('custom_create_from_service', self.service_items[item]['service_item'])
|
Registry().execute('custom_create_from_service', self.service_items[item]['service_item'])
|
||||||
@ -1448,8 +1526,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
Receive drop event and trigger an internal event to get the plugins to build and push the correct service item.
|
Receive drop event and trigger an internal event to get the plugins to build and push the correct service item.
|
||||||
The drag event payload carries the plugin name
|
The drag event payload carries the plugin name
|
||||||
|
|
||||||
``event``
|
:param event: Handle of the event passed
|
||||||
Handle of the event pint passed
|
|
||||||
"""
|
"""
|
||||||
link = event.mimeData()
|
link = event.mimeData()
|
||||||
if link.hasUrls():
|
if link.hasUrls():
|
||||||
@ -1508,8 +1585,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
"""
|
"""
|
||||||
Called from ThemeManager when the Themes have changed
|
Called from ThemeManager when the Themes have changed
|
||||||
|
|
||||||
``theme_list``
|
:param theme_list: A list of current themes to be displayed
|
||||||
A list of current themes to be displayed
|
|
||||||
"""
|
"""
|
||||||
self.theme_combo_box.clear()
|
self.theme_combo_box.clear()
|
||||||
self.theme_menu.clear()
|
self.theme_menu.clear()
|
||||||
@ -1532,9 +1608,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
self.renderer.set_service_theme(self.service_theme)
|
self.renderer.set_service_theme(self.service_theme)
|
||||||
self.regenerate_service_items()
|
self.regenerate_service_items()
|
||||||
|
|
||||||
def on_theme_change_action(self):
|
def on_theme_change_action(self, field=None):
|
||||||
"""
|
"""
|
||||||
Handles theme change events
|
Handles theme change events
|
||||||
|
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
theme = self.sender().objectName()
|
theme = self.sender().objectName()
|
||||||
# No object name means that the "Default" theme is supposed to be used.
|
# No object name means that the "Default" theme is supposed to be used.
|
||||||
@ -1547,6 +1625,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
|
|||||||
def _get_parent_item_data(self, item):
|
def _get_parent_item_data(self, item):
|
||||||
"""
|
"""
|
||||||
Finds and returns the parent item for any item
|
Finds and returns the parent item for any item
|
||||||
|
|
||||||
|
:param item: The service item list item to be checked.
|
||||||
"""
|
"""
|
||||||
parent_item = item.parent()
|
parent_item = item.parent()
|
||||||
if parent_item is None:
|
if parent_item is None:
|
||||||
|
@ -51,7 +51,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
Initialise the settings form
|
Initialise the settings form
|
||||||
"""
|
"""
|
||||||
Registry().register('settings_form', self)
|
Registry().register('settings_form', self)
|
||||||
Registry().register_function('bootstrap_post_set_up', self.post_set_up)
|
Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up)
|
||||||
super(SettingsForm, self).__init__(parent)
|
super(SettingsForm, self).__init__(parent)
|
||||||
self.processes = []
|
self.processes = []
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
@ -117,7 +117,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
self.stacked_layout.widget(tabIndex).cancel()
|
self.stacked_layout.widget(tabIndex).cancel()
|
||||||
return QtGui.QDialog.reject(self)
|
return QtGui.QDialog.reject(self)
|
||||||
|
|
||||||
def post_set_up(self):
|
def bootstrap_post_set_up(self):
|
||||||
"""
|
"""
|
||||||
Run any post-setup code for the tabs on the form
|
Run any post-setup code for the tabs on the form
|
||||||
"""
|
"""
|
||||||
|
@ -72,6 +72,11 @@ WIDE_MENU = [
|
|||||||
'desktop_screen_button'
|
'desktop_screen_button'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
NON_TEXT_MENU = [
|
||||||
|
'blank_screen_button',
|
||||||
|
'desktop_screen_button'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class DisplayController(QtGui.QWidget):
|
class DisplayController(QtGui.QWidget):
|
||||||
"""
|
"""
|
||||||
@ -116,6 +121,9 @@ class SlideController(DisplayController):
|
|||||||
self.screen_size_changed()
|
self.screen_size_changed()
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
"""
|
||||||
|
Initialise the UI elements of the controller
|
||||||
|
"""
|
||||||
self.screens = ScreenList()
|
self.screens = ScreenList()
|
||||||
try:
|
try:
|
||||||
self.ratio = self.screens.current['size'].width() / self.screens.current['size'].height()
|
self.ratio = self.screens.current['size'].width() / self.screens.current['size'].height()
|
||||||
@ -442,6 +450,8 @@ class SlideController(DisplayController):
|
|||||||
def set_live_hot_keys(self, parent=None):
|
def set_live_hot_keys(self, parent=None):
|
||||||
"""
|
"""
|
||||||
Set the live hotkeys
|
Set the live hotkeys
|
||||||
|
|
||||||
|
:param parent: The parent UI object for actions to be added to.
|
||||||
"""
|
"""
|
||||||
self.previous_service = create_action(parent, 'previousService',
|
self.previous_service = create_action(parent, 'previousService',
|
||||||
text=translate('OpenLP.SlideController', 'Previous Service'),
|
text=translate('OpenLP.SlideController', 'Previous Service'),
|
||||||
@ -469,6 +479,8 @@ class SlideController(DisplayController):
|
|||||||
def toggle_display(self, action):
|
def toggle_display(self, action):
|
||||||
"""
|
"""
|
||||||
Toggle the display settings triggered from remote messages.
|
Toggle the display settings triggered from remote messages.
|
||||||
|
|
||||||
|
:param action: The blank action to be processed.
|
||||||
"""
|
"""
|
||||||
if action == 'blank' or action == 'hide':
|
if action == 'blank' or action == 'hide':
|
||||||
self.on_blank_display(True)
|
self.on_blank_display(True)
|
||||||
@ -544,6 +556,8 @@ class SlideController(DisplayController):
|
|||||||
def __add_actions_to_widget(self, widget):
|
def __add_actions_to_widget(self, widget):
|
||||||
"""
|
"""
|
||||||
Add actions to the widget specified by `widget`
|
Add actions to the widget specified by `widget`
|
||||||
|
|
||||||
|
:param widget: The UI widget for the actions
|
||||||
"""
|
"""
|
||||||
widget.addActions([
|
widget.addActions([
|
||||||
self.previous_item, self.next_item,
|
self.previous_item, self.next_item,
|
||||||
@ -574,6 +588,8 @@ class SlideController(DisplayController):
|
|||||||
def on_controller_size_changed(self, width):
|
def on_controller_size_changed(self, width):
|
||||||
"""
|
"""
|
||||||
Change layout of display control buttons on controller size change
|
Change layout of display control buttons on controller size change
|
||||||
|
|
||||||
|
:param width: the new width of the display
|
||||||
"""
|
"""
|
||||||
if self.is_live:
|
if self.is_live:
|
||||||
# Space used by the toolbar.
|
# Space used by the toolbar.
|
||||||
@ -581,12 +597,24 @@ class SlideController(DisplayController):
|
|||||||
# Add the threshold to prevent flickering.
|
# Add the threshold to prevent flickering.
|
||||||
if width > used_space + HIDE_MENU_THRESHOLD and self.hide_menu.isVisible():
|
if width > used_space + HIDE_MENU_THRESHOLD and self.hide_menu.isVisible():
|
||||||
self.toolbar.set_widget_visible(NARROW_MENU, False)
|
self.toolbar.set_widget_visible(NARROW_MENU, False)
|
||||||
self.toolbar.set_widget_visible(WIDE_MENU)
|
self.set_blank_menu()
|
||||||
# Take away a threshold to prevent flickering.
|
# Take away a threshold to prevent flickering.
|
||||||
elif width < used_space - HIDE_MENU_THRESHOLD and not self.hide_menu.isVisible():
|
elif width < used_space - HIDE_MENU_THRESHOLD and not self.hide_menu.isVisible():
|
||||||
self.toolbar.set_widget_visible(WIDE_MENU, False)
|
self.set_blank_menu(False)
|
||||||
self.toolbar.set_widget_visible(NARROW_MENU)
|
self.toolbar.set_widget_visible(NARROW_MENU)
|
||||||
|
|
||||||
|
def set_blank_menu(self, visible=True):
|
||||||
|
"""
|
||||||
|
Set the correct menu type dependent on the service item type
|
||||||
|
|
||||||
|
:param visible: Do I need to hide the menu?
|
||||||
|
"""
|
||||||
|
self.toolbar.set_widget_visible(WIDE_MENU, False)
|
||||||
|
if self.service_item and self.service_item.is_text():
|
||||||
|
self.toolbar.set_widget_visible(WIDE_MENU, visible)
|
||||||
|
else:
|
||||||
|
self.toolbar.set_widget_visible(NON_TEXT_MENU, visible)
|
||||||
|
|
||||||
def on_song_bar_handler(self):
|
def on_song_bar_handler(self):
|
||||||
"""
|
"""
|
||||||
Some song handler
|
Some song handler
|
||||||
@ -612,6 +640,8 @@ class SlideController(DisplayController):
|
|||||||
def enable_tool_bar(self, item):
|
def enable_tool_bar(self, item):
|
||||||
"""
|
"""
|
||||||
Allows the toolbars to be reconfigured based on Controller Type and ServiceItem Type
|
Allows the toolbars to be reconfigured based on Controller Type and ServiceItem Type
|
||||||
|
|
||||||
|
:param item: current service item being processed
|
||||||
"""
|
"""
|
||||||
if self.is_live:
|
if self.is_live:
|
||||||
self.enable_live_tool_bar(item)
|
self.enable_live_tool_bar(item)
|
||||||
@ -621,6 +651,8 @@ class SlideController(DisplayController):
|
|||||||
def enable_live_tool_bar(self, item):
|
def enable_live_tool_bar(self, item):
|
||||||
"""
|
"""
|
||||||
Allows the live toolbar to be customised
|
Allows the live toolbar to be customised
|
||||||
|
|
||||||
|
:param item: The current service item
|
||||||
"""
|
"""
|
||||||
# Work-around for OS X, hide and then show the toolbar
|
# Work-around for OS X, hide and then show the toolbar
|
||||||
# See bug #791050
|
# See bug #791050
|
||||||
@ -643,6 +675,7 @@ class SlideController(DisplayController):
|
|||||||
self.mediabar.show()
|
self.mediabar.show()
|
||||||
self.previous_item.setVisible(not item.is_media())
|
self.previous_item.setVisible(not item.is_media())
|
||||||
self.next_item.setVisible(not item.is_media())
|
self.next_item.setVisible(not item.is_media())
|
||||||
|
self.set_blank_menu()
|
||||||
# Work-around for OS X, hide and then show the toolbar
|
# Work-around for OS X, hide and then show the toolbar
|
||||||
# See bug #791050
|
# See bug #791050
|
||||||
self.toolbar.show()
|
self.toolbar.show()
|
||||||
@ -977,11 +1010,13 @@ class SlideController(DisplayController):
|
|||||||
self.display.image(to_display)
|
self.display.image(to_display)
|
||||||
# reset the store used to display first image
|
# reset the store used to display first image
|
||||||
self.service_item.bg_image_bytes = None
|
self.service_item.bg_image_bytes = None
|
||||||
self.update_preview()
|
|
||||||
self.selected_row = row
|
self.selected_row = row
|
||||||
|
self.update_preview()
|
||||||
self.preview_widget.change_slide(row)
|
self.preview_widget.change_slide(row)
|
||||||
Registry().execute('slidecontroller_%s_changed' % self.type_prefix, row)
|
Registry().execute('slidecontroller_%s_changed' % self.type_prefix, row)
|
||||||
self.display.setFocus()
|
self.display.setFocus()
|
||||||
|
if self.type_prefix == 'live':
|
||||||
|
Registry().execute('websock_send', '')
|
||||||
|
|
||||||
def on_slide_change(self, row):
|
def on_slide_change(self, row):
|
||||||
"""
|
"""
|
||||||
@ -990,7 +1025,6 @@ class SlideController(DisplayController):
|
|||||||
self.preview_widget.change_slide(row)
|
self.preview_widget.change_slide(row)
|
||||||
self.update_preview()
|
self.update_preview()
|
||||||
self.selected_row = row
|
self.selected_row = row
|
||||||
Registry().execute('slidecontroller_%s_changed' % self.type_prefix, row)
|
|
||||||
|
|
||||||
def update_preview(self):
|
def update_preview(self):
|
||||||
"""
|
"""
|
||||||
|
@ -42,28 +42,25 @@ from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, get_text_fil
|
|||||||
check_item_selected, create_thumb, validate_thumb
|
check_item_selected, create_thumb, validate_thumb
|
||||||
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
||||||
from openlp.core.ui import FileRenameForm, ThemeForm, ThemeManagerHelper
|
from openlp.core.ui import FileRenameForm, ThemeForm
|
||||||
from openlp.core.utils import delete_file, get_locale_key, get_filesystem_encoding
|
from openlp.core.utils import delete_file, get_locale_key, get_filesystem_encoding
|
||||||
|
|
||||||
|
|
||||||
class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper):
|
class Ui_ThemeManager(object):
|
||||||
"""
|
"""
|
||||||
Manages the orders of Theme.
|
UI part of the Theme Manager
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent=None):
|
def setup_ui(self, widget):
|
||||||
"""
|
"""
|
||||||
Constructor
|
Define the UI
|
||||||
|
:param widget: The screen object the the dialog is to be attached to.
|
||||||
"""
|
"""
|
||||||
super(ThemeManager, self).__init__(parent)
|
|
||||||
self.settings_section = 'themes'
|
|
||||||
self.theme_form = ThemeForm(self)
|
|
||||||
self.file_rename_form = FileRenameForm()
|
|
||||||
# start with the layout
|
# start with the layout
|
||||||
self.layout = QtGui.QVBoxLayout(self)
|
self.layout = QtGui.QVBoxLayout(widget)
|
||||||
self.layout.setSpacing(0)
|
self.layout.setSpacing(0)
|
||||||
self.layout.setMargin(0)
|
self.layout.setMargin(0)
|
||||||
self.layout.setObjectName('layout')
|
self.layout.setObjectName('layout')
|
||||||
self.toolbar = OpenLPToolbar(self)
|
self.toolbar = OpenLPToolbar(widget)
|
||||||
self.toolbar.setObjectName('toolbar')
|
self.toolbar.setObjectName('toolbar')
|
||||||
self.toolbar.add_toolbar_action('newTheme',
|
self.toolbar.add_toolbar_action('newTheme',
|
||||||
text=UiStrings().NewTheme, icon=':/themes/theme_new.png',
|
text=UiStrings().NewTheme, icon=':/themes/theme_new.png',
|
||||||
@ -96,7 +93,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
self.theme_widget = QtGui.QWidgetAction(self.toolbar)
|
self.theme_widget = QtGui.QWidgetAction(self.toolbar)
|
||||||
self.theme_widget.setObjectName('theme_widget')
|
self.theme_widget.setObjectName('theme_widget')
|
||||||
# create theme manager list
|
# create theme manager list
|
||||||
self.theme_list_widget = QtGui.QListWidget(self)
|
self.theme_list_widget = QtGui.QListWidget(widget)
|
||||||
self.theme_list_widget.setAlternatingRowColors(True)
|
self.theme_list_widget.setAlternatingRowColors(True)
|
||||||
self.theme_list_widget.setIconSize(QtCore.QSize(88, 50))
|
self.theme_list_widget.setIconSize(QtCore.QSize(88, 50))
|
||||||
self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||||
@ -128,7 +125,18 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
# Signals
|
# Signals
|
||||||
self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen)
|
self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen)
|
||||||
self.theme_list_widget.currentItemChanged.connect(self.check_list_state)
|
self.theme_list_widget.currentItemChanged.connect(self.check_list_state)
|
||||||
Registry().register_function('theme_update_global', self.change_global_from_tab)
|
|
||||||
|
|
||||||
|
class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager):
|
||||||
|
"""
|
||||||
|
Manages the orders of Theme.
|
||||||
|
"""
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
"""
|
||||||
|
Constructor
|
||||||
|
"""
|
||||||
|
super(ThemeManager, self).__init__(parent)
|
||||||
|
self.settings_section = 'themes'
|
||||||
# Variables
|
# Variables
|
||||||
self.theme_list = []
|
self.theme_list = []
|
||||||
self.old_background_image = None
|
self.old_background_image = None
|
||||||
@ -137,7 +145,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
process the bootstrap initialise setup request
|
process the bootstrap initialise setup request
|
||||||
"""
|
"""
|
||||||
self.log_debug('initialise called')
|
self.setup_ui(self)
|
||||||
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
||||||
self.build_theme_path()
|
self.build_theme_path()
|
||||||
self.load_first_time_themes()
|
self.load_first_time_themes()
|
||||||
@ -146,12 +154,28 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
process the bootstrap post setup request
|
process the bootstrap post setup request
|
||||||
"""
|
"""
|
||||||
|
self.theme_form = ThemeForm(self)
|
||||||
|
self.theme_form.path = self.path
|
||||||
|
self.file_rename_form = FileRenameForm()
|
||||||
|
Registry().register_function('theme_update_global', self.change_global_from_tab)
|
||||||
self._push_themes()
|
self._push_themes()
|
||||||
|
|
||||||
|
def build_theme_path(self):
|
||||||
|
"""
|
||||||
|
Set up the theme path variables
|
||||||
|
"""
|
||||||
|
self.path = AppLocation.get_section_data_path(self.settings_section)
|
||||||
|
check_directory_exists(self.path)
|
||||||
|
self.thumb_path = os.path.join(self.path, 'thumbnails')
|
||||||
|
check_directory_exists(self.thumb_path)
|
||||||
|
|
||||||
def check_list_state(self, item, field=None):
|
def check_list_state(self, item, field=None):
|
||||||
"""
|
"""
|
||||||
If Default theme selected remove delete button.
|
If Default theme selected remove delete button.
|
||||||
Note for some reason a dummy field is required. Nothing is passed!
|
Note for some reason a dummy field is required. Nothing is passed!
|
||||||
|
|
||||||
|
:param field:
|
||||||
|
:param item: Service Item to process
|
||||||
"""
|
"""
|
||||||
if item is None:
|
if item is None:
|
||||||
return
|
return
|
||||||
@ -165,8 +189,9 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
|
|
||||||
def context_menu(self, point):
|
def context_menu(self, point):
|
||||||
"""
|
"""
|
||||||
Build the Right Click Context menu and set state depending on
|
Build the Right Click Context menu and set state depending on the type of theme.
|
||||||
the type of theme.
|
|
||||||
|
:param point: The position of the mouse so the correct item can be found.
|
||||||
"""
|
"""
|
||||||
item = self.theme_list_widget.itemAt(point)
|
item = self.theme_list_widget.itemAt(point)
|
||||||
if item is None:
|
if item is None:
|
||||||
@ -200,8 +225,9 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
|
|
||||||
def change_global_from_screen(self, index=-1):
|
def change_global_from_screen(self, index=-1):
|
||||||
"""
|
"""
|
||||||
Change the global theme when a theme is double clicked upon in the
|
Change the global theme when a theme is double clicked upon in the Theme Manager list.
|
||||||
Theme Manager list
|
|
||||||
|
:param index:
|
||||||
"""
|
"""
|
||||||
selected_row = self.theme_list_widget.currentRow()
|
selected_row = self.theme_list_widget.currentRow()
|
||||||
for count in range(0, self.theme_list_widget.count()):
|
for count in range(0, self.theme_list_widget.count()):
|
||||||
@ -221,8 +247,9 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
|
|
||||||
def on_add_theme(self, field=None):
|
def on_add_theme(self, field=None):
|
||||||
"""
|
"""
|
||||||
Loads a new theme with the default settings and then launches the theme
|
Loads a new theme with the default settings and then launches the theme editing form for the user to make
|
||||||
editing form for the user to make their customisations.
|
their customisations.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
theme = ThemeXML()
|
theme = ThemeXML()
|
||||||
theme.set_default_header_footer()
|
theme.set_default_header_footer()
|
||||||
@ -233,6 +260,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def on_rename_theme(self, field=None):
|
def on_rename_theme(self, field=None):
|
||||||
"""
|
"""
|
||||||
Renames an existing theme to a new name
|
Renames an existing theme to a new name
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
|
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
|
||||||
translate('OpenLP.ThemeManager', 'Rename Confirmation'),
|
translate('OpenLP.ThemeManager', 'Rename Confirmation'),
|
||||||
@ -257,6 +285,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def on_copy_theme(self, field=None):
|
def on_copy_theme(self, field=None):
|
||||||
"""
|
"""
|
||||||
Copies an existing theme to a new name
|
Copies an existing theme to a new name
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.theme_list_widget.currentItem()
|
item = self.theme_list_widget.currentItem()
|
||||||
old_theme_name = item.data(QtCore.Qt.UserRole)
|
old_theme_name = item.data(QtCore.Qt.UserRole)
|
||||||
@ -271,6 +300,9 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def clone_theme_data(self, theme_data, new_theme_name):
|
def clone_theme_data(self, theme_data, new_theme_name):
|
||||||
"""
|
"""
|
||||||
Takes a theme and makes a new copy of it as well as saving it.
|
Takes a theme and makes a new copy of it as well as saving it.
|
||||||
|
|
||||||
|
:param theme_data: The theme to be used
|
||||||
|
:param new_theme_name: The new theme name to save the data to
|
||||||
"""
|
"""
|
||||||
save_to = None
|
save_to = None
|
||||||
save_from = None
|
save_from = None
|
||||||
@ -286,6 +318,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Loads the settings for the theme that is to be edited and launches the
|
Loads the settings for the theme that is to be edited and launches the
|
||||||
theme editing form so the user can make their changes.
|
theme editing form so the user can make their changes.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
if check_item_selected(self.theme_list_widget,
|
if check_item_selected(self.theme_list_widget,
|
||||||
translate('OpenLP.ThemeManager', 'You must select a theme to edit.')):
|
translate('OpenLP.ThemeManager', 'You must select a theme to edit.')):
|
||||||
@ -301,7 +334,8 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
|
|
||||||
def on_delete_theme(self, field=None):
|
def on_delete_theme(self, field=None):
|
||||||
"""
|
"""
|
||||||
Delete a theme
|
Delete a theme triggered by the UI.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
|
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
|
||||||
translate('OpenLP.ThemeManager', 'Delete Confirmation'),
|
translate('OpenLP.ThemeManager', 'Delete Confirmation'),
|
||||||
@ -320,8 +354,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Delete a theme.
|
Delete a theme.
|
||||||
|
|
||||||
``theme``
|
:param theme: The theme to delete.
|
||||||
The theme to delete.
|
|
||||||
"""
|
"""
|
||||||
self.theme_list.remove(theme)
|
self.theme_list.remove(theme)
|
||||||
thumb = '%s.png' % theme
|
thumb = '%s.png' % theme
|
||||||
@ -337,6 +370,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def on_export_theme(self, field=None):
|
def on_export_theme(self, field=None):
|
||||||
"""
|
"""
|
||||||
Export the theme in a zip file
|
Export the theme in a zip file
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
item = self.theme_list_widget.currentItem()
|
item = self.theme_list_widget.currentItem()
|
||||||
if item is None:
|
if item is None:
|
||||||
@ -378,6 +412,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from
|
Opens a file dialog to select the theme file(s) to import before attempting to extract OpenLP themes from
|
||||||
those files. This process will load both OpenLP version 1 and version 2 themes.
|
those files. This process will load both OpenLP version 1 and version 2 themes.
|
||||||
|
:param field:
|
||||||
"""
|
"""
|
||||||
files = FileDialog.getOpenFileNames(self,
|
files = FileDialog.getOpenFileNames(self,
|
||||||
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
|
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
|
||||||
@ -462,8 +497,8 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Returns a theme object from an XML file
|
Returns a theme object from an XML file
|
||||||
|
|
||||||
``theme_name``
|
:param theme_name: Name of the theme to load from file
|
||||||
Name of the theme to load from file
|
:return The theme object.
|
||||||
"""
|
"""
|
||||||
self.log_debug('get theme data for theme %s' % theme_name)
|
self.log_debug('get theme data for theme %s' % theme_name)
|
||||||
xml_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')
|
xml_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')
|
||||||
@ -472,11 +507,13 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
self.log_debug('No theme data - using default theme')
|
self.log_debug('No theme data - using default theme')
|
||||||
return ThemeXML()
|
return ThemeXML()
|
||||||
else:
|
else:
|
||||||
return self._create_theme_from_Xml(xml, self.path)
|
return self._create_theme_from_xml(xml, self.path)
|
||||||
|
|
||||||
def over_write_message_box(self, theme_name):
|
def over_write_message_box(self, theme_name):
|
||||||
"""
|
"""
|
||||||
Display a warning box to the user that a theme already exists
|
Display a warning box to the user that a theme already exists
|
||||||
|
:param theme_name: Name of the theme.
|
||||||
|
:return Confirm if the theme is to be overeritten.
|
||||||
"""
|
"""
|
||||||
ret = QtGui.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
|
ret = QtGui.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
|
||||||
translate('OpenLP.ThemeManager',
|
translate('OpenLP.ThemeManager',
|
||||||
@ -489,11 +526,12 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
|
|
||||||
def unzip_theme(self, file_name, directory):
|
def unzip_theme(self, file_name, directory):
|
||||||
"""
|
"""
|
||||||
Unzip the theme, remove the preview file if stored
|
Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
|
||||||
Generate a new preview file. Check the XML theme version and upgrade if
|
and upgrade if necessary.
|
||||||
necessary.
|
:param file_name:
|
||||||
|
:param directory:
|
||||||
"""
|
"""
|
||||||
self.log_debug('Unzipping theme %s', file_name)
|
self.log_debug('Unzipping theme %s' % file_name)
|
||||||
file_name = str(file_name)
|
file_name = str(file_name)
|
||||||
theme_zip = None
|
theme_zip = None
|
||||||
out_file = None
|
out_file = None
|
||||||
@ -548,8 +586,8 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
if not abort_import:
|
if not abort_import:
|
||||||
# As all files are closed, we can create the Theme.
|
# As all files are closed, we can create the Theme.
|
||||||
if file_xml:
|
if file_xml:
|
||||||
theme = self._create_theme_from_Xml(file_xml, self.path)
|
theme = self._create_theme_from_xml(file_xml, self.path)
|
||||||
self.generate_and_save_image(directory, theme_name, theme)
|
self.generate_and_save_image(theme_name, theme)
|
||||||
# Only show the error message, when IOError was not raised (in
|
# Only show the error message, when IOError was not raised (in
|
||||||
# this case the error message has already been shown).
|
# this case the error message has already been shown).
|
||||||
elif theme_zip is not None:
|
elif theme_zip is not None:
|
||||||
@ -562,8 +600,8 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Check if theme already exists and displays error message
|
Check if theme already exists and displays error message
|
||||||
|
|
||||||
``theme_name``
|
:param theme_name: Name of the Theme to test
|
||||||
Name of the Theme to test
|
:return True or False if theme exists
|
||||||
"""
|
"""
|
||||||
theme_dir = os.path.join(self.path, theme_name)
|
theme_dir = os.path.join(self.path, theme_name)
|
||||||
if os.path.exists(theme_dir):
|
if os.path.exists(theme_dir):
|
||||||
@ -576,6 +614,10 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def save_theme(self, theme, image_from, image_to):
|
def save_theme(self, theme, image_from, image_to):
|
||||||
"""
|
"""
|
||||||
Called by theme maintenance Dialog to save the theme and to trigger the reload of the theme list
|
Called by theme maintenance Dialog to save the theme and to trigger the reload of the theme list
|
||||||
|
|
||||||
|
:param theme: The theme data object.
|
||||||
|
:param image_from: Where the theme image is currently located.
|
||||||
|
:param image_to: Where the Theme Image is to be saved to
|
||||||
"""
|
"""
|
||||||
self._write_theme(theme, image_from, image_to)
|
self._write_theme(theme, image_from, image_to)
|
||||||
if theme.background_type == BackgroundType.to_string(BackgroundType.Image):
|
if theme.background_type == BackgroundType.to_string(BackgroundType.Image):
|
||||||
@ -587,6 +629,10 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
def _write_theme(self, theme, image_from, image_to):
|
def _write_theme(self, theme, image_from, image_to):
|
||||||
"""
|
"""
|
||||||
Writes the theme to the disk and handles the background image if necessary
|
Writes the theme to the disk and handles the background image if necessary
|
||||||
|
|
||||||
|
:param theme: The theme data object.
|
||||||
|
:param image_from: Where the theme image is currently located.
|
||||||
|
:param image_to: Where the Theme Image is to be saved to
|
||||||
"""
|
"""
|
||||||
name = theme.theme_name
|
name = theme.theme_name
|
||||||
theme_pretty_xml = theme.extract_formatted_xml()
|
theme_pretty_xml = theme.extract_formatted_xml()
|
||||||
@ -611,11 +657,14 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
except IOError as xxx_todo_changeme:
|
except IOError as xxx_todo_changeme:
|
||||||
shutil.Error = xxx_todo_changeme
|
shutil.Error = xxx_todo_changeme
|
||||||
self.log_exception('Failed to save theme image')
|
self.log_exception('Failed to save theme image')
|
||||||
self.generate_and_save_image(self.path, name, theme)
|
self.generate_and_save_image(name, theme)
|
||||||
|
|
||||||
def generate_and_save_image(self, directory, name, theme):
|
def generate_and_save_image(self, name, theme):
|
||||||
"""
|
"""
|
||||||
Generate and save a preview image
|
Generate and save a preview image
|
||||||
|
|
||||||
|
:param name: The name of the theme.
|
||||||
|
:param theme: The theme data object.
|
||||||
"""
|
"""
|
||||||
frame = self.generate_image(theme)
|
frame = self.generate_image(theme)
|
||||||
sample_path_name = os.path.join(self.path, name + '.png')
|
sample_path_name = os.path.join(self.path, name + '.png')
|
||||||
@ -632,7 +681,7 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
self.main_window.display_progress_bar(len(self.theme_list))
|
self.main_window.display_progress_bar(len(self.theme_list))
|
||||||
for theme in self.theme_list:
|
for theme in self.theme_list:
|
||||||
self.main_window.increment_progress_bar()
|
self.main_window.increment_progress_bar()
|
||||||
self.generate_and_save_image(self.path, theme, self.get_theme_data(theme))
|
self.generate_and_save_image(theme, self.get_theme_data(theme))
|
||||||
self.main_window.finished_progress_bar()
|
self.main_window.finished_progress_bar()
|
||||||
self.load_themes()
|
self.load_themes()
|
||||||
|
|
||||||
@ -640,11 +689,8 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Call the renderer to build a Sample Image
|
Call the renderer to build a Sample Image
|
||||||
|
|
||||||
``theme_data``
|
:param theme_data: The theme to generated a preview for.
|
||||||
The theme to generated a preview for.
|
:param force_page: Flag to tell message lines per page need to be generated.
|
||||||
|
|
||||||
``force_page``
|
|
||||||
Flag to tell message lines per page need to be generated.
|
|
||||||
"""
|
"""
|
||||||
return self.renderer.generate_preview(theme_data, force_page)
|
return self.renderer.generate_preview(theme_data, force_page)
|
||||||
|
|
||||||
@ -652,26 +698,33 @@ class ThemeManager(RegistryMixin, OpenLPMixin, QtGui.QWidget, ThemeManagerHelper
|
|||||||
"""
|
"""
|
||||||
Return an image representing the look of the theme
|
Return an image representing the look of the theme
|
||||||
|
|
||||||
``theme``
|
:param theme: The theme to return the image for.
|
||||||
The theme to return the image for
|
|
||||||
"""
|
"""
|
||||||
return os.path.join(self.path, theme + '.png')
|
return os.path.join(self.path, theme + '.png')
|
||||||
|
|
||||||
def _create_theme_from_Xml(self, theme_xml, path):
|
def _create_theme_from_xml(self, theme_xml, image_path):
|
||||||
"""
|
"""
|
||||||
Return a theme object using information parsed from XML
|
Return a theme object using information parsed from XML
|
||||||
|
|
||||||
``theme_xml``
|
:param theme_xml: The Theme data object.
|
||||||
The XML data to load into the theme
|
:param image_path: Where the theme image is stored
|
||||||
|
:return Theme data.
|
||||||
"""
|
"""
|
||||||
theme = ThemeXML()
|
theme = ThemeXML()
|
||||||
theme.parse(theme_xml)
|
theme.parse(theme_xml)
|
||||||
theme.extend_image_filename(path)
|
theme.extend_image_filename(image_path)
|
||||||
return theme
|
return theme
|
||||||
|
|
||||||
def _validate_theme_action(self, select_text, confirm_title, confirm_text, test_plugin=True, confirm=True):
|
def _validate_theme_action(self, select_text, confirm_title, confirm_text, test_plugin=True, confirm=True):
|
||||||
"""
|
"""
|
||||||
Check to see if theme has been selected and the destructive action is allowed.
|
Check to see if theme has been selected and the destructive action is allowed.
|
||||||
|
|
||||||
|
:param select_text: Text for message box if no item selected.
|
||||||
|
:param confirm_title: Confirm message title to be displayed.
|
||||||
|
:param confirm_text: Confirm message text to be displayed.
|
||||||
|
:param test_plugin: Do we check the plugins for theme usage.
|
||||||
|
:param confirm: Do we display a confirm box before run checks.
|
||||||
|
:return True or False depending on the validity.
|
||||||
"""
|
"""
|
||||||
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
||||||
if check_item_selected(self.theme_list_widget, select_text):
|
if check_item_selected(self.theme_list_widget, select_text):
|
||||||
|
@ -127,9 +127,15 @@ __default_settings__ = {
|
|||||||
|
|
||||||
|
|
||||||
class AlertsPlugin(Plugin):
|
class AlertsPlugin(Plugin):
|
||||||
|
"""
|
||||||
|
The Alerts Plugin Class
|
||||||
|
"""
|
||||||
log.info('Alerts Plugin loaded')
|
log.info('Alerts Plugin loaded')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Class __init__ method
|
||||||
|
"""
|
||||||
super(AlertsPlugin, self).__init__('alerts', __default_settings__, settings_tab_class=AlertsTab)
|
super(AlertsPlugin, self).__init__('alerts', __default_settings__, settings_tab_class=AlertsTab)
|
||||||
self.weight = -3
|
self.weight = -3
|
||||||
self.icon_path = ':/plugins/plugin_alerts.png'
|
self.icon_path = ':/plugins/plugin_alerts.png'
|
||||||
@ -142,17 +148,20 @@ class AlertsPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
Give the alerts plugin the opportunity to add items to the **Tools** menu.
|
Give the alerts plugin the opportunity to add items to the **Tools** menu.
|
||||||
|
|
||||||
``tools_menu``
|
:param tools_menu: The actual **Tools** menu item, so that your actions can use it as their parent.
|
||||||
The actual **Tools** menu item, so that your actions can use it as their parent.
|
|
||||||
"""
|
"""
|
||||||
log.info('add tools menu')
|
log.info('add tools menu')
|
||||||
self.tools_alert_item = create_action(tools_menu, 'toolsAlertItem',
|
self.tools_alert_item = create_action(tools_menu, 'toolsAlertItem',
|
||||||
text=translate('AlertsPlugin', '&Alert'), icon=':/plugins/plugin_alerts.png',
|
text=translate('AlertsPlugin', '&Alert'),
|
||||||
|
icon=':/plugins/plugin_alerts.png',
|
||||||
statustip=translate('AlertsPlugin', 'Show an alert message.'),
|
statustip=translate('AlertsPlugin', 'Show an alert message.'),
|
||||||
visible=False, can_shortcuts=True, triggers=self.on_alerts_trigger)
|
visible=False, can_shortcuts=True, triggers=self.on_alerts_trigger)
|
||||||
self.main_window.tools_menu.addAction(self.tools_alert_item)
|
self.main_window.tools_menu.addAction(self.tools_alert_item)
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
"""
|
||||||
|
Initialise plugin
|
||||||
|
"""
|
||||||
log.info('Alerts Initialising')
|
log.info('Alerts Initialising')
|
||||||
super(AlertsPlugin, self).initialise()
|
super(AlertsPlugin, self).initialise()
|
||||||
self.tools_alert_item.setVisible(True)
|
self.tools_alert_item.setVisible(True)
|
||||||
@ -171,16 +180,27 @@ class AlertsPlugin(Plugin):
|
|||||||
action_list.remove_action(self.tools_alert_item, 'Tools')
|
action_list.remove_action(self.tools_alert_item, 'Tools')
|
||||||
|
|
||||||
def toggle_alerts_state(self):
|
def toggle_alerts_state(self):
|
||||||
|
"""
|
||||||
|
Switch the alerts state
|
||||||
|
"""
|
||||||
self.alerts_active = not self.alerts_active
|
self.alerts_active = not self.alerts_active
|
||||||
Settings().setValue(self.settings_section + '/active', self.alerts_active)
|
Settings().setValue(self.settings_section + '/active', self.alerts_active)
|
||||||
|
|
||||||
def on_alerts_trigger(self):
|
def on_alerts_trigger(self):
|
||||||
|
"""
|
||||||
|
Start of the Alerts dialog triggered from the main menu.
|
||||||
|
"""
|
||||||
self.alert_form.load_list()
|
self.alert_form.load_list()
|
||||||
self.alert_form.exec_()
|
self.alert_form.exec_()
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
|
"""
|
||||||
|
Plugin Alerts about method
|
||||||
|
|
||||||
|
:return: text
|
||||||
|
"""
|
||||||
about_text = translate('AlertsPlugin', '<strong>Alerts Plugin</strong>'
|
about_text = translate('AlertsPlugin', '<strong>Alerts Plugin</strong>'
|
||||||
'<br />The alert plugin controls the displaying of nursery alerts on the display screen.')
|
'<br />The alert plugin controls the displaying of alerts on the display screen.')
|
||||||
return about_text
|
return about_text
|
||||||
|
|
||||||
def set_plugin_text_strings(self):
|
def set_plugin_text_strings(self):
|
||||||
@ -221,8 +241,7 @@ class AlertsPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
Trigger an update of the CSS in the main display.
|
Trigger an update of the CSS in the main display.
|
||||||
|
|
||||||
``frame``
|
:param frame: The Web frame holding the page.
|
||||||
The Web frame holding the page.
|
|
||||||
"""
|
"""
|
||||||
align = VerticalType.Names[self.settings_tab.location]
|
align = VerticalType.Names[self.settings_tab.location]
|
||||||
frame.evaluateJavaScript('update_css("%s", "%s", "%s", "%s", "%s")' %
|
frame.evaluateJavaScript('update_css("%s", "%s", "%s", "%s", "%s")' %
|
||||||
|
@ -36,6 +36,11 @@ from openlp.core.lib.ui import create_button, create_button_box
|
|||||||
|
|
||||||
class Ui_AlertDialog(object):
|
class Ui_AlertDialog(object):
|
||||||
def setupUi(self, alert_dialog):
|
def setupUi(self, alert_dialog):
|
||||||
|
"""
|
||||||
|
Setup the Alert UI dialog
|
||||||
|
|
||||||
|
:param alert_dialog: The dialog
|
||||||
|
"""
|
||||||
alert_dialog.setObjectName('alert_dialog')
|
alert_dialog.setObjectName('alert_dialog')
|
||||||
alert_dialog.resize(400, 300)
|
alert_dialog.resize(400, 300)
|
||||||
alert_dialog.setWindowIcon(build_icon(':/icon/openlp-logo-16x16.png'))
|
alert_dialog.setWindowIcon(build_icon(':/icon/openlp-logo-16x16.png'))
|
||||||
@ -86,6 +91,11 @@ class Ui_AlertDialog(object):
|
|||||||
self.retranslateUi(alert_dialog)
|
self.retranslateUi(alert_dialog)
|
||||||
|
|
||||||
def retranslateUi(self, alert_dialog):
|
def retranslateUi(self, alert_dialog):
|
||||||
|
"""
|
||||||
|
Retranslate the UI strings
|
||||||
|
|
||||||
|
:param alert_dialog: The dialog
|
||||||
|
"""
|
||||||
alert_dialog.setWindowTitle(translate('AlertsPlugin.AlertForm', 'Alert Message'))
|
alert_dialog.setWindowTitle(translate('AlertsPlugin.AlertForm', 'Alert Message'))
|
||||||
self.alert_entry_label.setText(translate('AlertsPlugin.AlertForm', 'Alert &text:'))
|
self.alert_entry_label.setText(translate('AlertsPlugin.AlertForm', 'Alert &text:'))
|
||||||
self.alert_parameter.setText(translate('AlertsPlugin.AlertForm', '&Parameter:'))
|
self.alert_parameter.setText(translate('AlertsPlugin.AlertForm', '&Parameter:'))
|
||||||
|
@ -114,7 +114,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
if not self.alert_text_edit.text():
|
if not self.alert_text_edit.text():
|
||||||
QtGui.QMessageBox.information(self,
|
QtGui.QMessageBox.information(self,
|
||||||
translate('AlertsPlugin.AlertForm', 'New Alert'),
|
translate('AlertsPlugin.AlertForm', 'New Alert'),
|
||||||
translate('AlertsPlugin.AlertForm', 'You haven\'t specified any text for your alert. \n'
|
translate('AlertsPlugin.AlertForm',
|
||||||
|
'You haven\'t specified any text for your alert. \n'
|
||||||
'Please type in some text before clicking New.'))
|
'Please type in some text before clicking New.'))
|
||||||
else:
|
else:
|
||||||
alert = AlertItem()
|
alert = AlertItem()
|
||||||
@ -153,10 +154,10 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
List item has been double clicked to display it.
|
List item has been double clicked to display it.
|
||||||
"""
|
"""
|
||||||
item = self.alert_list_widget.selectedIndexes()[0]
|
item = self.alert_list_widget.selectedIndexes()[0]
|
||||||
bitem = self.alert_list_widget.item(item.row())
|
list_item = self.alert_list_widget.item(item.row())
|
||||||
self.trigger_alert(bitem.text())
|
self.trigger_alert(list_item.text())
|
||||||
self.alert_text_edit.setText(bitem.text())
|
self.alert_text_edit.setText(list_item.text())
|
||||||
self.item_id = bitem.data(QtCore.Qt.UserRole)
|
self.item_id = list_item.data(QtCore.Qt.UserRole)
|
||||||
self.save_button.setEnabled(False)
|
self.save_button.setEnabled(False)
|
||||||
|
|
||||||
def on_single_click(self):
|
def on_single_click(self):
|
||||||
@ -164,9 +165,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
List item has been single clicked to add it to the edit field so it can be changed.
|
List item has been single clicked to add it to the edit field so it can be changed.
|
||||||
"""
|
"""
|
||||||
item = self.alert_list_widget.selectedIndexes()[0]
|
item = self.alert_list_widget.selectedIndexes()[0]
|
||||||
bitem = self.alert_list_widget.item(item.row())
|
list_item = self.alert_list_widget.item(item.row())
|
||||||
self.alert_text_edit.setText(bitem.text())
|
self.alert_text_edit.setText(list_item.text())
|
||||||
self.item_id = bitem.data(QtCore.Qt.UserRole)
|
self.item_id = list_item.data(QtCore.Qt.UserRole)
|
||||||
# If the alert does not contain '<>' we clear the ParameterEdit field.
|
# If the alert does not contain '<>' we clear the ParameterEdit field.
|
||||||
if self.alert_text_edit.text().find('<>') == -1:
|
if self.alert_text_edit.text().find('<>') == -1:
|
||||||
self.parameter_edit.setText('')
|
self.parameter_edit.setText('')
|
||||||
@ -176,26 +177,30 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
"""
|
"""
|
||||||
Prepares the alert text for displaying.
|
Prepares the alert text for displaying.
|
||||||
|
|
||||||
``text``
|
:param text: The alert text.
|
||||||
The alert text (unicode).
|
|
||||||
"""
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return False
|
return False
|
||||||
# We found '<>' in the alert text, but the ParameterEdit field is empty.
|
# We found '<>' in the alert text, but the ParameterEdit field is empty.
|
||||||
if text.find('<>') != -1 and not self.parameter_edit.text() and QtGui.QMessageBox.question(self,
|
if text.find('<>') != -1 and not self.parameter_edit.text() and \
|
||||||
|
QtGui.QMessageBox.question(self,
|
||||||
translate('AlertsPlugin.AlertForm', 'No Parameter Found'),
|
translate('AlertsPlugin.AlertForm', 'No Parameter Found'),
|
||||||
translate('AlertsPlugin.AlertForm', 'You have not entered a parameter to be replaced.\n'
|
translate('AlertsPlugin.AlertForm',
|
||||||
|
'You have not entered a parameter to be replaced.\n'
|
||||||
'Do you want to continue anyway?'),
|
'Do you want to continue anyway?'),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.StandardButtons(
|
||||||
|
QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
self.parameter_edit.setFocus()
|
self.parameter_edit.setFocus()
|
||||||
return False
|
return False
|
||||||
# The ParameterEdit field is not empty, but we have not found '<>'
|
# The ParameterEdit field is not empty, but we have not found '<>'
|
||||||
# in the alert text.
|
# in the alert text.
|
||||||
elif text.find('<>') == -1 and self.parameter_edit.text() and QtGui.QMessageBox.question(self,
|
elif text.find('<>') == -1 and self.parameter_edit.text() and \
|
||||||
|
QtGui.QMessageBox.question(self,
|
||||||
translate('AlertsPlugin.AlertForm', 'No Placeholder Found'),
|
translate('AlertsPlugin.AlertForm', 'No Placeholder Found'),
|
||||||
translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n'
|
translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n'
|
||||||
'Do you want to continue anyway?'),
|
'Do you want to continue anyway?'),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.StandardButtons(
|
||||||
|
QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
self.parameter_edit.setFocus()
|
self.parameter_edit.setFocus()
|
||||||
return False
|
return False
|
||||||
text = text.replace('<>', self.parameter_edit.text())
|
text = text.replace('<>', self.parameter_edit.text())
|
||||||
@ -207,8 +212,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
Called when the *alert_list_widget*'s current row has been changed. This enables or disables buttons which
|
Called when the *alert_list_widget*'s current row has been changed. This enables or disables buttons which
|
||||||
require an item to act on.
|
require an item to act on.
|
||||||
|
|
||||||
``row``
|
:param row: The row (int). If there is no current row, the value is -1.
|
||||||
The row (int). If there is no current row, the value is -1.
|
|
||||||
"""
|
"""
|
||||||
if row == -1:
|
if row == -1:
|
||||||
self.display_button.setEnabled(False)
|
self.display_button.setEnabled(False)
|
||||||
|
@ -59,6 +59,8 @@ class AlertsManager(QtCore.QObject):
|
|||||||
def alert_text(self, message):
|
def alert_text(self, message):
|
||||||
"""
|
"""
|
||||||
Called via a alerts_text event. Message is single element array containing text.
|
Called via a alerts_text event. Message is single element array containing text.
|
||||||
|
|
||||||
|
:param message: The message text to be displayed
|
||||||
"""
|
"""
|
||||||
if message:
|
if message:
|
||||||
self.display_alert(message[0])
|
self.display_alert(message[0])
|
||||||
@ -67,8 +69,7 @@ class AlertsManager(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
Called from the Alert Tab to display an alert.
|
Called from the Alert Tab to display an alert.
|
||||||
|
|
||||||
``text``
|
:param text: The text to display
|
||||||
display text
|
|
||||||
"""
|
"""
|
||||||
log.debug('display alert called %s' % text)
|
log.debug('display alert called %s' % text)
|
||||||
if text:
|
if text:
|
||||||
@ -98,8 +99,7 @@ class AlertsManager(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
Time has finished so if our time then request the next Alert if there is one and reset the timer.
|
Time has finished so if our time then request the next Alert if there is one and reset the timer.
|
||||||
|
|
||||||
``event``
|
:param event: the QT event that has been triggered.
|
||||||
the QT event that has been triggered.
|
|
||||||
"""
|
"""
|
||||||
log.debug('timer event')
|
log.debug('timer event')
|
||||||
if event.timerId() == self.timer_id:
|
if event.timerId() == self.timer_id:
|
||||||
|
@ -114,6 +114,9 @@ class AlertsTab(SettingsTab):
|
|||||||
self.font_preview.setText(UiStrings().OLPV2x)
|
self.font_preview.setText(UiStrings().OLPV2x)
|
||||||
|
|
||||||
def on_background_color_button_clicked(self):
|
def on_background_color_button_clicked(self):
|
||||||
|
"""
|
||||||
|
The background color has been changed.
|
||||||
|
"""
|
||||||
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.background_color), self)
|
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.background_color), self)
|
||||||
if new_color.isValid():
|
if new_color.isValid():
|
||||||
self.background_color = new_color.name()
|
self.background_color = new_color.name()
|
||||||
@ -121,9 +124,15 @@ class AlertsTab(SettingsTab):
|
|||||||
self.update_display()
|
self.update_display()
|
||||||
|
|
||||||
def on_font_combo_box_clicked(self):
|
def on_font_combo_box_clicked(self):
|
||||||
|
"""
|
||||||
|
The Font Combo was changed.
|
||||||
|
"""
|
||||||
self.update_display()
|
self.update_display()
|
||||||
|
|
||||||
def on_font_color_button_clicked(self):
|
def on_font_color_button_clicked(self):
|
||||||
|
"""
|
||||||
|
The Font Color button has clicked.
|
||||||
|
"""
|
||||||
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.font_color), self)
|
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.font_color), self)
|
||||||
if new_color.isValid():
|
if new_color.isValid():
|
||||||
self.font_color = new_color.name()
|
self.font_color = new_color.name()
|
||||||
@ -131,14 +140,24 @@ class AlertsTab(SettingsTab):
|
|||||||
self.update_display()
|
self.update_display()
|
||||||
|
|
||||||
def on_timeout_spin_box_changed(self):
|
def on_timeout_spin_box_changed(self):
|
||||||
|
"""
|
||||||
|
The Time out spin box has changed.
|
||||||
|
|
||||||
|
"""
|
||||||
self.timeout = self.timeout_spin_box.value()
|
self.timeout = self.timeout_spin_box.value()
|
||||||
self.changed = True
|
self.changed = True
|
||||||
|
|
||||||
def on_font_size_spin_box_changed(self):
|
def on_font_size_spin_box_changed(self):
|
||||||
|
"""
|
||||||
|
The font size spin box has changed.
|
||||||
|
"""
|
||||||
self.font_size = self.font_size_spin_box.value()
|
self.font_size = self.font_size_spin_box.value()
|
||||||
self.update_display()
|
self.update_display()
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
"""
|
||||||
|
Load the settings into the UI.
|
||||||
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(self.settings_section)
|
settings.beginGroup(self.settings_section)
|
||||||
self.timeout = settings.value('timeout')
|
self.timeout = settings.value('timeout')
|
||||||
@ -160,6 +179,9 @@ class AlertsTab(SettingsTab):
|
|||||||
self.changed = False
|
self.changed = False
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
"""
|
||||||
|
Save the changes on exit of the Settings dialog.
|
||||||
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(self.settings_section)
|
settings.beginGroup(self.settings_section)
|
||||||
# Check value has changed as no event handles this field
|
# Check value has changed as no event handles this field
|
||||||
@ -179,6 +201,9 @@ class AlertsTab(SettingsTab):
|
|||||||
self.changed = False
|
self.changed = False
|
||||||
|
|
||||||
def update_display(self):
|
def update_display(self):
|
||||||
|
"""
|
||||||
|
Update the preview display after changes have been made,
|
||||||
|
"""
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily(self.font_combo_box.currentFont().family())
|
font.setFamily(self.font_combo_box.currentFont().family())
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
|
@ -47,7 +47,7 @@ def init_schema(url):
|
|||||||
"""
|
"""
|
||||||
Setup the alerts database connection and initialise the database schema
|
Setup the alerts database connection and initialise the database schema
|
||||||
|
|
||||||
``url``
|
:param url:
|
||||||
The database to setup
|
The database to setup
|
||||||
"""
|
"""
|
||||||
session, metadata = init_db(url)
|
session, metadata = init_db(url)
|
||||||
|
@ -36,6 +36,10 @@ from openlp.core.lib.ui import create_button_box, create_button
|
|||||||
|
|
||||||
class Ui_CustomEditDialog(object):
|
class Ui_CustomEditDialog(object):
|
||||||
def setupUi(self, custom_edit_dialog):
|
def setupUi(self, custom_edit_dialog):
|
||||||
|
"""
|
||||||
|
Build the Edit Dialog UI
|
||||||
|
:param custom_edit_dialog: The Dialog
|
||||||
|
"""
|
||||||
custom_edit_dialog.setObjectName('custom_edit_dialog')
|
custom_edit_dialog.setObjectName('custom_edit_dialog')
|
||||||
custom_edit_dialog.resize(450, 350)
|
custom_edit_dialog.resize(450, 350)
|
||||||
custom_edit_dialog.setWindowIcon(build_icon(':/icon/openlp-logo-16x16.png'))
|
custom_edit_dialog.setWindowIcon(build_icon(':/icon/openlp-logo-16x16.png'))
|
||||||
|
@ -70,8 +70,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
"""
|
"""
|
||||||
Load a list of themes into the themes combo box.
|
Load a list of themes into the themes combo box.
|
||||||
|
|
||||||
``theme_list``
|
:param theme_list: The list of themes to load.
|
||||||
The list of themes to load.
|
|
||||||
"""
|
"""
|
||||||
self.theme_combo_box.clear()
|
self.theme_combo_box.clear()
|
||||||
self.theme_combo_box.addItem('')
|
self.theme_combo_box.addItem('')
|
||||||
@ -81,12 +80,8 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
"""
|
"""
|
||||||
Called when editing or creating a new custom.
|
Called when editing or creating a new custom.
|
||||||
|
|
||||||
``id``
|
:param id: The custom's id. If zero, then a new custom is created.
|
||||||
The custom's id. If zero, then a new custom is created.
|
:param preview: States whether the custom is edited while being previewed in the preview panel.
|
||||||
|
|
||||||
``preview``
|
|
||||||
States whether the custom is edited while being previewed in the
|
|
||||||
preview panel.
|
|
||||||
"""
|
"""
|
||||||
self.slide_list_view.clear()
|
self.slide_list_view.clear()
|
||||||
if id == 0:
|
if id == 0:
|
||||||
@ -195,11 +190,8 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
"""
|
"""
|
||||||
Updates the slide list after editing slides.
|
Updates the slide list after editing slides.
|
||||||
|
|
||||||
``slides``
|
:param slides: A list of all slides which have been edited.
|
||||||
A list of all slides which have been edited.
|
:param edit_all: Indicates if all slides or only one slide has been edited.
|
||||||
|
|
||||||
``edit_all``
|
|
||||||
Indicates if all slides or only one slide has been edited.
|
|
||||||
"""
|
"""
|
||||||
if edit_all:
|
if edit_all:
|
||||||
self.slide_list_view.clear()
|
self.slide_list_view.clear()
|
||||||
@ -229,8 +221,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
Called when the *slide_list_view*'s current row has been changed. This
|
Called when the *slide_list_view*'s current row has been changed. This
|
||||||
enables or disables buttons which require an slide to act on.
|
enables or disables buttons which require an slide to act on.
|
||||||
|
|
||||||
``row``
|
:param row: The row (int). If there is no current row, the value is -1.
|
||||||
The row (int). If there is no current row, the value is -1.
|
|
||||||
"""
|
"""
|
||||||
if row == -1:
|
if row == -1:
|
||||||
self.delete_button.setEnabled(False)
|
self.delete_button.setEnabled(False)
|
||||||
|
@ -57,8 +57,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
|
|||||||
"""
|
"""
|
||||||
Set the text for slide_text_edit.
|
Set the text for slide_text_edit.
|
||||||
|
|
||||||
``text``
|
:param text: The text (unicode).
|
||||||
The text (unicode).
|
|
||||||
"""
|
"""
|
||||||
self.slide_text_edit.clear()
|
self.slide_text_edit.clear()
|
||||||
if text:
|
if text:
|
||||||
@ -87,7 +86,9 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
|
|||||||
|
|
||||||
def insert_single_line_text_at_cursor(self, text):
|
def insert_single_line_text_at_cursor(self, text):
|
||||||
"""
|
"""
|
||||||
Adds ``text`` in a single line at the cursor position.
|
Adds a single line at the cursor position.
|
||||||
|
|
||||||
|
:param text: The text to be inserted
|
||||||
"""
|
"""
|
||||||
full_text = self.slide_text_edit.toPlainText()
|
full_text = self.slide_text_edit.toPlainText()
|
||||||
position = self.slide_text_edit.textCursor().position()
|
position = self.slide_text_edit.textCursor().position()
|
||||||
|
@ -72,6 +72,8 @@ class CustomTab(SettingsTab):
|
|||||||
def on_display_footer_check_box_changed(self, check_state):
|
def on_display_footer_check_box_changed(self, check_state):
|
||||||
"""
|
"""
|
||||||
Toggle the setting for displaying the footer.
|
Toggle the setting for displaying the footer.
|
||||||
|
|
||||||
|
:param check_state: The current check box state
|
||||||
"""
|
"""
|
||||||
self.display_footer = False
|
self.display_footer = False
|
||||||
# we have a set value convert to True/False
|
# we have a set value convert to True/False
|
||||||
@ -79,9 +81,18 @@ class CustomTab(SettingsTab):
|
|||||||
self.display_footer = True
|
self.display_footer = True
|
||||||
|
|
||||||
def on_add_from_service_check_box_changed(self, check_state):
|
def on_add_from_service_check_box_changed(self, check_state):
|
||||||
|
"""
|
||||||
|
Allows service items to create Custom items.
|
||||||
|
|
||||||
|
:param check_state: The current check box state
|
||||||
|
"""
|
||||||
self.update_load = (check_state == QtCore.Qt.Checked)
|
self.update_load = (check_state == QtCore.Qt.Checked)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Load the settings into the dialog
|
||||||
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(self.settings_section)
|
settings.beginGroup(self.settings_section)
|
||||||
self.display_footer = settings.value('display footer')
|
self.display_footer = settings.value('display footer')
|
||||||
@ -91,6 +102,9 @@ class CustomTab(SettingsTab):
|
|||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
"""
|
||||||
|
Save the Dialog settings
|
||||||
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(self.settings_section)
|
settings.beginGroup(self.settings_section)
|
||||||
settings.setValue('display footer', self.display_footer)
|
settings.setValue('display footer', self.display_footer)
|
||||||
|
@ -50,6 +50,7 @@ from lxml import etree, objectify
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
#TODO: These classes need to be refactored into a single class.
|
#TODO: These classes need to be refactored into a single class.
|
||||||
class CustomXMLBuilder(object):
|
class CustomXMLBuilder(object):
|
||||||
"""
|
"""
|
||||||
@ -89,15 +90,11 @@ class CustomXMLBuilder(object):
|
|||||||
"""
|
"""
|
||||||
Add a verse to the ``<lyrics>`` tag.
|
Add a verse to the ``<lyrics>`` tag.
|
||||||
|
|
||||||
``verse_type``
|
:param verse_type: A string denoting the type of verse. Possible values are "Chorus", "Verse", "Bridge",
|
||||||
A string denoting the type of verse. Possible values are "Chorus",
|
and "Custom".
|
||||||
"Verse", "Bridge", and "Custom".
|
:param number: An integer denoting the number of the item, for example: verse 1.
|
||||||
|
:param content: The actual text of the verse to be stored.
|
||||||
|
|
||||||
``number``
|
|
||||||
An integer denoting the number of the item, for example: verse 1.
|
|
||||||
|
|
||||||
``content``
|
|
||||||
The actual text of the verse to be stored.
|
|
||||||
"""
|
"""
|
||||||
verse = self.custom_xml.createElement('verse')
|
verse = self.custom_xml.createElement('verse')
|
||||||
verse.setAttribute('type', verse_type)
|
verse.setAttribute('type', verse_type)
|
||||||
|
@ -73,6 +73,9 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
self.remote_custom = -1
|
self.remote_custom = -1
|
||||||
|
|
||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
|
"""
|
||||||
|
Add the Custom End Head bar and register events and functions
|
||||||
|
"""
|
||||||
self.toolbar.addSeparator()
|
self.toolbar.addSeparator()
|
||||||
self.add_search_to_toolbar()
|
self.add_search_to_toolbar()
|
||||||
# Signals and slots
|
# Signals and slots
|
||||||
@ -91,10 +94,17 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service')
|
self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service')
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
self.search_text_label.setText('%s:' % UiStrings().Search)
|
self.search_text_label.setText('%s:' % UiStrings().Search)
|
||||||
self.search_text_button.setText(UiStrings().Search)
|
self.search_text_button.setText(UiStrings().Search)
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
"""
|
||||||
|
Initialise the UI so it can provide Searches
|
||||||
|
"""
|
||||||
self.search_text_edit.set_search_types([(CustomSearch.Titles, ':/songs/song_search_title.png',
|
self.search_text_edit.set_search_types([(CustomSearch.Titles, ':/songs/song_search_title.png',
|
||||||
translate('SongsPlugin.MediaItem', 'Titles'),
|
translate('SongsPlugin.MediaItem', 'Titles'),
|
||||||
translate('SongsPlugin.MediaItem', 'Search Titles...')),
|
translate('SongsPlugin.MediaItem', 'Search Titles...')),
|
||||||
@ -107,6 +117,11 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def load_list(self, custom_slides, target_group=None):
|
def load_list(self, custom_slides, target_group=None):
|
||||||
# Sort out what custom we want to select after loading the list.
|
# Sort out what custom we want to select after loading the list.
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param custom_slides:
|
||||||
|
:param target_group:
|
||||||
|
"""
|
||||||
self.save_auto_select_id()
|
self.save_auto_select_id()
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
custom_slides.sort()
|
custom_slides.sort()
|
||||||
@ -123,6 +138,9 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
# active trigger it and clean up so it will not update again.
|
# active trigger it and clean up so it will not update again.
|
||||||
|
|
||||||
def on_new_click(self):
|
def on_new_click(self):
|
||||||
|
"""
|
||||||
|
Handle the New item event
|
||||||
|
"""
|
||||||
self.edit_custom_form.load_custom(0)
|
self.edit_custom_form.load_custom(0)
|
||||||
self.edit_custom_form.exec_()
|
self.edit_custom_form.exec_()
|
||||||
self.on_clear_text_button_click()
|
self.on_clear_text_button_click()
|
||||||
@ -132,6 +150,9 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
Called by ServiceManager or SlideController by event passing the custom Id in the payload along with an
|
Called by ServiceManager or SlideController by event passing the custom Id in the payload along with an
|
||||||
indicator to say which type of display is required.
|
indicator to say which type of display is required.
|
||||||
|
|
||||||
|
:param custom_id: The id of the item to be edited
|
||||||
|
:param preview: Do we need to update the Preview after the edit. (Default False)
|
||||||
"""
|
"""
|
||||||
custom_id = int(custom_id)
|
custom_id = int(custom_id)
|
||||||
valid = self.plugin.db_manager.get_object(CustomSlide, custom_id)
|
valid = self.plugin.db_manager.get_object(CustomSlide, custom_id)
|
||||||
@ -184,12 +205,20 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
self.on_search_text_button_clicked()
|
self.on_search_text_button_clicked()
|
||||||
|
|
||||||
def on_focus(self):
|
def on_focus(self):
|
||||||
|
"""
|
||||||
|
Set the focus
|
||||||
|
"""
|
||||||
self.search_text_edit.setFocus()
|
self.search_text_edit.setFocus()
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xml_version=False,
|
def generate_slide_data(self, service_item, item=None, xml_version=False,
|
||||||
remote=False, context=ServiceItemContext.Service):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
"""
|
"""
|
||||||
Generate the slide data. Needs to be implemented by the plugin.
|
Generate the slide data. Needs to be implemented by the plugin.
|
||||||
|
:param service_item: To be updated
|
||||||
|
:param item: The custom database item to be used
|
||||||
|
:param xml_version: No used
|
||||||
|
:param remote: Is this triggered by the Preview Controller or Service Manager.
|
||||||
|
:param context: Why is this item required to be build (Default Service).
|
||||||
"""
|
"""
|
||||||
item_id = self._get_id_of_item_to_generate(item, self.remote_custom)
|
item_id = self._get_id_of_item_to_generate(item, self.remote_custom)
|
||||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
@ -243,6 +272,8 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
If search as type enabled invoke the search on each key press. If the Title is being searched do not start until
|
If search as type enabled invoke the search on each key press. If the Title is being searched do not start until
|
||||||
2 characters have been entered.
|
2 characters have been entered.
|
||||||
|
|
||||||
|
:param text: The search text
|
||||||
"""
|
"""
|
||||||
search_length = 2
|
search_length = 2
|
||||||
if len(text) > search_length:
|
if len(text) > search_length:
|
||||||
@ -253,6 +284,8 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
def service_load(self, item):
|
def service_load(self, item):
|
||||||
"""
|
"""
|
||||||
Triggered by a custom item being loaded by the service manager.
|
Triggered by a custom item being loaded by the service manager.
|
||||||
|
|
||||||
|
:param item: The service Item from the service to load found in the database.
|
||||||
"""
|
"""
|
||||||
log.debug('service_load')
|
log.debug('service_load')
|
||||||
if self.plugin.status != PluginStatus.Active:
|
if self.plugin.status != PluginStatus.Active:
|
||||||
@ -271,6 +304,8 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
def create_from_service_item(self, item):
|
def create_from_service_item(self, item):
|
||||||
"""
|
"""
|
||||||
Create a custom slide from a text service item
|
Create a custom slide from a text service item
|
||||||
|
|
||||||
|
:param item: the service item to be converted to a Custom item
|
||||||
"""
|
"""
|
||||||
custom = CustomSlide()
|
custom = CustomSlide()
|
||||||
custom.title = item.title
|
custom.title = item.title
|
||||||
@ -303,6 +338,9 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
def search(self, string, show_error):
|
def search(self, string, show_error):
|
||||||
"""
|
"""
|
||||||
Search the database for a given item.
|
Search the database for a given item.
|
||||||
|
|
||||||
|
:param string: The search string
|
||||||
|
:param show_error: The error string to be show.
|
||||||
"""
|
"""
|
||||||
search = '%' + string.lower() + '%'
|
search = '%' + string.lower() + '%'
|
||||||
search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
|
search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
|
||||||
|
@ -94,7 +94,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
self.reset_action.setToolTip(UiStrings().ResetLiveBG)
|
||||||
self.automatic = UiStrings().Automatic
|
self.automatic = UiStrings().Automatic
|
||||||
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
self.display_type_label.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||||
self.rebuild_players()
|
#self.rebuild_players()
|
||||||
|
|
||||||
def required_icons(self):
|
def required_icons(self):
|
||||||
"""
|
"""
|
||||||
@ -112,9 +112,9 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
def add_end_header_bar(self):
|
def add_end_header_bar(self):
|
||||||
# Replace backgrounds do not work at present so remove functionality.
|
# Replace backgrounds do not work at present so remove functionality.
|
||||||
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_blank.png',
|
self.replace_action = self.toolbar.add_toolbar_action('replace_action', icon=':/slides/slide_blank.png',
|
||||||
triggers=self.onReplaceClick)
|
triggers=self.on_replace_click)
|
||||||
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
|
self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png',
|
||||||
visible=False, triggers=self.onResetClick)
|
visible=False, triggers=self.on_reset_click)
|
||||||
self.media_widget = QtGui.QWidget(self)
|
self.media_widget = QtGui.QWidget(self)
|
||||||
self.media_widget.setObjectName('media_widget')
|
self.media_widget.setObjectName('media_widget')
|
||||||
self.display_layout = QtGui.QFormLayout(self.media_widget)
|
self.display_layout = QtGui.QFormLayout(self.media_widget)
|
||||||
@ -128,16 +128,16 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.display_layout.addRow(self.display_type_label, self.display_type_combo_box)
|
self.display_layout.addRow(self.display_type_label, self.display_type_combo_box)
|
||||||
# Add the Media widget to the page layout.
|
# Add the Media widget to the page layout.
|
||||||
self.page_layout.addWidget(self.media_widget)
|
self.page_layout.addWidget(self.media_widget)
|
||||||
self.display_type_combo_box.currentIndexChanged.connect(self.overridePlayerChanged)
|
self.display_type_combo_box.currentIndexChanged.connect(self.override_player_changed)
|
||||||
|
|
||||||
def overridePlayerChanged(self, index):
|
def override_player_changed(self, index):
|
||||||
player = get_media_players()[0]
|
player = get_media_players()[0]
|
||||||
if index == 0:
|
if index == 0:
|
||||||
set_media_players(player)
|
set_media_players(player)
|
||||||
else:
|
else:
|
||||||
set_media_players(player, player[index-1])
|
set_media_players(player, player[index-1])
|
||||||
|
|
||||||
def onResetClick(self):
|
def on_reset_click(self):
|
||||||
"""
|
"""
|
||||||
Called to reset the Live background with the media selected,
|
Called to reset the Live background with the media selected,
|
||||||
"""
|
"""
|
||||||
@ -150,12 +150,13 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
self.reset_action.setVisible(False)
|
self.reset_action.setVisible(False)
|
||||||
|
|
||||||
def onReplaceClick(self):
|
def on_replace_click(self):
|
||||||
"""
|
"""
|
||||||
Called to replace Live background with the media selected.
|
Called to replace Live background with the media selected.
|
||||||
"""
|
"""
|
||||||
if check_item_selected(self.list_view,
|
if check_item_selected(self.list_view,
|
||||||
translate('MediaPlugin.MediaItem', 'You must select a media file to replace the background with.')):
|
translate('MediaPlugin.MediaItem',
|
||||||
|
'You must select a media file to replace the background with.')):
|
||||||
item = self.list_view.currentItem()
|
item = self.list_view.currentItem()
|
||||||
filename = item.data(QtCore.Qt.UserRole)
|
filename = item.data(QtCore.Qt.UserRole)
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
@ -168,11 +169,13 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.reset_action.setVisible(True)
|
self.reset_action.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
translate('MediaPlugin.MediaItem', 'There was no display item to amend.'))
|
translate('MediaPlugin.MediaItem',
|
||||||
|
'There was no display item to amend.'))
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
translate('MediaPlugin.MediaItem',
|
translate('MediaPlugin.MediaItem',
|
||||||
'There was a problem replacing your background, the media file "%s" no longer exists.') % filename)
|
'There was a problem replacing your background, '
|
||||||
|
'the media file "%s" no longer exists.') % filename)
|
||||||
|
|
||||||
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
|
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
|
||||||
context=ServiceItemContext.Live):
|
context=ServiceItemContext.Live):
|
||||||
@ -211,16 +214,16 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
def initialise(self):
|
def initialise(self):
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
self.list_view.setIconSize(QtCore.QSize(88, 50))
|
self.list_view.setIconSize(QtCore.QSize(88, 50))
|
||||||
self.servicePath = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
|
self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
|
||||||
check_directory_exists(self.servicePath)
|
check_directory_exists(self.service_path)
|
||||||
self.load_list(Settings().value(self.settings_section + '/media files'))
|
self.load_list(Settings().value(self.settings_section + '/media files'))
|
||||||
self.populateDisplayTypes()
|
self.populate_display_types()
|
||||||
|
|
||||||
def rebuild_players(self):
|
def rebuild_players(self):
|
||||||
"""
|
"""
|
||||||
Rebuild the tab in the media manager when changes are made in the settings.
|
Rebuild the tab in the media manager when changes are made in the settings.
|
||||||
"""
|
"""
|
||||||
self.populateDisplayTypes()
|
self.populate_display_types()
|
||||||
self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % (
|
self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % (
|
||||||
' '.join(self.media_controller.video_extensions_list),
|
' '.join(self.media_controller.video_extensions_list),
|
||||||
' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles)
|
' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles)
|
||||||
@ -228,25 +231,25 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
def display_setup(self):
|
def display_setup(self):
|
||||||
self.media_controller.setup_display(self.display_controller.preview_display, False)
|
self.media_controller.setup_display(self.display_controller.preview_display, False)
|
||||||
|
|
||||||
def populateDisplayTypes(self):
|
def populate_display_types(self):
|
||||||
"""
|
"""
|
||||||
Load the combobox with the enabled media players, allowing user to select a specific player if settings allow.
|
Load the combobox with the enabled media players, allowing user to select a specific player if settings allow.
|
||||||
"""
|
"""
|
||||||
# block signals to avoid unnecessary overridePlayerChanged Signals while combo box creation
|
# block signals to avoid unnecessary override_player_changed Signals while combo box creation
|
||||||
self.display_type_combo_box.blockSignals(True)
|
self.display_type_combo_box.blockSignals(True)
|
||||||
self.display_type_combo_box.clear()
|
self.display_type_combo_box.clear()
|
||||||
usedPlayers, overridePlayer = get_media_players()
|
used_players, override_player = get_media_players()
|
||||||
media_players = self.media_controller.media_players
|
media_players = self.media_controller.media_players
|
||||||
currentIndex = 0
|
current_index = 0
|
||||||
for player in usedPlayers:
|
for player in used_players:
|
||||||
# load the drop down selection
|
# load the drop down selection
|
||||||
self.display_type_combo_box.addItem(media_players[player].original_name)
|
self.display_type_combo_box.addItem(media_players[player].original_name)
|
||||||
if overridePlayer == player:
|
if override_player == player:
|
||||||
currentIndex = len(self.display_type_combo_box)
|
current_index = len(self.display_type_combo_box)
|
||||||
if self.display_type_combo_box.count() > 1:
|
if self.display_type_combo_box.count() > 1:
|
||||||
self.display_type_combo_box.insertItem(0, self.automatic)
|
self.display_type_combo_box.insertItem(0, self.automatic)
|
||||||
self.display_type_combo_box.setCurrentIndex(currentIndex)
|
self.display_type_combo_box.setCurrentIndex(current_index)
|
||||||
if overridePlayer:
|
if override_player:
|
||||||
self.media_widget.show()
|
self.media_widget.show()
|
||||||
else:
|
else:
|
||||||
self.media_widget.hide()
|
self.media_widget.hide()
|
||||||
@ -266,25 +269,25 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def load_list(self, media, target_group=None):
|
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(str(filename))[1]))
|
media.sort(key=lambda file_name: get_locale_key(os.path.split(str(file_name))[1]))
|
||||||
for track in media:
|
for track in media:
|
||||||
track_info = QtCore.QFileInfo(track)
|
track_info = QtCore.QFileInfo(track)
|
||||||
if not os.path.exists(track):
|
if not os.path.exists(track):
|
||||||
filename = os.path.split(str(track))[1]
|
file_name = os.path.split(str(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(file_name)
|
||||||
item_name.setIcon(ERROR_ICON)
|
item_name.setIcon(ERROR_ICON)
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
elif track_info.isFile():
|
elif track_info.isFile():
|
||||||
filename = os.path.split(str(track))[1]
|
file_name = os.path.split(str(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(file_name)
|
||||||
if '*.%s' % (filename.split('.')[-1].lower()) in self.media_controller.audio_extensions_list:
|
if '*.%s' % (file_name.split('.')[-1].lower()) in self.media_controller.audio_extensions_list:
|
||||||
item_name.setIcon(AUDIO_ICON)
|
item_name.setIcon(AUDIO_ICON)
|
||||||
else:
|
else:
|
||||||
item_name.setIcon(VIDEO_ICON)
|
item_name.setIcon(VIDEO_ICON)
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
else:
|
else:
|
||||||
filename = os.path.split(str(track))[1]
|
file_name = os.path.split(str(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(file_name)
|
||||||
item_name.setIcon(build_icon(DVD_ICON))
|
item_name.setIcon(build_icon(DVD_ICON))
|
||||||
item_name.setData(QtCore.Qt.UserRole, track)
|
item_name.setData(QtCore.Qt.UserRole, track)
|
||||||
item_name.setToolTip(track)
|
item_name.setToolTip(track)
|
||||||
@ -302,7 +305,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
media = [x for x in media if os.path.splitext(x)[1] in extension]
|
media = [x for x in media if os.path.splitext(x)[1] in extension]
|
||||||
return media
|
return media
|
||||||
|
|
||||||
def search(self, string, showError):
|
def search(self, string, show_error):
|
||||||
files = Settings().value(self.settings_section + '/media files')
|
files = Settings().value(self.settings_section + '/media files')
|
||||||
results = []
|
results = []
|
||||||
string = string.lower()
|
string = string.lower()
|
||||||
|
@ -41,7 +41,8 @@ if os.name == 'nt':
|
|||||||
import win32ui
|
import win32ui
|
||||||
import pywintypes
|
import pywintypes
|
||||||
|
|
||||||
from openlp.core.lib import ScreenList, Registry
|
from openlp.core.lib import ScreenList
|
||||||
|
from openlp.core.common import Registry
|
||||||
from .presentationcontroller import PresentationController, PresentationDocument
|
from .presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
<link rel="stylesheet" href="/files/openlp.css" />
|
<link rel="stylesheet" href="/files/openlp.css" />
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
<link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
|
||||||
<script type="text/javascript" src="/files/jquery.js"></script>
|
<script type="text/javascript" src="/files/jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="/files/WebSocketEvents.js"></script>
|
||||||
<script type="text/javascript" src="/files/openlp.js"></script>
|
<script type="text/javascript" src="/files/openlp.js"></script>
|
||||||
<script type="text/javascript" src="/files/jquery.mobile.js"></script>
|
<script type="text/javascript" src="/files/jquery.mobile.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -400,4 +400,4 @@ $("#search").live("pageinit", function (event) {
|
|||||||
});
|
});
|
||||||
//setInterval("OpenLP.pollServer();", 30000);
|
//setInterval("OpenLP.pollServer();", 30000);
|
||||||
//OpenLP.pollServer();
|
//OpenLP.pollServer();
|
||||||
var ws = new wsEventEngine("ws://" + window.location.hostname + ":9999/Test", OpenLP.pollServer, 500);
|
var ws = new wsEventEngine("ws://" + window.location.hostname + ":8888/Test", OpenLP.pollServer, 500);
|
||||||
|
@ -30,5 +30,6 @@
|
|||||||
from .remotetab import RemoteTab
|
from .remotetab import RemoteTab
|
||||||
from .httprouter import HttpRouter
|
from .httprouter import HttpRouter
|
||||||
from .httpserver import OpenLPServer
|
from .httpserver import OpenLPServer
|
||||||
|
from .websocket import WebSocketManager
|
||||||
|
|
||||||
__all__ = ['RemoteTab', 'OpenLPServer', 'HttpRouter']
|
__all__ = ['RemoteTab', 'OpenLPServer', 'HttpRouter','WebSocketManager']
|
||||||
|
@ -31,7 +31,8 @@ import logging
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from openlp.core.lib import Plugin, StringContent, translate, build_icon
|
from openlp.core.lib import Plugin, StringContent, translate, build_icon
|
||||||
from openlp.plugins.remotes.lib import RemoteTab, OpenLPServer
|
from openlp.core.common import Registry
|
||||||
|
from openlp.plugins.remotes.lib import RemoteTab, OpenLPServer, WebSocketManager
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ class RemotesPlugin(Plugin):
|
|||||||
self.icon = build_icon(self.icon_path)
|
self.icon = build_icon(self.icon_path)
|
||||||
self.weight = -1
|
self.weight = -1
|
||||||
self.server = None
|
self.server = None
|
||||||
|
self.websocketserver = None
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
"""
|
"""
|
||||||
@ -67,6 +69,9 @@ class RemotesPlugin(Plugin):
|
|||||||
log.debug('initialise')
|
log.debug('initialise')
|
||||||
super(RemotesPlugin, self).initialise()
|
super(RemotesPlugin, self).initialise()
|
||||||
self.server = OpenLPServer()
|
self.server = OpenLPServer()
|
||||||
|
self.websocketserver = WebSocketManager()
|
||||||
|
self.websocketserver.start()
|
||||||
|
Registry().register_function('websock_send', self.websocketserver.send)
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
@ -77,6 +82,9 @@ class RemotesPlugin(Plugin):
|
|||||||
if self.server:
|
if self.server:
|
||||||
self.server.stop_server()
|
self.server.stop_server()
|
||||||
self.server = None
|
self.server = None
|
||||||
|
if self.websocketserver:
|
||||||
|
self.websocketserver.stop()
|
||||||
|
self.websocketserver = None
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
"""
|
"""
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
# Copyright (c) 2008-2014 Raoul Snyman #
|
||||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||||
|
@ -63,18 +63,14 @@ class TestRegistry(TestCase):
|
|||||||
|
|
||||||
# WHEN I try to get back a non existent component
|
# WHEN I try to get back a non existent component
|
||||||
# THEN I will get an exception
|
# THEN I will get an exception
|
||||||
with self.assertRaises(KeyError) as context:
|
|
||||||
temp = Registry().get('test2')
|
temp = Registry().get('test2')
|
||||||
self.assertEqual(context.exception.args[0], 'Service test2 not found in list',
|
self.assertEqual(temp, None, 'None should have been returned for missing service')
|
||||||
'KeyError exception should have been thrown for missing service')
|
|
||||||
|
|
||||||
# WHEN I try to replace a component I should be allowed (testing only)
|
# WHEN I try to replace a component I should be allowed (testing only)
|
||||||
Registry().remove('test1')
|
Registry().remove('test1')
|
||||||
# THEN I will get an exception
|
# THEN I will get an exception
|
||||||
with self.assertRaises(KeyError) as context:
|
|
||||||
temp = Registry().get('test1')
|
temp = Registry().get('test1')
|
||||||
self.assertEqual(context.exception.args[0], 'Service test1 not found in list',
|
self.assertEqual(temp, None, 'None should have been returned for deleted service')
|
||||||
'KeyError exception should have been thrown for deleted service')
|
|
||||||
|
|
||||||
def registry_function_test(self):
|
def registry_function_test(self):
|
||||||
"""
|
"""
|
||||||
|
85
tests/functional/openlp_core_ui/test_servicemanager.py
Normal file
85
tests/functional/openlp_core_ui/test_servicemanager.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2014 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
|
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||||
|
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||||
|
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||||
|
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
||||||
|
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Package to test the openlp.core.ui.slidecontroller package.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from openlp.core.common import Registry
|
||||||
|
from openlp.core.ui import ServiceManager
|
||||||
|
|
||||||
|
from tests.interfaces import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
|
class TestServiceManager(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the UI
|
||||||
|
"""
|
||||||
|
Registry.create()
|
||||||
|
#self.app = QtGui.QApplication([])
|
||||||
|
#ScreenList.create(self.app.desktop())
|
||||||
|
#Registry().register('application', MagicMock())
|
||||||
|
#with patch('openlp.core.lib.PluginManager'):
|
||||||
|
# self.main_window = MainWindow()
|
||||||
|
#self.service_manager = Registry().get('service_manager')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Delete all the C++ objects at the end so that we don't have a segfault
|
||||||
|
"""
|
||||||
|
#del self.main_window
|
||||||
|
#del self.app
|
||||||
|
pass
|
||||||
|
|
||||||
|
def initial_service_manager_test(self):
|
||||||
|
"""
|
||||||
|
Test the initial of service manager.
|
||||||
|
"""
|
||||||
|
# GIVEN: A new service manager instance.
|
||||||
|
ServiceManager(None)
|
||||||
|
# WHEN: the default service manager is built.
|
||||||
|
# THEN: The the controller should be registered in the registry.
|
||||||
|
self.assertNotEqual(Registry().get('service_manager'), None, 'The base service manager should be registered')
|
||||||
|
|
||||||
|
def create_basic_service_test(self):
|
||||||
|
"""
|
||||||
|
Test the create basic service array
|
||||||
|
"""
|
||||||
|
# GIVEN: A new service manager instance.
|
||||||
|
service_manager = ServiceManager(None)
|
||||||
|
# WHEN: when the basic service array is created.
|
||||||
|
service_manager._save_lite = False
|
||||||
|
service_manager.service_theme = 'test_theme'
|
||||||
|
service = service_manager.create_basic_service()[0]
|
||||||
|
# THEN: The the controller should be registered in the registry.
|
||||||
|
self.assertNotEqual(service, None, 'The base service should be created')
|
||||||
|
self.assertEqual(service['openlp_core']['service-theme'], 'test_theme', 'The test theme should be saved')
|
||||||
|
self.assertEqual(service['openlp_core']['lite-service'], False, 'The lite service should be saved')
|
@ -27,24 +27,52 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The Theme Controller helps manages adding, deleteing and modifying of themes.
|
Package to test the openlp.core.ui.slidecontroller package.
|
||||||
"""
|
"""
|
||||||
import os
|
from unittest import TestCase
|
||||||
|
|
||||||
from openlp.core.common import AppLocation, check_directory_exists
|
from openlp.core.ui import SlideController
|
||||||
|
|
||||||
|
from tests.interfaces import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
class ThemeManagerHelper(object):
|
class TestSlideController(TestCase):
|
||||||
|
|
||||||
|
def initial_slide_controller_test(self):
|
||||||
"""
|
"""
|
||||||
Manages the non ui theme functions.
|
Test the initial slide controller state .
|
||||||
"""
|
"""
|
||||||
def build_theme_path(self):
|
# GIVEN: A new slideController instance.
|
||||||
|
slide_controller = SlideController(None)
|
||||||
|
# WHEN: the default controller is built.
|
||||||
|
# THEN: The controller should not be a live controller.
|
||||||
|
self.assertEqual(slide_controller.is_live, False, 'The base slide controller should not be a live controller')
|
||||||
|
|
||||||
|
def toggle_blank_test(self):
|
||||||
"""
|
"""
|
||||||
Set up the theme path variables
|
Test the setting of the display blank icons by display type.
|
||||||
"""
|
"""
|
||||||
self.log_debug('build theme path called')
|
# GIVEN: A new slideController instance.
|
||||||
self.path = AppLocation.get_section_data_path(self.settings_section)
|
slide_controller = SlideController(None)
|
||||||
check_directory_exists(self.path)
|
service_item = MagicMock()
|
||||||
self.thumb_path = os.path.join(self.path, 'thumbnails')
|
toolbar = MagicMock()
|
||||||
check_directory_exists(self.thumb_path)
|
toolbar.set_widget_visible = self.dummy_widget_visible
|
||||||
self.theme_form.path = self.path
|
slide_controller.toolbar = toolbar
|
||||||
|
slide_controller.service_item = service_item
|
||||||
|
|
||||||
|
# WHEN a text based service item is used
|
||||||
|
slide_controller.service_item.is_text = MagicMock(return_value=True)
|
||||||
|
slide_controller.set_blank_menu()
|
||||||
|
|
||||||
|
# THEN: then call set up the toolbar to blank the display screen.
|
||||||
|
self.assertEqual(len(self.test_widget), 3, 'There should be three icons to display on the screen')
|
||||||
|
|
||||||
|
# WHEN a non text based service item is used
|
||||||
|
slide_controller.service_item.is_text = MagicMock(return_value=False)
|
||||||
|
slide_controller.set_blank_menu()
|
||||||
|
|
||||||
|
# THEN: then call set up the toolbar to blank the display screen.
|
||||||
|
self.assertEqual(len(self.test_widget), 2, 'There should be only two icons to display on the screen')
|
||||||
|
|
||||||
|
def dummy_widget_visible(self, widget, visible=True):
|
||||||
|
self.test_widget = widget
|
@ -38,7 +38,7 @@ class TestListPreviewWidget(TestCase):
|
|||||||
|
|
||||||
def initial_slide_count_test(self):
|
def initial_slide_count_test(self):
|
||||||
"""
|
"""
|
||||||
Test the inital slide count.
|
Test the initial slide count .
|
||||||
"""
|
"""
|
||||||
# GIVEN: A new ListPreviewWidget instance.
|
# GIVEN: A new ListPreviewWidget instance.
|
||||||
# WHEN: No SlideItem has been added yet.
|
# WHEN: No SlideItem has been added yet.
|
||||||
@ -47,7 +47,7 @@ class TestListPreviewWidget(TestCase):
|
|||||||
|
|
||||||
def initial_slide_number_test(self):
|
def initial_slide_number_test(self):
|
||||||
"""
|
"""
|
||||||
Test the inital slide number.
|
Test the initial current slide number.
|
||||||
"""
|
"""
|
||||||
# GIVEN: A new ListPreviewWidget instance.
|
# GIVEN: A new ListPreviewWidget instance.
|
||||||
# WHEN: No SlideItem has been added yet.
|
# WHEN: No SlideItem has been added yet.
|
||||||
|
@ -27,7 +27,8 @@ class TestMainWindow(TestCase):
|
|||||||
# Mock classes and methods used by mainwindow.
|
# Mock classes and methods used by mainwindow.
|
||||||
with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \
|
with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \
|
||||||
patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \
|
patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \
|
||||||
patch('openlp.core.ui.mainwindow.SlideController') as mocked_slide_controller, \
|
patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \
|
||||||
|
patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \
|
||||||
patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \
|
patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \
|
||||||
patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \
|
patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \
|
||||||
patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \
|
patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \
|
||||||
@ -53,7 +54,7 @@ class TestMainWindow(TestCase):
|
|||||||
mocked_value.side_effect = [True, 2]
|
mocked_value.side_effect = [True, 2]
|
||||||
|
|
||||||
# WHEN: Call the restore method.
|
# WHEN: Call the restore method.
|
||||||
Registry().execute('bootstrap_post_set_up')
|
self.main_window.restore_current_media_manager_item()
|
||||||
|
|
||||||
# THEN: The current widget should have been set.
|
# THEN: The current widget should have been set.
|
||||||
self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2)
|
self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2)
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
from PyQt4 import QtGui, QtTest, QtCore
|
||||||
|
|
||||||
from openlp.core.common import Registry
|
from openlp.core.common import Registry
|
||||||
from openlp.core.lib import ScreenList, ServiceItem
|
from openlp.core.lib import ScreenList, ServiceItem, ItemCapabilities
|
||||||
from openlp.core.ui.mainwindow import MainWindow
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
from tests.interfaces import MagicMock, patch
|
from tests.interfaces import MagicMock, patch
|
||||||
|
|
||||||
@ -35,20 +35,22 @@ class TestServiceManager(TestCase):
|
|||||||
|
|
||||||
def basic_service_manager_test(self):
|
def basic_service_manager_test(self):
|
||||||
"""
|
"""
|
||||||
Test the Service Manager display functionality
|
Test the Service Manager UI Functionality
|
||||||
"""
|
"""
|
||||||
# GIVEN: A New Service Manager instance
|
# GIVEN: A New Service Manager instance
|
||||||
|
|
||||||
# WHEN I have an empty display
|
# WHEN I have set up the display
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
# THEN the count of items should be zero
|
# THEN the count of items should be zero
|
||||||
self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
|
self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
|
||||||
'The service manager list should be empty ')
|
'The service manager list should be empty ')
|
||||||
|
|
||||||
def context_menu_test(self):
|
def default_context_menu_test(self):
|
||||||
"""
|
"""
|
||||||
Test the context_menu() method.
|
Test the context_menu() method with a default service item
|
||||||
"""
|
"""
|
||||||
# GIVEN: A service item added
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
patch('PyQt4.QtGui.QMenu.exec_'):
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
@ -84,3 +86,236 @@ class TestServiceManager(TestCase):
|
|||||||
'The action should be set invisible.'
|
'The action should be set invisible.'
|
||||||
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
'The action should be set invisible.'
|
'The action should be set invisible.'
|
||||||
|
|
||||||
|
def edit_context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method with a edit service item
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
|
service_item.edit_id = 1
|
||||||
|
self.service_manager.service_items = [{'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.maintain_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.notes_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.time_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_with(True), \
|
||||||
|
'The action should be set visible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), 'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
|
||||||
|
def maintain_context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method with a maintain
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
service_item.add_capability(ItemCapabilities.CanMaintain)
|
||||||
|
self.service_manager.service_items = [{'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.maintain_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.notes_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.time_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_with(True), \
|
||||||
|
'The action should be set visible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), 'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
|
||||||
|
def loopy_context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method with a loop
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
|
service_item._raw_frames.append("One")
|
||||||
|
service_item._raw_frames.append("Two")
|
||||||
|
self.service_manager.service_items = [{'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.maintain_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.notes_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.time_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), 'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
|
||||||
|
def start_time_context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method with a start time
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
service_item.add_capability(ItemCapabilities.HasVariableStartTime)
|
||||||
|
self.service_manager.service_items = [{'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.maintain_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.notes_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.time_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), 'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_with(True), \
|
||||||
|
'The action should be set visible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
|
||||||
|
def auto_start_context_menu_test(self):
|
||||||
|
"""
|
||||||
|
Test the context_menu() method with can auto start
|
||||||
|
"""
|
||||||
|
# GIVEN: A service item added
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
with patch('PyQt4.QtGui.QTreeWidget.itemAt') as mocked_item_at_method, \
|
||||||
|
patch('PyQt4.QtGui.QWidget.mapToGlobal'), \
|
||||||
|
patch('PyQt4.QtGui.QMenu.exec_'):
|
||||||
|
mocked_item = MagicMock()
|
||||||
|
mocked_item.parent.return_value = None
|
||||||
|
mocked_item_at_method.return_value = mocked_item
|
||||||
|
# We want 1 to be returned for the position
|
||||||
|
mocked_item.data.return_value = 1
|
||||||
|
# A service item without capabilities.
|
||||||
|
service_item = ServiceItem()
|
||||||
|
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
||||||
|
self.service_manager.service_items = [{'service_item': service_item}]
|
||||||
|
q_point = None
|
||||||
|
# Mocked actions.
|
||||||
|
self.service_manager.edit_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.create_custom_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.maintain_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.notes_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.time_action.setVisible = MagicMock()
|
||||||
|
self.service_manager.auto_start_action.setVisible = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: Show the context menu.
|
||||||
|
self.service_manager.context_menu(q_point)
|
||||||
|
|
||||||
|
# THEN: The following actions should be not visible.
|
||||||
|
self.service_manager.edit_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.create_custom_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.maintain_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.notes_action.setVisible.assert_called_with(True), 'The action should be set visible.'
|
||||||
|
self.service_manager.time_action.setVisible.assert_called_once_with(False), \
|
||||||
|
'The action should be set invisible.'
|
||||||
|
self.service_manager.auto_start_action.setVisible.assert_called_with(True), \
|
||||||
|
'The action should be set visible.'
|
||||||
|
|
||||||
|
def click_on_new_service_test(self):
|
||||||
|
"""
|
||||||
|
Test the on_new_service event handler is called by the UI
|
||||||
|
"""
|
||||||
|
# GIVEN: An initial form
|
||||||
|
mocked_event = MagicMock()
|
||||||
|
self.service_manager.on_new_service_clicked = mocked_event
|
||||||
|
self.service_manager.setup_ui(self.service_manager)
|
||||||
|
|
||||||
|
# WHEN displaying the UI and pressing cancel
|
||||||
|
new_service = self.service_manager.toolbar.actions['newService']
|
||||||
|
new_service.trigger()
|
||||||
|
|
||||||
|
assert mocked_event.call_count == 1, 'The on_new_service_clicked method should have been called once'
|
||||||
|
@ -34,27 +34,27 @@ class TestStartTimeDialog(TestCase):
|
|||||||
"""
|
"""
|
||||||
Test StartTimeDialog are defaults correct
|
Test StartTimeDialog are defaults correct
|
||||||
"""
|
"""
|
||||||
self.assertEqual(self.form.hourSpinBox.minimum(), 0, 'The minimum hour should stay the same as the dialog')
|
self.assertEqual(self.form.hour_spin_box.minimum(), 0, 'The minimum hour should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.hourSpinBox.maximum(), 4, 'The maximum hour should stay the same as the dialog')
|
self.assertEqual(self.form.hour_spin_box.maximum(), 4, 'The maximum hour should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.minuteSpinBox.minimum(), 0,
|
self.assertEqual(self.form.minute_spin_box.minimum(), 0,
|
||||||
'The minimum minute should stay the same as the dialog')
|
'The minimum minute should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.minuteSpinBox.maximum(), 59,
|
self.assertEqual(self.form.minute_spin_box.maximum(), 59,
|
||||||
'The maximum minute should stay the same as the dialog')
|
'The maximum minute should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.secondSpinBox.minimum(), 0,
|
self.assertEqual(self.form.second_spin_box.minimum(), 0,
|
||||||
'The minimum second should stay the same as the dialog')
|
'The minimum second should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.secondSpinBox.maximum(), 59,
|
self.assertEqual(self.form.second_spin_box.maximum(), 59,
|
||||||
'The maximum second should stay the same as the dialog')
|
'The maximum second should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.hourFinishSpinBox.minimum(), 0,
|
self.assertEqual(self.form.hour_finish_spin_box.minimum(), 0,
|
||||||
'The minimum finish hour should stay the same as the dialog')
|
'The minimum finish hour should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.hourFinishSpinBox.maximum(), 4,
|
self.assertEqual(self.form.hour_finish_spin_box.maximum(), 4,
|
||||||
'The maximum finish hour should stay the same as the dialog')
|
'The maximum finish hour should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.minuteFinishSpinBox.minimum(), 0,
|
self.assertEqual(self.form.minute_finish_spin_box.minimum(), 0,
|
||||||
'The minimum finish minute should stay the same as the dialog')
|
'The minimum finish minute should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.minuteFinishSpinBox.maximum(), 59,
|
self.assertEqual(self.form.minute_finish_spin_box.maximum(), 59,
|
||||||
'The maximum finish minute should stay the same as the dialog')
|
'The maximum finish minute should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.secondFinishSpinBox.minimum(), 0,
|
self.assertEqual(self.form.second_finish_spin_box.minimum(), 0,
|
||||||
'The minimum finish second should stay the same as the dialog')
|
'The minimum finish second should stay the same as the dialog')
|
||||||
self.assertEqual(self.form.secondFinishSpinBox.maximum(), 59,
|
self.assertEqual(self.form.second_finish_spin_box.maximum(), 59,
|
||||||
'The maximum finish second should stay the same as the dialog')
|
'The maximum finish second should stay the same as the dialog')
|
||||||
|
|
||||||
def time_display_test(self):
|
def time_display_test(self):
|
||||||
@ -75,22 +75,22 @@ class TestStartTimeDialog(TestCase):
|
|||||||
QtTest.QTest.mouseClick(ok_widget, QtCore.Qt.LeftButton)
|
QtTest.QTest.mouseClick(ok_widget, QtCore.Qt.LeftButton)
|
||||||
|
|
||||||
# THEN the following input values are returned
|
# THEN the following input values are returned
|
||||||
self.assertEqual(self.form.hourSpinBox.value(), 0)
|
self.assertEqual(self.form.hour_spin_box.value(), 0)
|
||||||
self.assertEqual(self.form.minuteSpinBox.value(), 1)
|
self.assertEqual(self.form.minute_spin_box.value(), 1)
|
||||||
self.assertEqual(self.form.secondSpinBox.value(), 1)
|
self.assertEqual(self.form.second_spin_box.value(), 1)
|
||||||
self.assertEqual(self.form.item['service_item'].start_time, 61, 'The start time should stay the same')
|
self.assertEqual(self.form.item['service_item'].start_time, 61, 'The start time should stay the same')
|
||||||
|
|
||||||
# WHEN displaying the UI, changing the time to 2min 3secs and pressing enter
|
# WHEN displaying the UI, changing the time to 2min 3secs and pressing enter
|
||||||
self.form.item = {'service_item': mocked_serviceitem}
|
self.form.item = {'service_item': mocked_serviceitem}
|
||||||
with patch('PyQt4.QtGui.QDialog.exec_'):
|
with patch('PyQt4.QtGui.QDialog.exec_'):
|
||||||
self.form.exec_()
|
self.form.exec_()
|
||||||
self.form.minuteSpinBox.setValue(2)
|
self.form.minute_spin_box.setValue(2)
|
||||||
self.form.secondSpinBox.setValue(3)
|
self.form.second_spin_box.setValue(3)
|
||||||
ok_widget = self.form.button_box.button(self.form.button_box.Ok)
|
ok_widget = self.form.button_box.button(self.form.button_box.Ok)
|
||||||
QtTest.QTest.mouseClick(ok_widget, QtCore.Qt.LeftButton)
|
QtTest.QTest.mouseClick(ok_widget, QtCore.Qt.LeftButton)
|
||||||
|
|
||||||
# THEN the following values are returned
|
# THEN the following values are returned
|
||||||
self.assertEqual(self.form.hourSpinBox.value(), 0)
|
self.assertEqual(self.form.hour_spin_box.value(), 0)
|
||||||
self.assertEqual(self.form.minuteSpinBox.value(), 2)
|
self.assertEqual(self.form.minute_spin_box.value(), 2)
|
||||||
self.assertEqual(self.form.secondSpinBox.value(), 3)
|
self.assertEqual(self.form.second_spin_box.value(), 3)
|
||||||
self.assertEqual(self.form.item['service_item'].start_time, 123, 'The start time should have changed')
|
self.assertEqual(self.form.item['service_item'].start_time, 123, 'The start time should have changed')
|
||||||
|
@ -27,20 +27,22 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
Interface tests to test the thememanagerhelper class and related methods.
|
Interface tests to test the themeManager class and related methods.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from tempfile import mkstemp
|
from tempfile import mkstemp
|
||||||
|
|
||||||
from openlp.core.common import Settings
|
from PyQt4 import QtGui
|
||||||
from openlp.core.ui import ThemeManagerHelper
|
|
||||||
|
from openlp.core.common import Registry, Settings
|
||||||
|
from openlp.core.ui import ThemeManager
|
||||||
from tests.functional import patch, MagicMock
|
from tests.functional import patch, MagicMock
|
||||||
|
|
||||||
|
|
||||||
class TestThemeManagerHelper(TestCase):
|
class TestThemeManager(TestCase):
|
||||||
"""
|
"""
|
||||||
Test the functions in the ThemeManagerHelp[er module
|
Test the functions in the ThemeManager module
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
@ -48,8 +50,9 @@ class TestThemeManagerHelper(TestCase):
|
|||||||
"""
|
"""
|
||||||
fd, self.ini_file = mkstemp('.ini')
|
fd, self.ini_file = mkstemp('.ini')
|
||||||
Settings().set_filename(self.ini_file)
|
Settings().set_filename(self.ini_file)
|
||||||
self.helper = ThemeManagerHelper()
|
self.app = QtGui.QApplication([])
|
||||||
self.helper.settings_section = "themes"
|
Registry.create()
|
||||||
|
self.theme_manager = ThemeManager()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""
|
"""
|
||||||
@ -57,30 +60,31 @@ class TestThemeManagerHelper(TestCase):
|
|||||||
"""
|
"""
|
||||||
os.unlink(self.ini_file)
|
os.unlink(self.ini_file)
|
||||||
os.unlink(Settings().fileName())
|
os.unlink(Settings().fileName())
|
||||||
|
del self.app
|
||||||
|
|
||||||
def test_initialise(self):
|
def initialise_test(self):
|
||||||
"""
|
"""
|
||||||
Test the thememanagerhelper initialise - basic test
|
Test the thememanager initialise - basic test
|
||||||
"""
|
"""
|
||||||
# GIVEN: A new a call to initialise
|
# GIVEN: A new a call to initialise
|
||||||
|
self.theme_manager.build_theme_path = MagicMock()
|
||||||
|
self.theme_manager.load_first_time_themes = MagicMock()
|
||||||
Settings().setValue('themes/global theme', 'my_theme')
|
Settings().setValue('themes/global theme', 'my_theme')
|
||||||
self.helper.build_theme_path = MagicMock()
|
|
||||||
self.helper.load_first_time_themes = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: the initialistion is run
|
# WHEN: the initialistion is run
|
||||||
self.helper.initialise()
|
self.theme_manager.bootstrap_initialise()
|
||||||
|
|
||||||
# THEN:
|
# THEN:
|
||||||
self.assertEqual(1, self.helper.build_theme_path.call_count,
|
self.assertEqual(1, self.theme_manager.build_theme_path.call_count,
|
||||||
'The function build_theme_path should have been called')
|
'The function build_theme_path should have been called')
|
||||||
self.assertEqual(1, self.helper.load_first_time_themes.call_count,
|
self.assertEqual(1, self.theme_manager.load_first_time_themes.call_count,
|
||||||
'The function load_first_time_themes should have been called only once')
|
'The function load_first_time_themes should have been called only once')
|
||||||
self.assertEqual(self.helper.global_theme, 'my_theme',
|
self.assertEqual(self.theme_manager.global_theme, 'my_theme',
|
||||||
'The global theme should have been set to my_theme')
|
'The global theme should have been set to my_theme')
|
||||||
|
|
||||||
def test_build_theme_path(self):
|
def build_theme_path_test(self):
|
||||||
"""
|
"""
|
||||||
Test the thememanagerhelper build_theme_path - basic test
|
Test the thememanager build_theme_path - basic test
|
||||||
"""
|
"""
|
||||||
# GIVEN: A new a call to initialise
|
# GIVEN: A new a call to initialise
|
||||||
with patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
|
with patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
|
||||||
@ -88,12 +92,28 @@ class TestThemeManagerHelper(TestCase):
|
|||||||
mocked_check_directory_exists.return_value = True
|
mocked_check_directory_exists.return_value = True
|
||||||
Settings().setValue('themes/global theme', 'my_theme')
|
Settings().setValue('themes/global theme', 'my_theme')
|
||||||
|
|
||||||
self.helper.theme_form = MagicMock()
|
self.theme_manager.theme_form = MagicMock()
|
||||||
#self.helper.load_first_time_themes = MagicMock()
|
self.theme_manager.load_first_time_themes = MagicMock()
|
||||||
|
|
||||||
# WHEN: the build_theme_path is run
|
# WHEN: the build_theme_path is run
|
||||||
self.helper.build_theme_path()
|
self.theme_manager.build_theme_path()
|
||||||
|
|
||||||
# THEN:
|
# THEN:
|
||||||
self.assertEqual(self.helper.path, self.helper.theme_form.path,
|
assert self.theme_manager.thumb_path.startswith(self.theme_manager.path) is True, \
|
||||||
'The theme path and the main path should be the same value')
|
'The thumb path and the main path should start with the same value'
|
||||||
|
|
||||||
|
def click_on_new_theme_test(self):
|
||||||
|
"""
|
||||||
|
Test the on_add_theme event handler is called by the UI
|
||||||
|
"""
|
||||||
|
# GIVEN: An initial form
|
||||||
|
Settings().setValue('themes/global theme', 'my_theme')
|
||||||
|
mocked_event = MagicMock()
|
||||||
|
self.theme_manager.on_add_theme = mocked_event
|
||||||
|
self.theme_manager.setup_ui(self.theme_manager)
|
||||||
|
|
||||||
|
# WHEN displaying the UI and pressing cancel
|
||||||
|
new_theme = self.theme_manager.toolbar.actions['newTheme']
|
||||||
|
new_theme.trigger()
|
||||||
|
|
||||||
|
assert mocked_event.call_count == 1, 'The on_add_theme method should have been called once'
|
Loading…
Reference in New Issue
Block a user