forked from openlp/openlp
Head
This commit is contained in:
commit
c8042f6023
@ -126,7 +126,8 @@ class OpenLP(QtGui.QApplication):
|
|||||||
# Correct stylesheet bugs
|
# Correct stylesheet bugs
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
|
base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
|
||||||
application_stylesheet = u'* {alternate-background-color: ' + base_color.name() + ';}\n'
|
application_stylesheet = \
|
||||||
|
u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
|
||||||
application_stylesheet += nt_repair_stylesheet
|
application_stylesheet += nt_repair_stylesheet
|
||||||
self.setStyleSheet(application_stylesheet)
|
self.setStyleSheet(application_stylesheet)
|
||||||
# show the splashscreen
|
# show the splashscreen
|
||||||
|
@ -37,6 +37,14 @@ from PyQt4 import QtCore, QtGui, Qt
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class ServiceItemContext(object):
|
||||||
|
"""
|
||||||
|
The context in which a Service Item is being generated
|
||||||
|
"""
|
||||||
|
Preview = 0
|
||||||
|
Live = 1
|
||||||
|
Service = 2
|
||||||
|
|
||||||
|
|
||||||
class ImageSource(object):
|
class ImageSource(object):
|
||||||
"""
|
"""
|
||||||
@ -395,4 +403,4 @@ from dockwidget import OpenLPDockWidget
|
|||||||
from imagemanager import ImageManager
|
from imagemanager import ImageManager
|
||||||
from renderer import Renderer
|
from renderer import Renderer
|
||||||
from mediamanageritem import MediaManagerItem
|
from mediamanageritem import MediaManagerItem
|
||||||
from openlp.core.utils.actions import ActionList
|
|
||||||
|
@ -36,7 +36,8 @@ import re
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \
|
from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \
|
||||||
StringContent, build_icon, translate, Receiver, ListWidgetWithDnD
|
StringContent, build_icon, translate, Receiver, ListWidgetWithDnD, \
|
||||||
|
ServiceItemContext
|
||||||
from openlp.core.lib.searchedit import SearchEdit
|
from openlp.core.lib.searchedit import SearchEdit
|
||||||
from openlp.core.lib.ui import UiStrings, create_widget_action, \
|
from openlp.core.lib.ui import UiStrings, create_widget_action, \
|
||||||
critical_error_message_box
|
critical_error_message_box
|
||||||
@ -459,7 +460,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def generateSlideData(self, serviceItem, item=None, xmlVersion=False,
|
def generateSlideData(self, serviceItem, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Live):
|
||||||
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
|
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
|
||||||
u'to be defined by the plugin')
|
u'to be defined by the plugin')
|
||||||
|
|
||||||
@ -521,6 +522,8 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
if serviceItem:
|
if serviceItem:
|
||||||
if not item_id:
|
if not item_id:
|
||||||
serviceItem.from_plugin = True
|
serviceItem.from_plugin = True
|
||||||
|
if remote:
|
||||||
|
serviceItem.will_auto_start = True
|
||||||
self.plugin.liveController.addServiceItem(serviceItem)
|
self.plugin.liveController.addServiceItem(serviceItem)
|
||||||
|
|
||||||
def createItemFromId(self, item_id):
|
def createItemFromId(self, item_id):
|
||||||
@ -548,7 +551,8 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
self.addToService(item)
|
self.addToService(item)
|
||||||
|
|
||||||
def addToService(self, item=None, replace=None, remote=False):
|
def addToService(self, item=None, replace=None, remote=False):
|
||||||
serviceItem = self.buildServiceItem(item, True, remote=remote)
|
serviceItem = self.buildServiceItem(item, True, remote=remote,
|
||||||
|
context=ServiceItemContext.Service)
|
||||||
if serviceItem:
|
if serviceItem:
|
||||||
serviceItem.from_plugin = False
|
serviceItem.from_plugin = False
|
||||||
self.plugin.serviceManager.addServiceItem(serviceItem,
|
self.plugin.serviceManager.addServiceItem(serviceItem,
|
||||||
@ -581,13 +585,15 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
unicode(translate('OpenLP.MediaManagerItem',
|
unicode(translate('OpenLP.MediaManagerItem',
|
||||||
'You must select a %s service item.')) % self.title)
|
'You must select a %s service item.')) % self.title)
|
||||||
|
|
||||||
def buildServiceItem(self, item=None, xmlVersion=False, remote=False):
|
def buildServiceItem(self, item=None, xmlVersion=False, remote=False,
|
||||||
|
context=ServiceItemContext.Live):
|
||||||
"""
|
"""
|
||||||
Common method for generating a service item
|
Common method for generating a service item
|
||||||
"""
|
"""
|
||||||
serviceItem = ServiceItem(self.plugin)
|
serviceItem = ServiceItem(self.plugin)
|
||||||
serviceItem.add_icon(self.plugin.iconPath)
|
serviceItem.add_icon(self.plugin.iconPath)
|
||||||
if self.generateSlideData(serviceItem, item, xmlVersion, remote):
|
if self.generateSlideData(serviceItem, item, xmlVersion, remote,
|
||||||
|
context):
|
||||||
return serviceItem
|
return serviceItem
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
@ -54,6 +54,64 @@ class ServiceItemType(object):
|
|||||||
class ItemCapabilities(object):
|
class ItemCapabilities(object):
|
||||||
"""
|
"""
|
||||||
Provides an enumeration of a service item's capabilities
|
Provides an enumeration of a service item's capabilities
|
||||||
|
|
||||||
|
``CanPreview``
|
||||||
|
The capability to allow the ServiceManager to add to the preview
|
||||||
|
tab when making the previous item live.
|
||||||
|
|
||||||
|
``CanEdit``
|
||||||
|
The capability to allow the ServiceManager to allow the item to be
|
||||||
|
edited
|
||||||
|
|
||||||
|
``CanMaintain``
|
||||||
|
The capability to allow the ServiceManager to allow the item to be
|
||||||
|
reordered.
|
||||||
|
|
||||||
|
``RequiresMedia``
|
||||||
|
Determines is the serviceItem needs a Media Player
|
||||||
|
|
||||||
|
``CanLoop``
|
||||||
|
The capability to allow the SlideController to allow the loop
|
||||||
|
processing.
|
||||||
|
|
||||||
|
``CanAppend``
|
||||||
|
The capability to allow the ServiceManager to add leaves to the
|
||||||
|
item
|
||||||
|
|
||||||
|
``NoLineBreaks``
|
||||||
|
The capability to remove lines breaks in the renderer
|
||||||
|
|
||||||
|
``OnLoadUpdate``
|
||||||
|
The capability to update MediaManager when a service Item is
|
||||||
|
loaded.
|
||||||
|
|
||||||
|
``AddIfNewItem``
|
||||||
|
Not Used
|
||||||
|
|
||||||
|
``ProvidesOwnDisplay``
|
||||||
|
The capability to tell the SlideController the service Item has a
|
||||||
|
different display.
|
||||||
|
|
||||||
|
``HasDetailedTitleDisplay``
|
||||||
|
ServiceItem provides a title
|
||||||
|
|
||||||
|
``HasVariableStartTime``
|
||||||
|
The capability to tell the ServiceManager that a change to start
|
||||||
|
time is possible.
|
||||||
|
|
||||||
|
``CanSoftBreak``
|
||||||
|
The capability to tell the renderer that Soft Break is allowed
|
||||||
|
|
||||||
|
``CanWordSplit``
|
||||||
|
The capability to tell the renderer that it can split words is
|
||||||
|
allowed
|
||||||
|
|
||||||
|
``HasBackgroundAudio``
|
||||||
|
That a audio file is present with the text.
|
||||||
|
|
||||||
|
``CanAutoStartForLive``
|
||||||
|
The capability to ignore the do not play if display blank flag.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
CanPreview = 1
|
CanPreview = 1
|
||||||
CanEdit = 2
|
CanEdit = 2
|
||||||
@ -70,6 +128,7 @@ class ItemCapabilities(object):
|
|||||||
CanSoftBreak = 13
|
CanSoftBreak = 13
|
||||||
CanWordSplit = 14
|
CanWordSplit = 14
|
||||||
HasBackgroundAudio = 15
|
HasBackgroundAudio = 15
|
||||||
|
CanAutoStartForLive = 16
|
||||||
|
|
||||||
|
|
||||||
class ServiceItem(object):
|
class ServiceItem(object):
|
||||||
@ -123,6 +182,7 @@ class ServiceItem(object):
|
|||||||
self.background_audio = []
|
self.background_audio = []
|
||||||
self.theme_overwritten = False
|
self.theme_overwritten = False
|
||||||
self.temporary_edit = False
|
self.temporary_edit = False
|
||||||
|
self.will_auto_start = False
|
||||||
self._new_item()
|
self._new_item()
|
||||||
|
|
||||||
def _new_item(self):
|
def _new_item(self):
|
||||||
@ -267,7 +327,7 @@ class ServiceItem(object):
|
|||||||
{u'title': file_name, u'image': image, u'path': path})
|
{u'title': file_name, u'image': image, u'path': path})
|
||||||
self._new_item()
|
self._new_item()
|
||||||
|
|
||||||
def get_service_repr(self):
|
def get_service_repr(self, lite_save):
|
||||||
"""
|
"""
|
||||||
This method returns some text which can be saved into the service
|
This method returns some text which can be saved into the service
|
||||||
file to represent this item.
|
file to represent this item.
|
||||||
@ -291,17 +351,24 @@ class ServiceItem(object):
|
|||||||
u'end_time': self.end_time,
|
u'end_time': self.end_time,
|
||||||
u'media_length': self.media_length,
|
u'media_length': self.media_length,
|
||||||
u'background_audio': self.background_audio,
|
u'background_audio': self.background_audio,
|
||||||
u'theme_overwritten': self.theme_overwritten
|
u'theme_overwritten': self.theme_overwritten,
|
||||||
|
u'will_auto_start': self.will_auto_start
|
||||||
}
|
}
|
||||||
service_data = []
|
service_data = []
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
service_data = [slide for slide in self._raw_frames]
|
service_data = [slide for slide in self._raw_frames]
|
||||||
elif self.service_item_type == ServiceItemType.Image:
|
elif self.service_item_type == ServiceItemType.Image:
|
||||||
|
if lite_save:
|
||||||
|
for slide in self._raw_frames:
|
||||||
|
service_data.append(
|
||||||
|
{u'title': slide[u'title'], u'path': slide[u'path']})
|
||||||
|
else:
|
||||||
service_data = [slide[u'title'] for slide in self._raw_frames]
|
service_data = [slide[u'title'] for slide in self._raw_frames]
|
||||||
elif self.service_item_type == ServiceItemType.Command:
|
elif self.service_item_type == ServiceItemType.Command:
|
||||||
for slide in self._raw_frames:
|
for slide in self._raw_frames:
|
||||||
service_data.append(
|
service_data.append(
|
||||||
{u'title': slide[u'title'], u'image': slide[u'image']})
|
{u'title': slide[u'title'], u'image': slide[u'image'],
|
||||||
|
u'path': slide[u'path']})
|
||||||
return {u'header': service_header, u'data': service_data}
|
return {u'header': service_header, u'data': service_data}
|
||||||
|
|
||||||
def set_from_service(self, serviceitem, path=None):
|
def set_from_service(self, serviceitem, path=None):
|
||||||
@ -313,7 +380,9 @@ class ServiceItem(object):
|
|||||||
The item to extract data from.
|
The item to extract data from.
|
||||||
|
|
||||||
``path``
|
``path``
|
||||||
Defaults to *None*. Any path data, usually for images.
|
Defaults to *None*. This is the service manager path for things
|
||||||
|
which have their files saved with them or None when the saved
|
||||||
|
service is lite and the original file paths need to be preserved..
|
||||||
"""
|
"""
|
||||||
log.debug(u'set_from_service called with path %s' % path)
|
log.debug(u'set_from_service called with path %s' % path)
|
||||||
header = serviceitem[u'serviceitem'][u'header']
|
header = serviceitem[u'serviceitem'][u'header']
|
||||||
@ -335,6 +404,7 @@ class ServiceItem(object):
|
|||||||
self.start_time = header.get(u'start_time', 0)
|
self.start_time = header.get(u'start_time', 0)
|
||||||
self.end_time = header.get(u'end_time', 0)
|
self.end_time = header.get(u'end_time', 0)
|
||||||
self.media_length = header.get(u'media_length', 0)
|
self.media_length = header.get(u'media_length', 0)
|
||||||
|
self.will_auto_start = header.get(u'will_auto_start', False)
|
||||||
if u'background_audio' in header:
|
if u'background_audio' in header:
|
||||||
self.background_audio = []
|
self.background_audio = []
|
||||||
for filename in header[u'background_audio']:
|
for filename in header[u'background_audio']:
|
||||||
@ -345,14 +415,24 @@ class ServiceItem(object):
|
|||||||
for slide in serviceitem[u'serviceitem'][u'data']:
|
for slide in serviceitem[u'serviceitem'][u'data']:
|
||||||
self._raw_frames.append(slide)
|
self._raw_frames.append(slide)
|
||||||
elif self.service_item_type == ServiceItemType.Image:
|
elif self.service_item_type == ServiceItemType.Image:
|
||||||
|
if path:
|
||||||
for text_image in serviceitem[u'serviceitem'][u'data']:
|
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||||
filename = os.path.join(path, text_image)
|
filename = os.path.join(path, text_image)
|
||||||
self.add_from_image(filename, text_image)
|
self.add_from_image(filename, text_image)
|
||||||
|
else:
|
||||||
|
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||||
|
self.add_from_image(text_image[u'path'],
|
||||||
|
text_image[u'title'])
|
||||||
elif self.service_item_type == ServiceItemType.Command:
|
elif self.service_item_type == ServiceItemType.Command:
|
||||||
for text_image in serviceitem[u'serviceitem'][u'data']:
|
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||||
filename = os.path.join(path, text_image[u'title'])
|
if path:
|
||||||
self.add_from_command(
|
self.add_from_command(
|
||||||
path, text_image[u'title'], text_image[u'image'])
|
path, text_image[u'title'], text_image[u'image'])
|
||||||
|
else:
|
||||||
|
self.add_from_command(
|
||||||
|
text_image[u'path'], text_image[u'title'],
|
||||||
|
text_image[u'image'])
|
||||||
|
|
||||||
self._new_item()
|
self._new_item()
|
||||||
|
|
||||||
def get_display_title(self):
|
def get_display_title(self):
|
||||||
@ -434,6 +514,17 @@ class ServiceItem(object):
|
|||||||
"""
|
"""
|
||||||
return self.service_item_type == ServiceItemType.Text
|
return self.service_item_type == ServiceItemType.Text
|
||||||
|
|
||||||
|
def set_media_length(self, length):
|
||||||
|
"""
|
||||||
|
Stores the media length of the item
|
||||||
|
|
||||||
|
``length``
|
||||||
|
The length of the media item
|
||||||
|
"""
|
||||||
|
self.media_length = length
|
||||||
|
if length > 0:
|
||||||
|
self.add_capability(ItemCapabilities.HasVariableStartTime)
|
||||||
|
|
||||||
def get_frames(self):
|
def get_frames(self):
|
||||||
"""
|
"""
|
||||||
Returns the frames for the ServiceItem
|
Returns the frames for the ServiceItem
|
||||||
@ -446,6 +537,8 @@ class ServiceItem(object):
|
|||||||
def get_rendered_frame(self, row):
|
def get_rendered_frame(self, row):
|
||||||
"""
|
"""
|
||||||
Returns the correct frame for a given list and renders it if required.
|
Returns the correct frame for a given list and renders it if required.
|
||||||
|
``row``
|
||||||
|
The service item slide to be returned
|
||||||
"""
|
"""
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
return self._display_frames[row][u'html'].split(u'\n')[0]
|
return self._display_frames[row][u'html'].split(u'\n')[0]
|
||||||
|
@ -61,6 +61,8 @@ class UiStrings(object):
|
|||||||
self.Add = translate('OpenLP.Ui', '&Add')
|
self.Add = translate('OpenLP.Ui', '&Add')
|
||||||
self.Advanced = translate('OpenLP.Ui', 'Advanced')
|
self.Advanced = translate('OpenLP.Ui', 'Advanced')
|
||||||
self.AllFiles = translate('OpenLP.Ui', 'All Files')
|
self.AllFiles = translate('OpenLP.Ui', 'All Files')
|
||||||
|
self.Automatic = translate('OpenLP.Ui', 'Automatic')
|
||||||
|
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
|
||||||
self.Bottom = translate('OpenLP.Ui', 'Bottom')
|
self.Bottom = translate('OpenLP.Ui', 'Bottom')
|
||||||
self.Browse = translate('OpenLP.Ui', 'Browse...')
|
self.Browse = translate('OpenLP.Ui', 'Browse...')
|
||||||
self.Cancel = translate('OpenLP.Ui', 'Cancel')
|
self.Cancel = translate('OpenLP.Ui', 'Cancel')
|
||||||
@ -69,6 +71,7 @@ class UiStrings(object):
|
|||||||
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
|
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
|
||||||
self.Continuous = translate('OpenLP.Ui', 'Continuous')
|
self.Continuous = translate('OpenLP.Ui', 'Continuous')
|
||||||
self.Default = unicode(translate('OpenLP.Ui', 'Default'))
|
self.Default = unicode(translate('OpenLP.Ui', 'Default'))
|
||||||
|
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
|
||||||
self.Delete = translate('OpenLP.Ui', '&Delete')
|
self.Delete = translate('OpenLP.Ui', '&Delete')
|
||||||
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
|
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
|
||||||
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
|
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
|
||||||
@ -106,7 +109,8 @@ class UiStrings(object):
|
|||||||
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
|
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
|
||||||
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
|
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
|
||||||
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
|
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
|
||||||
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
|
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
|
||||||
|
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
|
||||||
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. '
|
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. '
|
||||||
'Do you wish to continue?')
|
'Do you wish to continue?')
|
||||||
self.OpenService = translate('OpenLP.Ui', 'Open service.')
|
self.OpenService = translate('OpenLP.Ui', 'Open service.')
|
||||||
@ -465,9 +469,8 @@ def create_valign_selection_widgets(parent):
|
|||||||
label = QtGui.QLabel(parent)
|
label = QtGui.QLabel(parent)
|
||||||
label.setText(translate('OpenLP.Ui', '&Vertical Align:'))
|
label.setText(translate('OpenLP.Ui', '&Vertical Align:'))
|
||||||
combo_box = QtGui.QComboBox(parent)
|
combo_box = QtGui.QComboBox(parent)
|
||||||
combo_box.addItem(UiStrings().Top)
|
combo_box.addItems(
|
||||||
combo_box.addItem(UiStrings().Middle)
|
[UiStrings().Top, UiStrings().Middle, UiStrings().Bottom])
|
||||||
combo_box.addItem(UiStrings().Bottom)
|
|
||||||
label.setBuddy(combo_box)
|
label.setBuddy(combo_box)
|
||||||
return label, combo_box
|
return label, combo_box
|
||||||
|
|
||||||
@ -482,8 +485,7 @@ def find_and_set_in_combo_box(combo_box, value_to_find):
|
|||||||
``value_to_find``
|
``value_to_find``
|
||||||
The value to find
|
The value to find
|
||||||
"""
|
"""
|
||||||
index = combo_box.findText(value_to_find,
|
index = combo_box.findText(value_to_find, QtCore.Qt.MatchExactly)
|
||||||
QtCore.Qt.MatchExactly)
|
|
||||||
if index == -1:
|
if index == -1:
|
||||||
# Not Found.
|
# Not Found.
|
||||||
index = 0
|
index = 0
|
||||||
|
@ -72,6 +72,16 @@ class AlertLocation(object):
|
|||||||
Middle = 1
|
Middle = 1
|
||||||
Bottom = 2
|
Bottom = 2
|
||||||
|
|
||||||
|
class DisplayControllerType(object):
|
||||||
|
"""
|
||||||
|
This is an enumeration class which says where a display controller
|
||||||
|
originated from.
|
||||||
|
"""
|
||||||
|
Live = 0
|
||||||
|
Preview = 1
|
||||||
|
Plugin = 2
|
||||||
|
|
||||||
|
|
||||||
from firsttimeform import FirstTimeForm
|
from firsttimeform import FirstTimeForm
|
||||||
from firsttimelanguageform import FirstTimeLanguageForm
|
from firsttimelanguageform import FirstTimeLanguageForm
|
||||||
from themelayoutform import ThemeLayoutForm
|
from themelayoutform import ThemeLayoutForm
|
||||||
@ -82,7 +92,7 @@ from screen import ScreenList
|
|||||||
from maindisplay import MainDisplay, Display
|
from maindisplay import MainDisplay, Display
|
||||||
from servicenoteform import ServiceNoteForm
|
from servicenoteform import ServiceNoteForm
|
||||||
from serviceitemeditform import ServiceItemEditForm
|
from serviceitemeditform import ServiceItemEditForm
|
||||||
from slidecontroller import SlideController, Controller
|
from slidecontroller import SlideController, DisplayController
|
||||||
from splashscreen import SplashScreen
|
from splashscreen import SplashScreen
|
||||||
from generaltab import GeneralTab
|
from generaltab import GeneralTab
|
||||||
from themestab import ThemesTab
|
from themestab import ThemesTab
|
||||||
@ -98,4 +108,4 @@ from thememanager import ThemeManager
|
|||||||
|
|
||||||
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay',
|
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay',
|
||||||
'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager',
|
'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager',
|
||||||
'ServiceItemEditForm', u'FirstTimeForm']
|
'ServiceItemEditForm', 'FirstTimeForm']
|
||||||
|
@ -103,28 +103,22 @@ class AdvancedTab(SettingsTab):
|
|||||||
u'expandServiceItemCheckBox')
|
u'expandServiceItemCheckBox')
|
||||||
self.uiLayout.addRow(self.expandServiceItemCheckBox)
|
self.uiLayout.addRow(self.expandServiceItemCheckBox)
|
||||||
self.enableAutoCloseCheckBox = QtGui.QCheckBox(self.uiGroupBox)
|
self.enableAutoCloseCheckBox = QtGui.QCheckBox(self.uiGroupBox)
|
||||||
self.enableAutoCloseCheckBox.setObjectName(
|
self.enableAutoCloseCheckBox.setObjectName(u'enableAutoCloseCheckBox')
|
||||||
u'enableAutoCloseCheckBox')
|
|
||||||
self.uiLayout.addRow(self.enableAutoCloseCheckBox)
|
self.uiLayout.addRow(self.enableAutoCloseCheckBox)
|
||||||
self.leftLayout.addWidget(self.uiGroupBox)
|
self.leftLayout.addWidget(self.uiGroupBox)
|
||||||
# Default service name
|
# Default service name
|
||||||
self.serviceNameGroupBox = QtGui.QGroupBox(self.leftColumn)
|
self.serviceNameGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
self.serviceNameGroupBox.setObjectName(u'serviceNameGroupBox')
|
self.serviceNameGroupBox.setObjectName(u'serviceNameGroupBox')
|
||||||
self.serviceNameLayout = QtGui.QFormLayout(
|
self.serviceNameLayout = QtGui.QFormLayout(self.serviceNameGroupBox)
|
||||||
self.serviceNameGroupBox)
|
self.serviceNameCheckBox = QtGui.QCheckBox(self.serviceNameGroupBox)
|
||||||
self.serviceNameCheckBox = QtGui.QCheckBox(
|
|
||||||
self.serviceNameGroupBox)
|
|
||||||
self.serviceNameCheckBox.setObjectName(u'serviceNameCheckBox')
|
self.serviceNameCheckBox.setObjectName(u'serviceNameCheckBox')
|
||||||
self.serviceNameLayout.setObjectName(u'serviceNameLayout')
|
self.serviceNameLayout.setObjectName(u'serviceNameLayout')
|
||||||
self.serviceNameLayout.addRow(self.serviceNameCheckBox)
|
self.serviceNameLayout.addRow(self.serviceNameCheckBox)
|
||||||
self.serviceNameTimeLabel = QtGui.QLabel(self.serviceNameGroupBox)
|
self.serviceNameTimeLabel = QtGui.QLabel(self.serviceNameGroupBox)
|
||||||
self.serviceNameTimeLabel.setObjectName(u'serviceNameTimeLabel')
|
self.serviceNameTimeLabel.setObjectName(u'serviceNameTimeLabel')
|
||||||
self.serviceNameDay = QtGui.QComboBox(
|
self.serviceNameDay = QtGui.QComboBox(self.serviceNameGroupBox)
|
||||||
self.serviceNameGroupBox)
|
self.serviceNameDay.addItems([u'', u'', u'', u'', u'', u'', u'', u''])
|
||||||
self.serviceNameDay.addItems(
|
self.serviceNameDay.setObjectName(u'serviceNameDay')
|
||||||
[u'', u'', u'', u'', u'', u'', u'', u''])
|
|
||||||
self.serviceNameDay.setObjectName(
|
|
||||||
u'serviceNameDay')
|
|
||||||
self.serviceNameTime = QtGui.QTimeEdit(self.serviceNameGroupBox)
|
self.serviceNameTime = QtGui.QTimeEdit(self.serviceNameGroupBox)
|
||||||
self.serviceNameTime.setObjectName(u'serviceNameTime')
|
self.serviceNameTime.setObjectName(u'serviceNameTime')
|
||||||
self.serviceNameTimeHBox = QtGui.QHBoxLayout()
|
self.serviceNameTimeHBox = QtGui.QHBoxLayout()
|
||||||
@ -151,8 +145,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.serviceNameHBox.addWidget(self.serviceNameRevertButton)
|
self.serviceNameHBox.addWidget(self.serviceNameRevertButton)
|
||||||
self.serviceNameLayout.addRow(self.serviceNameLabel,
|
self.serviceNameLayout.addRow(self.serviceNameLabel,
|
||||||
self.serviceNameHBox)
|
self.serviceNameHBox)
|
||||||
self.serviceNameExampleLabel = QtGui.QLabel(
|
self.serviceNameExampleLabel = QtGui.QLabel(self.serviceNameGroupBox)
|
||||||
self.serviceNameGroupBox)
|
|
||||||
self.serviceNameExampleLabel.setObjectName(
|
self.serviceNameExampleLabel.setObjectName(
|
||||||
u'serviceNameExampleLabel')
|
u'serviceNameExampleLabel')
|
||||||
self.serviceNameExample = QtGui.QLabel(self.serviceNameGroupBox)
|
self.serviceNameExample = QtGui.QLabel(self.serviceNameGroupBox)
|
||||||
@ -202,8 +195,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.newDataDirectoryLabelHBox.setObjectName(
|
self.newDataDirectoryLabelHBox.setObjectName(
|
||||||
u'newDataDirectoryLabelHBox')
|
u'newDataDirectoryLabelHBox')
|
||||||
self.newDataDirectoryLabelHBox.addWidget(self.newDataDirectoryEdit)
|
self.newDataDirectoryLabelHBox.addWidget(self.newDataDirectoryEdit)
|
||||||
self.newDataDirectoryLabelHBox.addWidget(
|
self.newDataDirectoryLabelHBox.addWidget(self.dataDirectoryBrowseButton)
|
||||||
self.dataDirectoryBrowseButton)
|
|
||||||
self.newDataDirectoryLabelHBox.addWidget(
|
self.newDataDirectoryLabelHBox.addWidget(
|
||||||
self.dataDirectoryDefaultButton)
|
self.dataDirectoryDefaultButton)
|
||||||
self.dataDirectoryCopyCheckHBox = QtGui.QHBoxLayout()
|
self.dataDirectoryCopyCheckHBox = QtGui.QHBoxLayout()
|
||||||
@ -340,8 +332,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
Setup the interface translation strings.
|
Setup the interface translation strings.
|
||||||
"""
|
"""
|
||||||
self.tabTitleVisible = UiStrings().Advanced
|
self.tabTitleVisible = UiStrings().Advanced
|
||||||
self.uiGroupBox.setTitle(
|
self.uiGroupBox.setTitle(translate('OpenLP.AdvancedTab', 'UI Settings'))
|
||||||
translate('OpenLP.AdvancedTab', 'UI Settings'))
|
|
||||||
self.dataDirectoryGroupBox.setTitle(
|
self.dataDirectoryGroupBox.setTitle(
|
||||||
translate('OpenLP.AdvancedTab', 'Data Location'))
|
translate('OpenLP.AdvancedTab', 'Data Location'))
|
||||||
self.recentLabel.setText(
|
self.recentLabel.setText(
|
||||||
@ -477,7 +468,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
settings.value(u'enable exit confirmation',
|
settings.value(u'enable exit confirmation',
|
||||||
QtCore.QVariant(True)).toBool())
|
QtCore.QVariant(True)).toBool())
|
||||||
self.hideMouseCheckBox.setChecked(
|
self.hideMouseCheckBox.setChecked(
|
||||||
settings.value(u'hide mouse', QtCore.QVariant(False)).toBool())
|
settings.value(u'hide mouse', QtCore.QVariant(True)).toBool())
|
||||||
self.serviceNameDay.setCurrentIndex(
|
self.serviceNameDay.setCurrentIndex(
|
||||||
settings.value(u'default service day',
|
settings.value(u'default service day',
|
||||||
QtCore.QVariant(self.defaultServiceDay)).toInt()[0])
|
QtCore.QVariant(self.defaultServiceDay)).toInt()[0])
|
||||||
@ -504,8 +495,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.defaultColor = settings.value(u'default color',
|
self.defaultColor = settings.value(u'default color',
|
||||||
QtCore.QVariant(u'#ffffff')).toString()
|
QtCore.QVariant(u'#ffffff')).toString()
|
||||||
self.defaultFileEdit.setText(settings.value(u'default image',
|
self.defaultFileEdit.setText(settings.value(u'default image',
|
||||||
QtCore.QVariant(u':/graphics/openlp-splash-screen.png'))\
|
QtCore.QVariant(u':/graphics/openlp-splash-screen.png')).toString())
|
||||||
.toString())
|
|
||||||
self.slide_limits = settings.value(
|
self.slide_limits = settings.value(
|
||||||
u'slide limits', QtCore.QVariant(SlideLimits.End)).toInt()[0]
|
u'slide limits', QtCore.QVariant(SlideLimits.End)).toInt()[0]
|
||||||
if self.slide_limits == SlideLimits.End:
|
if self.slide_limits == SlideLimits.End:
|
||||||
@ -547,8 +537,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.currentDataPath = AppLocation.get_data_path()
|
self.currentDataPath = AppLocation.get_data_path()
|
||||||
log.warning(u'User requested data path set to default %s'
|
log.warning(u'User requested data path set to default %s'
|
||||||
% self.currentDataPath)
|
% self.currentDataPath)
|
||||||
self.dataDirectoryLabel.setText(os.path.abspath(
|
self.dataDirectoryLabel.setText(os.path.abspath(self.currentDataPath))
|
||||||
self.currentDataPath))
|
|
||||||
self.defaultColorButton.setStyleSheet(
|
self.defaultColorButton.setStyleSheet(
|
||||||
u'background-color: %s' % self.defaultColor)
|
u'background-color: %s' % self.defaultColor)
|
||||||
# Don't allow data directory move if running portable.
|
# Don't allow data directory move if running portable.
|
||||||
@ -662,8 +651,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
file_filters = u'%s;;%s (*.*) (*)' % (get_images_filter(),
|
file_filters = u'%s;;%s (*.*) (*)' % (get_images_filter(),
|
||||||
UiStrings().AllFiles)
|
UiStrings().AllFiles)
|
||||||
filename = QtGui.QFileDialog.getOpenFileName(self,
|
filename = QtGui.QFileDialog.getOpenFileName(self,
|
||||||
translate('OpenLP.AdvancedTab', 'Open File'), '',
|
translate('OpenLP.AdvancedTab', 'Open File'), '', file_filters)
|
||||||
file_filters)
|
|
||||||
if filename:
|
if filename:
|
||||||
self.defaultFileEdit.setText(filename)
|
self.defaultFileEdit.setText(filename)
|
||||||
self.defaultFileEdit.setFocus()
|
self.defaultFileEdit.setFocus()
|
||||||
@ -713,7 +701,8 @@ class AdvancedTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
new_data_path = AppLocation.get_directory(AppLocation.DataDir)
|
new_data_path = AppLocation.get_directory(AppLocation.DataDir)
|
||||||
if self.currentDataPath.lower() != new_data_path.lower():
|
if self.currentDataPath.lower() != new_data_path.lower():
|
||||||
# Make sure they want to change the data location back to the default.
|
# Make sure they want to change the data location back to the
|
||||||
|
# default.
|
||||||
answer = QtGui.QMessageBox.question(self,
|
answer = QtGui.QMessageBox.question(self,
|
||||||
translate('OpenLP.AdvancedTab', 'Reset Data Directory'),
|
translate('OpenLP.AdvancedTab', 'Reset Data Directory'),
|
||||||
translate('OpenLP.AdvancedTab',
|
translate('OpenLP.AdvancedTab',
|
||||||
|
@ -105,7 +105,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'config_screen_changed'), self.updateScreenListCombo)
|
QtCore.SIGNAL(u'config_screen_changed'), self.updateScreenListCombo)
|
||||||
|
|
||||||
def exec_(self, edit=False):
|
def exec_(self):
|
||||||
"""
|
"""
|
||||||
Run the wizard.
|
Run the wizard.
|
||||||
"""
|
"""
|
||||||
@ -271,8 +271,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
self._performWizard()
|
self._performWizard()
|
||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
Receiver.send_message(u'openlp_process_events')
|
Receiver.send_message(u'openlp_process_events')
|
||||||
Settings().setValue(u'general/has run wizard',
|
Settings().setValue(u'general/has run wizard', QtCore.QVariant(True))
|
||||||
QtCore.QVariant(True))
|
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def urlGetFile(self, url, fpath):
|
def urlGetFile(self, url, fpath):
|
||||||
@ -283,7 +282,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
block_count = 0
|
block_count = 0
|
||||||
block_size = 4096
|
block_size = 4096
|
||||||
urlfile = urllib2.urlopen(url)
|
urlfile = urllib2.urlopen(url)
|
||||||
filesize = urlfile.headers["Content-Length"]
|
|
||||||
filename = open(fpath, "wb")
|
filename = open(fpath, "wb")
|
||||||
# Download until finished or canceled.
|
# Download until finished or canceled.
|
||||||
while not self.downloadCancelled:
|
while not self.downloadCancelled:
|
||||||
@ -292,7 +290,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
break
|
break
|
||||||
filename.write(data)
|
filename.write(data)
|
||||||
block_count += 1
|
block_count += 1
|
||||||
self._downloadProgress(block_count, block_size, filesize)
|
self._downloadProgress(block_count, block_size)
|
||||||
filename.close()
|
filename.close()
|
||||||
# Delete file if cancelled, it may be a partial file.
|
# Delete file if cancelled, it may be a partial file.
|
||||||
if self.downloadCancelled:
|
if self.downloadCancelled:
|
||||||
@ -320,7 +318,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
meta = site.info()
|
meta = site.info()
|
||||||
return int(meta.getheaders("Content-Length")[0])
|
return int(meta.getheaders("Content-Length")[0])
|
||||||
|
|
||||||
def _downloadProgress(self, count, block_size, total_size):
|
def _downloadProgress(self, count, block_size):
|
||||||
increment = (count * block_size) - self.previous_size
|
increment = (count * block_size) - self.previous_size
|
||||||
self._incrementProgressBar(None, increment)
|
self._incrementProgressBar(None, increment)
|
||||||
self.previous_size = count * block_size
|
self.previous_size = count * block_size
|
||||||
|
@ -327,7 +327,7 @@ class MainDisplay(Display):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'image to display')
|
log.debug(u'image to display')
|
||||||
image = self.imageManager.getImageBytes(path, ImageSource.ImagePlugin)
|
image = self.imageManager.getImageBytes(path, ImageSource.ImagePlugin)
|
||||||
self.controller.mediaController.video_reset(self.controller)
|
self.controller.mediaController.media_reset(self.controller)
|
||||||
self.displayImage(image)
|
self.displayImage(image)
|
||||||
|
|
||||||
def displayImage(self, image):
|
def displayImage(self, image):
|
||||||
@ -498,7 +498,7 @@ class MainDisplay(Display):
|
|||||||
Hide mouse cursor when moved over display.
|
Hide mouse cursor when moved over display.
|
||||||
"""
|
"""
|
||||||
if Settings().value(u'advanced/hide mouse',
|
if Settings().value(u'advanced/hide mouse',
|
||||||
QtCore.QVariant(False)).toBool():
|
QtCore.QVariant(True)).toBool():
|
||||||
self.setCursor(QtCore.Qt.BlankCursor)
|
self.setCursor(QtCore.Qt.BlankCursor)
|
||||||
self.frame.evaluateJavaScript('document.body.style.cursor = "none"')
|
self.frame.evaluateJavaScript('document.body.style.cursor = "none"')
|
||||||
else:
|
else:
|
||||||
|
@ -395,7 +395,7 @@ class Ui_MainWindow(object):
|
|||||||
"""
|
"""
|
||||||
Set up the translation system
|
Set up the translation system
|
||||||
"""
|
"""
|
||||||
mainWindow.mainTitle = UiStrings().OLPV2
|
mainWindow.mainTitle = UiStrings().OLPV2x
|
||||||
mainWindow.setWindowTitle(mainWindow.mainTitle)
|
mainWindow.setWindowTitle(mainWindow.mainTitle)
|
||||||
self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
|
self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
|
||||||
self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))
|
self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))
|
||||||
@ -576,6 +576,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.headerSection = u'SettingsImport'
|
self.headerSection = u'SettingsImport'
|
||||||
self.serviceNotSaved = False
|
self.serviceNotSaved = False
|
||||||
self.aboutForm = AboutForm(self)
|
self.aboutForm = AboutForm(self)
|
||||||
|
self.mediaController = MediaController(self)
|
||||||
self.settingsForm = SettingsForm(self, self)
|
self.settingsForm = SettingsForm(self, self)
|
||||||
self.formattingTagForm = FormattingTagForm(self)
|
self.formattingTagForm = FormattingTagForm(self)
|
||||||
self.shortcutForm = ShortcutListForm(self)
|
self.shortcutForm = ShortcutListForm(self)
|
||||||
@ -585,9 +586,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.pluginManager = PluginManager(plugin_path)
|
self.pluginManager = PluginManager(plugin_path)
|
||||||
self.pluginHelpers = {}
|
self.pluginHelpers = {}
|
||||||
self.imageManager = ImageManager()
|
self.imageManager = ImageManager()
|
||||||
self.mediaController = MediaController(self)
|
|
||||||
# Set up the interface
|
# Set up the interface
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
# Register the active media players and suffixes
|
||||||
|
self.mediaController.check_available_media_players()
|
||||||
# Load settings after setupUi so default UI sizes are overwritten
|
# Load settings after setupUi so default UI sizes are overwritten
|
||||||
self.loadSettings()
|
self.loadSettings()
|
||||||
# Once settings are loaded update the menu with the recent files.
|
# Once settings are loaded update the menu with the recent files.
|
||||||
@ -1169,7 +1171,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
if self.serviceManagerContents.isModified():
|
if self.serviceManagerContents.isModified():
|
||||||
ret = self.serviceManagerContents.saveModifiedService()
|
ret = self.serviceManagerContents.saveModifiedService()
|
||||||
if ret == QtGui.QMessageBox.Save:
|
if ret == QtGui.QMessageBox.Save:
|
||||||
if self.serviceManagerContents.saveFile():
|
if self.serviceManagerContents.decideSaveMethod():
|
||||||
self.cleanUp()
|
self.cleanUp()
|
||||||
event.accept()
|
event.accept()
|
||||||
else:
|
else:
|
||||||
|
@ -47,7 +47,7 @@ class MediaState(object):
|
|||||||
|
|
||||||
class MediaType(object):
|
class MediaType(object):
|
||||||
"""
|
"""
|
||||||
An enumeration of possibible Media Types
|
An enumeration of possible Media Types
|
||||||
"""
|
"""
|
||||||
Unused = 0
|
Unused = 0
|
||||||
Audio = 1
|
Audio = 1
|
||||||
@ -59,7 +59,7 @@ class MediaType(object):
|
|||||||
|
|
||||||
class MediaInfo(object):
|
class MediaInfo(object):
|
||||||
"""
|
"""
|
||||||
This class hold the media related infos
|
This class hold the media related info
|
||||||
"""
|
"""
|
||||||
file_info = None
|
file_info = None
|
||||||
volume = 100
|
volume = 100
|
||||||
@ -72,30 +72,26 @@ class MediaInfo(object):
|
|||||||
|
|
||||||
def get_media_players():
|
def get_media_players():
|
||||||
"""
|
"""
|
||||||
This method extract the configured media players and overridden player from
|
This method extracts the configured media players and overridden player
|
||||||
the settings.
|
from the settings.
|
||||||
|
|
||||||
``players_list``
|
|
||||||
A list with all active media players.
|
|
||||||
|
|
||||||
``overridden_player``
|
|
||||||
Here an special media player is chosen for all media actions.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'get_media_players')
|
log.debug(u'get_media_players')
|
||||||
players = unicode(Settings().value(u'media/players').toString())
|
saved_players = unicode(Settings().value(u'media/players').toString())
|
||||||
if not players:
|
if not saved_players:
|
||||||
players = u'webkit'
|
# we must always have a player and Webkit is the core one.
|
||||||
|
saved_players = u'webkit'
|
||||||
reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
|
reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
|
||||||
if Settings().value(u'media/override player',
|
if Settings().value(u'media/override player',
|
||||||
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == QtCore.Qt.Checked:
|
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == QtCore.Qt.Checked:
|
||||||
if reg_ex.exactMatch(players):
|
if reg_ex.exactMatch(saved_players):
|
||||||
overridden_player = u'%s' % reg_ex.cap(1)
|
overridden_player = u'%s' % reg_ex.cap(1)
|
||||||
else:
|
else:
|
||||||
overridden_player = u'auto'
|
overridden_player = u'auto'
|
||||||
else:
|
else:
|
||||||
overridden_player = u''
|
overridden_player = u''
|
||||||
players_list = players.replace(u'[', u'').replace(u']', u'').split(u',')
|
saved_players_list = saved_players.replace(u'[', u'').\
|
||||||
return players_list, overridden_player
|
replace(u']',u'').split(u',')
|
||||||
|
return saved_players_list, overridden_player
|
||||||
|
|
||||||
|
|
||||||
def set_media_players(players_list, overridden_player=u'auto'):
|
def set_media_players(players_list, overridden_player=u'auto'):
|
||||||
@ -118,3 +114,4 @@ def set_media_players(players_list, overridden_player=u'auto'):
|
|||||||
Settings().setValue(u'media/players', QtCore.QVariant(players))
|
Settings().setValue(u'media/players', QtCore.QVariant(players))
|
||||||
|
|
||||||
from mediacontroller import MediaController
|
from mediacontroller import MediaController
|
||||||
|
from playertab import PlayerTab
|
||||||
|
@ -34,11 +34,12 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import OpenLPToolbar, Receiver, translate
|
from openlp.core.lib import OpenLPToolbar, Receiver, translate
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.lib.mediaplayer import MediaPlayer
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
|
||||||
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, \
|
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, \
|
||||||
get_media_players, set_media_players
|
get_media_players, set_media_players
|
||||||
|
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||||
from openlp.core.utils import AppLocation
|
from openlp.core.utils import AppLocation
|
||||||
|
from openlp.core.ui import DisplayControllerType
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -46,68 +47,104 @@ class MediaController(object):
|
|||||||
"""
|
"""
|
||||||
The implementation of the Media Controller. The Media Controller adds an own
|
The implementation of the Media Controller. The Media Controller adds an own
|
||||||
class for every Player. Currently these are QtWebkit, Phonon and Vlc.
|
class for every Player. Currently these are QtWebkit, Phonon and Vlc.
|
||||||
"""
|
|
||||||
|
|
||||||
|
displayControllers are an array of controllers keyed on the
|
||||||
|
slidecontroller or plugin which built them. ControllerType is the class
|
||||||
|
containing the key values.
|
||||||
|
|
||||||
|
mediaPlayers are an array of media players keyed on player name.
|
||||||
|
|
||||||
|
currentMediaPlayer is an array of player instances keyed on ControllerType.
|
||||||
|
|
||||||
|
"""
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
self.parent = parent
|
self.mainWindow = parent
|
||||||
self.mediaPlayers = {}
|
self.mediaPlayers = {}
|
||||||
self.controller = []
|
self.displayControllers = {}
|
||||||
self.curDisplayMediaPlayer = {}
|
self.currentMediaPlayer = {}
|
||||||
# Timer for video state
|
# Timer for video state
|
||||||
self.timer = QtCore.QTimer()
|
self.timer = QtCore.QTimer()
|
||||||
self.timer.setInterval(200)
|
self.timer.setInterval(200)
|
||||||
self.withLivePreview = False
|
|
||||||
self.check_available_media_players()
|
|
||||||
# Signals
|
# Signals
|
||||||
QtCore.QObject.connect(self.timer,
|
QtCore.QObject.connect(self.timer,
|
||||||
QtCore.SIGNAL("timeout()"), self.video_state)
|
QtCore.SIGNAL("timeout()"), self.media_state)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'playbackPlay'), self.video_play)
|
QtCore.SIGNAL(u'playbackPlay'), self.media_play_msg)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'playbackPause'), self.video_pause)
|
QtCore.SIGNAL(u'playbackPause'), self.media_pause_msg)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'playbackStop'), self.video_stop)
|
QtCore.SIGNAL(u'playbackStop'), self.media_stop_msg)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'seekSlider'), self.video_seek)
|
QtCore.SIGNAL(u'seekSlider'), self.media_seek)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'volumeSlider'), self.video_volume)
|
QtCore.SIGNAL(u'volumeSlider'), self.media_volume)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'media_hide'), self.video_hide)
|
QtCore.SIGNAL(u'media_hide'), self.media_hide)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'media_blank'), self.video_blank)
|
QtCore.SIGNAL(u'media_blank'), self.media_blank)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'media_unblank'), self.video_unblank)
|
QtCore.SIGNAL(u'media_unblank'), self.media_unblank)
|
||||||
# Signals for background video
|
# Signals for background video
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'songs_hide'), self.video_hide)
|
QtCore.SIGNAL(u'songs_hide'), self.media_hide)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'songs_unblank'), self.video_unblank)
|
QtCore.SIGNAL(u'songs_unblank'), self.media_unblank)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.set_active_players)
|
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self._set_active_players)
|
||||||
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
QtCore.SIGNAL(u'mediaitem_suffixes'),
|
||||||
|
self._generate_extensions_lists)
|
||||||
|
|
||||||
def set_active_players(self):
|
def _set_active_players(self):
|
||||||
|
"""
|
||||||
|
Set the active players and available media files
|
||||||
|
"""
|
||||||
savedPlayers = get_media_players()[0]
|
savedPlayers = get_media_players()[0]
|
||||||
for player in self.mediaPlayers.keys():
|
for player in self.mediaPlayers.keys():
|
||||||
self.mediaPlayers[player].isActive = player in savedPlayers
|
self.mediaPlayers[player].isActive = player in savedPlayers
|
||||||
|
|
||||||
def register_controllers(self, controller):
|
def _generate_extensions_lists(self):
|
||||||
"""
|
"""
|
||||||
Register each media Player controller (Webkit, Phonon, etc) and store
|
Set the active players and available media files
|
||||||
|
"""
|
||||||
|
self.audio_extensions_list = []
|
||||||
|
for player in self.mediaPlayers.values():
|
||||||
|
if player.isActive:
|
||||||
|
for item in player.audio_extensions_list:
|
||||||
|
if not item in self.audio_extensions_list:
|
||||||
|
self.audio_extensions_list.append(item)
|
||||||
|
self.mainWindow.serviceManagerContents. \
|
||||||
|
supportedSuffixes(item[2:])
|
||||||
|
self.video_extensions_list = []
|
||||||
|
for player in self.mediaPlayers.values():
|
||||||
|
if player.isActive:
|
||||||
|
for item in player.video_extensions_list:
|
||||||
|
if item not in self.video_extensions_list:
|
||||||
|
self.video_extensions_list.extend(item)
|
||||||
|
self.mainWindow.serviceManagerContents. \
|
||||||
|
supportedSuffixes(item[2:])
|
||||||
|
|
||||||
|
def register_players(self, player):
|
||||||
|
"""
|
||||||
|
Register each media Player (Webkit, Phonon, etc) and store
|
||||||
for later use
|
for later use
|
||||||
|
|
||||||
|
``player``
|
||||||
|
Individual player class which has been enabled
|
||||||
"""
|
"""
|
||||||
self.mediaPlayers[controller.name] = controller
|
self.mediaPlayers[player.name] = player
|
||||||
|
|
||||||
def check_available_media_players(self):
|
def check_available_media_players(self):
|
||||||
"""
|
"""
|
||||||
Check to see if we have any media Player's available. If Not do not
|
Check to see if we have any media Player's available.
|
||||||
install the plugin.
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'check_available_media_players')
|
log.debug(u'_check_available_media_players')
|
||||||
controller_dir = os.path.join(
|
controller_dir = os.path.join(
|
||||||
AppLocation.get_directory(AppLocation.AppDir),
|
AppLocation.get_directory(AppLocation.AppDir),
|
||||||
u'core', u'ui', u'media')
|
u'core', u'ui', u'media')
|
||||||
for filename in os.listdir(controller_dir):
|
for filename in os.listdir(controller_dir):
|
||||||
if filename.endswith(u'player.py'):
|
if filename.endswith(u'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 = u'openlp.core.ui.media.' + \
|
modulename = u'openlp.core.ui.media.' + \
|
||||||
@ -120,10 +157,10 @@ class MediaController(object):
|
|||||||
except (ImportError, OSError):
|
except (ImportError, OSError):
|
||||||
log.warn(u'Failed to import %s on path %s',
|
log.warn(u'Failed to import %s on path %s',
|
||||||
modulename, path)
|
modulename, path)
|
||||||
controller_classes = MediaPlayer.__subclasses__()
|
player_classes = MediaPlayer.__subclasses__()
|
||||||
for controller_class in controller_classes:
|
for player_class in player_classes:
|
||||||
controller = controller_class(self)
|
player = player_class(self)
|
||||||
self.register_controllers(controller)
|
self.register_players(player)
|
||||||
if not self.mediaPlayers:
|
if not self.mediaPlayers:
|
||||||
return False
|
return False
|
||||||
savedPlayers, overriddenPlayer = get_media_players()
|
savedPlayers, overriddenPlayer = get_media_players()
|
||||||
@ -134,31 +171,33 @@ class MediaController(object):
|
|||||||
for invalidPlayer in invalidMediaPlayers:
|
for invalidPlayer in invalidMediaPlayers:
|
||||||
savedPlayers.remove(invalidPlayer)
|
savedPlayers.remove(invalidPlayer)
|
||||||
set_media_players(savedPlayers, overriddenPlayer)
|
set_media_players(savedPlayers, overriddenPlayer)
|
||||||
self.set_active_players()
|
self._set_active_players()
|
||||||
|
self._generate_extensions_lists()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def video_state(self):
|
def media_state(self):
|
||||||
"""
|
"""
|
||||||
Check if there is a running media Player and do updating stuff (e.g.
|
Check if there is a running media Player and do updating stuff (e.g.
|
||||||
update the UI)
|
update the UI)
|
||||||
"""
|
"""
|
||||||
if not self.curDisplayMediaPlayer.keys():
|
if not self.currentMediaPlayer.keys():
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
else:
|
else:
|
||||||
any_active = False
|
any_active = False
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
for source in self.currentMediaPlayer.keys():
|
||||||
self.curDisplayMediaPlayer[display].resize(display)
|
display = self._define_display(self.displayControllers[source])
|
||||||
self.curDisplayMediaPlayer[display].update_ui(display)
|
self.currentMediaPlayer[source].resize(display)
|
||||||
if self.curDisplayMediaPlayer[display].state == \
|
self.currentMediaPlayer[source].update_ui(display)
|
||||||
|
if self.currentMediaPlayer[source].state == \
|
||||||
MediaState.Playing:
|
MediaState.Playing:
|
||||||
any_active = True
|
any_active = True
|
||||||
# There are still any active players - no need to stop timer.
|
# There are still any active players - no need to stop timer.
|
||||||
if any_active:
|
if any_active:
|
||||||
return
|
return
|
||||||
|
# no players are active anymore
|
||||||
# No players are active anymore.
|
for source in self.currentMediaPlayer.keys():
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
if self.currentMediaPlayer[source].state != MediaState.Paused:
|
||||||
if self.curDisplayMediaPlayer[display].state != MediaState.Paused:
|
display = self._define_display(self.displayControllers[source])
|
||||||
display.controller.seekSlider.setSliderPosition(0)
|
display.controller.seekSlider.setSliderPosition(0)
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
|
|
||||||
@ -192,14 +231,22 @@ class MediaController(object):
|
|||||||
html += player.get_media_display_html()
|
html += player.get_media_display_html()
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def add_controller_items(self, controller, control_panel):
|
def register_controller(self, controller):
|
||||||
self.controller.append(controller)
|
|
||||||
self.setup_generic_controls(controller, control_panel)
|
|
||||||
self.setup_special_controls(controller, control_panel)
|
|
||||||
|
|
||||||
def setup_generic_controls(self, controller, control_panel):
|
|
||||||
"""
|
"""
|
||||||
Add generic media control items (valid for all types of medias)
|
Registers media controls where the players will be placed to run.
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
The controller where a player will be placed
|
||||||
|
"""
|
||||||
|
self.displayControllers[controller.controllerType] = controller
|
||||||
|
self.setup_generic_controls(controller)
|
||||||
|
|
||||||
|
def setup_generic_controls(self, controller):
|
||||||
|
"""
|
||||||
|
Set up controls on the control_panel for a given controller
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
controller.media_info = MediaInfo()
|
controller.media_info = MediaInfo()
|
||||||
# Build a Media ToolBar
|
# Build a Media ToolBar
|
||||||
@ -212,7 +259,8 @@ class MediaController(object):
|
|||||||
controller.mediabar.addToolbarAction(u'playbackPause',
|
controller.mediabar.addToolbarAction(u'playbackPause',
|
||||||
text=u'media_playback_pause',
|
text=u'media_playback_pause',
|
||||||
icon=u':/slides/media_playback_pause.png',
|
icon=u':/slides/media_playback_pause.png',
|
||||||
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
|
tooltip=translate('OpenLP.SlideController',
|
||||||
|
'Pause playing media.'),
|
||||||
triggers=controller.sendToPlugins)
|
triggers=controller.sendToPlugins)
|
||||||
controller.mediabar.addToolbarAction(u'playbackStop',
|
controller.mediabar.addToolbarAction(u'playbackStop',
|
||||||
text=u'media_playback_stop',
|
text=u'media_playback_stop',
|
||||||
@ -241,7 +289,7 @@ class MediaController(object):
|
|||||||
controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24))
|
controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24))
|
||||||
controller.volumeSlider.setObjectName(u'volumeSlider')
|
controller.volumeSlider.setObjectName(u'volumeSlider')
|
||||||
controller.mediabar.addToolbarWidget(controller.volumeSlider)
|
controller.mediabar.addToolbarWidget(controller.volumeSlider)
|
||||||
control_panel.addWidget(controller.mediabar)
|
controller.controllerLayout.addWidget(controller.mediabar)
|
||||||
controller.mediabar.setVisible(False)
|
controller.mediabar.setVisible(False)
|
||||||
# Signals
|
# Signals
|
||||||
QtCore.QObject.connect(controller.seekSlider,
|
QtCore.QObject.connect(controller.seekSlider,
|
||||||
@ -249,75 +297,96 @@ class MediaController(object):
|
|||||||
QtCore.QObject.connect(controller.volumeSlider,
|
QtCore.QObject.connect(controller.volumeSlider,
|
||||||
QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
|
QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
|
||||||
|
|
||||||
def setup_special_controls(self, controller, control_panel):
|
|
||||||
"""
|
|
||||||
Special media Toolbars will be created here (e.g. for DVD Playback)
|
|
||||||
"""
|
|
||||||
controller.media_info = MediaInfo()
|
|
||||||
# TODO: add Toolbar for DVD, ...
|
|
||||||
|
|
||||||
def setup_display(self, display):
|
def setup_display(self, display, preview):
|
||||||
"""
|
"""
|
||||||
After a new display is configured, all media related widget will be
|
After a new display is configured, all media related widget will be
|
||||||
created too
|
created too
|
||||||
|
|
||||||
|
``display``
|
||||||
|
Display on which the output is to be played
|
||||||
|
|
||||||
|
``preview``
|
||||||
|
Whether the display is a main or preview display
|
||||||
"""
|
"""
|
||||||
# clean up possible running old media files
|
# clean up possible running old media files
|
||||||
self.finalise()
|
self.finalise()
|
||||||
# update player status
|
# update player status
|
||||||
self.set_active_players()
|
self._set_active_players()
|
||||||
display.hasAudio = True
|
display.hasAudio = True
|
||||||
if not self.withLivePreview and \
|
if display.isLive and preview:
|
||||||
display == self.parent.liveController.previewDisplay:
|
|
||||||
return
|
return
|
||||||
if display == self.parent.previewController.previewDisplay or \
|
if preview:
|
||||||
display == self.parent.liveController.previewDisplay:
|
|
||||||
display.hasAudio = False
|
display.hasAudio = False
|
||||||
for player in self.mediaPlayers.values():
|
for player in self.mediaPlayers.values():
|
||||||
if player.isActive:
|
if player.isActive:
|
||||||
player.setup(display)
|
player.setup(display)
|
||||||
|
|
||||||
def set_controls_visible(self, controller, value):
|
def set_controls_visible(self, controller, value):
|
||||||
|
"""
|
||||||
|
After a new display is configured, all media related widget will be
|
||||||
|
created too
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
The controller on which controls act.
|
||||||
|
|
||||||
|
``value``
|
||||||
|
control name to be changed.
|
||||||
|
"""
|
||||||
# Generic controls
|
# Generic controls
|
||||||
controller.mediabar.setVisible(value)
|
controller.mediabar.setVisible(value)
|
||||||
if controller.isLive and controller.display:
|
if controller.isLive and controller.display:
|
||||||
if self.curDisplayMediaPlayer and value:
|
if self.currentMediaPlayer and value:
|
||||||
if self.curDisplayMediaPlayer[controller.display] != \
|
if self.currentMediaPlayer[controller.controllerType] != \
|
||||||
self.mediaPlayers[u'webkit']:
|
self.mediaPlayers[u'webkit']:
|
||||||
controller.display.setTransparency(False)
|
controller.display.setTransparency(False)
|
||||||
# Special controls: Here media type specific Controls will be enabled
|
|
||||||
# (e.g. for DVD control, ...)
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
def resize(self, controller, display, player):
|
def resize(self, display, player):
|
||||||
"""
|
"""
|
||||||
After Mainwindow changes or Splitter moved all related media widgets
|
After Mainwindow changes or Splitter moved all related media widgets
|
||||||
have to be resized
|
have to be resized
|
||||||
|
|
||||||
|
``display``
|
||||||
|
The display on which output is playing.
|
||||||
|
|
||||||
|
``player``
|
||||||
|
The player which is doing the playing.
|
||||||
"""
|
"""
|
||||||
player.resize(display)
|
player.resize(display)
|
||||||
|
|
||||||
def video(self, controller, file, muted, isBackground, hidden=False,
|
def video(self, source, serviceItem, hidden=False, videoBehindText=False):
|
||||||
isInfo=False, controlsVisible=True):
|
|
||||||
"""
|
"""
|
||||||
Loads and starts a video to run with the option of sound
|
Loads and starts a video to run with the option of sound
|
||||||
|
|
||||||
|
``source``
|
||||||
|
Where the call originated form
|
||||||
|
|
||||||
|
``serviceItem``
|
||||||
|
The player which is doing the playing
|
||||||
|
|
||||||
|
``hidden``
|
||||||
|
The player which is doing the playing
|
||||||
|
|
||||||
|
``videoBehindText``
|
||||||
|
Is the video to be played behind text.
|
||||||
"""
|
"""
|
||||||
log.debug(u'video')
|
log.debug(u'video')
|
||||||
isValid = False
|
isValid = False
|
||||||
|
controller = self.displayControllers[source]
|
||||||
# stop running videos
|
# stop running videos
|
||||||
self.video_reset(controller)
|
self.media_reset(controller)
|
||||||
controller.media_info = MediaInfo()
|
controller.media_info = MediaInfo()
|
||||||
if muted:
|
if videoBehindText:
|
||||||
controller.media_info.volume = 0
|
controller.media_info.volume = 0
|
||||||
|
controller.media_info.is_background = True
|
||||||
else:
|
else:
|
||||||
controller.media_info.volume = controller.volumeSlider.value()
|
controller.media_info.volume = controller.volumeSlider.value()
|
||||||
controller.media_info.file_info = QtCore.QFileInfo(file)
|
controller.media_info.is_background = False
|
||||||
controller.media_info.is_background = isBackground
|
controller.media_info.file_info = \
|
||||||
display = None
|
QtCore.QFileInfo(serviceItem.get_frame_path())
|
||||||
|
display = self._define_display(controller)
|
||||||
if controller.isLive:
|
if controller.isLive:
|
||||||
if self.withLivePreview and controller.previewDisplay:
|
isValid = self._check_file_type(controller, display, serviceItem)
|
||||||
display = controller.previewDisplay
|
|
||||||
isValid = self.check_file_type(controller, display)
|
|
||||||
display = controller.display
|
|
||||||
isValid = self.check_file_type(controller, display)
|
|
||||||
display.override[u'theme'] = u''
|
display.override[u'theme'] = u''
|
||||||
display.override[u'video'] = True
|
display.override[u'video'] = True
|
||||||
if controller.media_info.is_background:
|
if controller.media_info.is_background:
|
||||||
@ -327,10 +396,9 @@ class MediaController(object):
|
|||||||
else:
|
else:
|
||||||
controller.media_info.start_time = \
|
controller.media_info.start_time = \
|
||||||
display.serviceItem.start_time
|
display.serviceItem.start_time
|
||||||
controller.media_info.end_time = display.serviceItem.end_time
|
controller.media_info.end_time = serviceItem.end_time
|
||||||
elif controller.previewDisplay:
|
elif controller.previewDisplay:
|
||||||
display = controller.previewDisplay
|
isValid = self._check_file_type(controller, display, serviceItem)
|
||||||
isValid = self.check_file_type(controller, display)
|
|
||||||
if not isValid:
|
if not isValid:
|
||||||
# Media could not be loaded correctly
|
# Media could not be loaded correctly
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
@ -347,33 +415,74 @@ class MediaController(object):
|
|||||||
# Preview requested
|
# Preview requested
|
||||||
if not controller.isLive:
|
if not controller.isLive:
|
||||||
autoplay = True
|
autoplay = True
|
||||||
# Visible or background requested
|
# Visible or background requested or Service Item wants to autostart
|
||||||
elif not hidden or controller.media_info.is_background:
|
elif not hidden or controller.media_info.is_background or \
|
||||||
|
serviceItem.will_auto_start:
|
||||||
autoplay = True
|
autoplay = True
|
||||||
# Unblank on load set
|
# Unblank on load set
|
||||||
elif Settings().value(u'general/auto unblank',
|
elif Settings().value(u'general/auto unblank',
|
||||||
QtCore.QVariant(False)).toBool():
|
QtCore.QVariant(False)).toBool():
|
||||||
autoplay = True
|
autoplay = True
|
||||||
# Start playback only for visible widgets. If we need just load a video
|
if autoplay:
|
||||||
# and get video information, do not start playback.
|
if not self.media_play(controller):
|
||||||
if autoplay and not isInfo:
|
|
||||||
if not self.video_play([controller]):
|
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
||||||
unicode(translate('MediaPlugin.MediaItem',
|
unicode(translate('MediaPlugin.MediaItem',
|
||||||
'Unsupported File')))
|
'Unsupported File')))
|
||||||
return False
|
return False
|
||||||
self.set_controls_visible(controller, controlsVisible)
|
self.set_controls_visible(controller, True)
|
||||||
log.debug(u'use %s controller' % self.curDisplayMediaPlayer[display])
|
log.debug(u'use %s controller' %
|
||||||
|
self.currentMediaPlayer[controller.controllerType])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_file_type(self, controller, display):
|
def media_length(self, serviceItem):
|
||||||
|
"""
|
||||||
|
Loads and starts a media item to obtain the media length
|
||||||
|
|
||||||
|
``serviceItem``
|
||||||
|
The ServiceItem containing the details to be played.
|
||||||
|
"""
|
||||||
|
controller = self.displayControllers[DisplayControllerType.Plugin]
|
||||||
|
log.debug(u'media_length')
|
||||||
|
# stop running videos
|
||||||
|
self.media_reset(controller)
|
||||||
|
controller.media_info = MediaInfo()
|
||||||
|
controller.media_info.volume = 0
|
||||||
|
controller.media_info.file_info = QtCore.QFileInfo(serviceItem
|
||||||
|
.get_frame_path())
|
||||||
|
display = controller.previewDisplay
|
||||||
|
if not self._check_file_type(controller, display, serviceItem):
|
||||||
|
# Media could not be loaded correctly
|
||||||
|
critical_error_message_box(
|
||||||
|
translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
||||||
|
unicode(translate('MediaPlugin.MediaItem',
|
||||||
|
'Unsupported File')))
|
||||||
|
return False
|
||||||
|
if not self.media_play(controller):
|
||||||
|
critical_error_message_box(
|
||||||
|
translate('MediaPlugin.MediaItem', 'Unsupported File'),
|
||||||
|
unicode(translate('MediaPlugin.MediaItem',
|
||||||
|
'Unsupported File')))
|
||||||
|
return False
|
||||||
|
serviceItem.set_media_length(controller.media_info.length)
|
||||||
|
self.media_stop(controller)
|
||||||
|
log.debug(u'use %s controller' %
|
||||||
|
self.currentMediaPlayer[controller.controllerType])
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _check_file_type(self, controller, display, serviceItem):
|
||||||
"""
|
"""
|
||||||
Select the correct media Player type from the prioritized Player list
|
Select the correct media Player type from the prioritized Player list
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
First element is the controller which should be used
|
||||||
|
|
||||||
|
``serviceItem``
|
||||||
|
The ServiceItem containing the details to be played.
|
||||||
"""
|
"""
|
||||||
usedPlayers, overriddenPlayer = get_media_players()
|
usedPlayers = get_media_players()[0]
|
||||||
if overriddenPlayer and overriddenPlayer != u'auto':
|
if serviceItem.title != UiStrings().Automatic:
|
||||||
usedPlayers = [overriddenPlayer]
|
usedPlayers = [serviceItem.title.lower()]
|
||||||
if controller.media_info.file_info.isFile():
|
if controller.media_info.file_info.isFile():
|
||||||
suffix = u'*.%s' % \
|
suffix = u'*.%s' % \
|
||||||
controller.media_info.file_info.suffix().toLower()
|
controller.media_info.file_info.suffix().toLower()
|
||||||
@ -383,45 +492,65 @@ class MediaController(object):
|
|||||||
if not controller.media_info.is_background or \
|
if not controller.media_info.is_background or \
|
||||||
controller.media_info.is_background and \
|
controller.media_info.is_background and \
|
||||||
player.canBackground:
|
player.canBackground:
|
||||||
self.resize(controller, display, player)
|
self.resize(display, player)
|
||||||
if player.load(display):
|
if player.load(display):
|
||||||
self.curDisplayMediaPlayer[display] = player
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
|
= player
|
||||||
controller.media_info.media_type = MediaType.Video
|
controller.media_info.media_type = MediaType.Video
|
||||||
return True
|
return True
|
||||||
if suffix in player.audio_extensions_list:
|
if suffix in player.audio_extensions_list:
|
||||||
if player.load(display):
|
if player.load(display):
|
||||||
self.curDisplayMediaPlayer[display] = player
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
|
= player
|
||||||
controller.media_info.media_type = MediaType.Audio
|
controller.media_info.media_type = MediaType.Audio
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
for title in usedPlayers:
|
for title in usedPlayers:
|
||||||
player = self.mediaPlayers[title]
|
player = self.mediaPlayers[title]
|
||||||
if player.canFolder:
|
if player.canFolder:
|
||||||
self.resize(controller, display, player)
|
self.resize(display, player)
|
||||||
if player.load(display):
|
if player.load(display):
|
||||||
self.curDisplayMediaPlayer[display] = player
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
|
= player
|
||||||
controller.media_info.media_type = MediaType.Video
|
controller.media_info.media_type = MediaType.Video
|
||||||
return True
|
return True
|
||||||
# no valid player found
|
# no valid player found
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def video_play(self, msg, status=True):
|
def media_play_msg(self, msg, status=True):
|
||||||
"""
|
"""
|
||||||
Responds to the request to play a loaded video
|
Responds to the request to play a loaded video
|
||||||
|
|
||||||
``msg``
|
``msg``
|
||||||
First element is the controller which should be used
|
First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
log.debug(u'video_play')
|
log.debug(u'media_play_msg')
|
||||||
controller = msg[0]
|
self.media_play(msg[0],status)
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
|
||||||
if display.controller == controller:
|
|
||||||
if not self.curDisplayMediaPlayer[display].play(display):
|
def media_play(self, controller, status=True):
|
||||||
|
"""
|
||||||
|
Responds to the request to play a loaded video
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
The controller to be played
|
||||||
|
"""
|
||||||
|
log.debug(u'media_play')
|
||||||
|
display = self._define_display(controller)
|
||||||
|
if not self.currentMediaPlayer[controller.controllerType].play(display):
|
||||||
return False
|
return False
|
||||||
if status:
|
if status:
|
||||||
display.frame.evaluateJavaScript(u'show_blank("desktop");')
|
display.frame.evaluateJavaScript(u'show_blank("desktop");')
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display,
|
self.currentMediaPlayer[controller.controllerType]\
|
||||||
True)
|
.set_visible(display, True)
|
||||||
|
# Flash needs to be played and will not AutoPlay
|
||||||
|
if controller.media_info.is_flash:
|
||||||
|
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
|
||||||
|
controller.mediabar.actions[u'playbackPause'].setVisible(False)
|
||||||
|
else:
|
||||||
|
controller.mediabar.actions[u'playbackPlay'].setVisible(False)
|
||||||
|
controller.mediabar.actions[u'playbackPause'].setVisible(True)
|
||||||
|
controller.mediabar.actions[u'playbackStop'].setVisible(True)
|
||||||
if controller.isLive:
|
if controller.isLive:
|
||||||
if controller.hideMenu.defaultAction().isChecked():
|
if controller.hideMenu.defaultAction().isChecked():
|
||||||
controller.hideMenu.defaultAction().trigger()
|
controller.hideMenu.defaultAction().trigger()
|
||||||
@ -430,36 +559,60 @@ class MediaController(object):
|
|||||||
self.timer.start()
|
self.timer.start()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def video_pause(self, msg):
|
def media_pause_msg(self, msg):
|
||||||
"""
|
"""
|
||||||
Responds to the request to pause a loaded video
|
Responds to the request to pause a loaded video
|
||||||
|
|
||||||
``msg``
|
``msg``
|
||||||
First element is the controller which should be used
|
First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
log.debug(u'video_pause')
|
log.debug(u'media_pause_msg')
|
||||||
controller = msg[0]
|
self.media_pause( msg[0])
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
|
||||||
if display.controller == controller:
|
|
||||||
self.curDisplayMediaPlayer[display].pause(display)
|
|
||||||
|
|
||||||
def video_stop(self, msg):
|
def media_pause(self, controller):
|
||||||
|
"""
|
||||||
|
Responds to the request to pause a loaded video
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
The Controller to be paused
|
||||||
|
"""
|
||||||
|
log.debug(u'media_pause')
|
||||||
|
display = self._define_display(controller)
|
||||||
|
self.currentMediaPlayer[controller.controllerType].pause(display)
|
||||||
|
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
|
||||||
|
controller.mediabar.actions[u'playbackStop'].setVisible(True)
|
||||||
|
controller.mediabar.actions[u'playbackPause'].setVisible(False)
|
||||||
|
|
||||||
|
def media_stop_msg(self, msg):
|
||||||
"""
|
"""
|
||||||
Responds to the request to stop a loaded video
|
Responds to the request to stop a loaded video
|
||||||
|
|
||||||
``msg``
|
``msg``
|
||||||
First element is the controller which should be used
|
First element is the controller which should be used
|
||||||
"""
|
"""
|
||||||
log.debug(u'video_stop')
|
log.debug(u'media_stop_msg')
|
||||||
controller = msg[0]
|
self.media_stop(msg[0])
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
|
||||||
if display.controller == controller:
|
|
||||||
display.frame.evaluateJavaScript(u'show_blank("black");')
|
|
||||||
self.curDisplayMediaPlayer[display].stop(display)
|
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display, False)
|
|
||||||
controller.seekSlider.setSliderPosition(0)
|
|
||||||
|
|
||||||
def video_volume(self, msg):
|
def media_stop(self, controller):
|
||||||
|
"""
|
||||||
|
Responds to the request to stop a loaded video
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
The controller that needs to be stopped
|
||||||
|
"""
|
||||||
|
log.debug(u'media_stop')
|
||||||
|
display = self._define_display(controller)
|
||||||
|
if controller.controllerType in self.currentMediaPlayer:
|
||||||
|
display.frame.evaluateJavaScript(u'show_blank("black");')
|
||||||
|
self.currentMediaPlayer[controller.controllerType].stop(display)
|
||||||
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
|
.set_visible(display, False)
|
||||||
|
controller.seekSlider.setSliderPosition(0)
|
||||||
|
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
|
||||||
|
controller.mediabar.actions[u'playbackStop'].setVisible(False)
|
||||||
|
controller.mediabar.actions[u'playbackPause'].setVisible(False)
|
||||||
|
|
||||||
|
def media_volume(self, msg):
|
||||||
"""
|
"""
|
||||||
Changes the volume of a running video
|
Changes the volume of a running video
|
||||||
|
|
||||||
@ -468,12 +621,11 @@ class MediaController(object):
|
|||||||
"""
|
"""
|
||||||
controller = msg[0]
|
controller = msg[0]
|
||||||
vol = msg[1][0]
|
vol = msg[1][0]
|
||||||
log.debug(u'video_volume %d' % vol)
|
log.debug(u'media_volume %d' % vol)
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller == controller:
|
self.currentMediaPlayer[controller.controllerType].volume(display, vol)
|
||||||
self.curDisplayMediaPlayer[display].volume(display, vol)
|
|
||||||
|
|
||||||
def video_seek(self, msg):
|
def media_seek(self, msg):
|
||||||
"""
|
"""
|
||||||
Responds to the request to change the seek Slider of a loaded video
|
Responds to the request to change the seek Slider of a loaded video
|
||||||
|
|
||||||
@ -481,29 +633,30 @@ class MediaController(object):
|
|||||||
First element is the controller which should be used
|
First element is the controller which should be used
|
||||||
Second element is a list with the seek Value as first element
|
Second element is a list with the seek Value as first element
|
||||||
"""
|
"""
|
||||||
log.debug(u'video_seek')
|
log.debug(u'media_seek')
|
||||||
controller = msg[0]
|
controller = msg[0]
|
||||||
seekVal = msg[1][0]
|
seekVal = msg[1][0]
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller == controller:
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
self.curDisplayMediaPlayer[display].seek(display, seekVal)
|
.seek(display, seekVal)
|
||||||
|
|
||||||
def video_reset(self, controller):
|
def media_reset(self, controller):
|
||||||
"""
|
"""
|
||||||
Responds to the request to reset a loaded video
|
Responds to the request to reset a loaded video
|
||||||
"""
|
"""
|
||||||
log.debug(u'video_reset')
|
log.debug(u'media_reset')
|
||||||
self.set_controls_visible(controller, False)
|
self.set_controls_visible(controller, False)
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller == controller:
|
if controller.controllerType in self.currentMediaPlayer:
|
||||||
display.override = {}
|
display.override = {}
|
||||||
self.curDisplayMediaPlayer[display].reset(display)
|
self.currentMediaPlayer[controller.controllerType].reset(display)
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display, False)
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
|
.set_visible(display, False)
|
||||||
display.frame.evaluateJavaScript(u'show_video( \
|
display.frame.evaluateJavaScript(u'show_video( \
|
||||||
"setBackBoard", null, null, null,"hidden");')
|
"setBackBoard", null, null, null,"hidden");')
|
||||||
del self.curDisplayMediaPlayer[display]
|
del self.currentMediaPlayer[controller.controllerType]
|
||||||
|
|
||||||
def video_hide(self, msg):
|
def media_hide(self, msg):
|
||||||
"""
|
"""
|
||||||
Hide the related video Widget
|
Hide the related video Widget
|
||||||
|
|
||||||
@ -513,15 +666,15 @@ class MediaController(object):
|
|||||||
isLive = msg[1]
|
isLive = msg[1]
|
||||||
if not isLive:
|
if not isLive:
|
||||||
return
|
return
|
||||||
controller = self.parent.liveController
|
controller = self.mainWindow.liveController
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller != controller or \
|
if self.currentMediaPlayer[controller.controllerType].state \
|
||||||
self.curDisplayMediaPlayer[display].state != MediaState.Playing:
|
== MediaState.Playing:
|
||||||
continue
|
self.currentMediaPlayer[controller.controllerType].pause(display)
|
||||||
self.curDisplayMediaPlayer[display].pause(display)
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display, False)
|
.set_visible(display, False)
|
||||||
|
|
||||||
def video_blank(self, msg):
|
def media_blank(self, msg):
|
||||||
"""
|
"""
|
||||||
Blank the related video Widget
|
Blank the related video Widget
|
||||||
|
|
||||||
@ -534,15 +687,15 @@ class MediaController(object):
|
|||||||
if not isLive:
|
if not isLive:
|
||||||
return
|
return
|
||||||
Receiver.send_message(u'live_display_hide', hide_mode)
|
Receiver.send_message(u'live_display_hide', hide_mode)
|
||||||
controller = self.parent.liveController
|
controller = self.mainWindow.liveController
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller != controller or \
|
if self.currentMediaPlayer[controller.controllerType].state \
|
||||||
self.curDisplayMediaPlayer[display].state != MediaState.Playing:
|
== MediaState.Playing:
|
||||||
continue
|
self.currentMediaPlayer[controller.controllerType].pause(display)
|
||||||
self.curDisplayMediaPlayer[display].pause(display)
|
self.currentMediaPlayer[controller.controllerType] \
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display, False)
|
.set_visible(display, False)
|
||||||
|
|
||||||
def video_unblank(self, msg):
|
def media_unblank(self, msg):
|
||||||
"""
|
"""
|
||||||
Unblank the related video Widget
|
Unblank the related video Widget
|
||||||
|
|
||||||
@ -554,35 +707,28 @@ class MediaController(object):
|
|||||||
isLive = msg[1]
|
isLive = msg[1]
|
||||||
if not isLive:
|
if not isLive:
|
||||||
return
|
return
|
||||||
controller = self.parent.liveController
|
controller = self.mainWindow.liveController
|
||||||
for display in self.curDisplayMediaPlayer.keys():
|
display = self._define_display(controller)
|
||||||
if display.controller != controller or \
|
if controller.controllerType in self.currentMediaPlayer and \
|
||||||
self.curDisplayMediaPlayer[display].state != MediaState.Paused:
|
self.currentMediaPlayer[controller.controllerType].state != MediaState.Playing:
|
||||||
continue
|
if self.currentMediaPlayer[controller.controllerType].play(display):
|
||||||
if self.curDisplayMediaPlayer[display].play(display):
|
self.currentMediaPlayer[controller.controllerType].set_visible(display, True)
|
||||||
self.curDisplayMediaPlayer[display].set_visible(display, True)
|
|
||||||
# Start Timer for ui updates
|
# Start Timer for ui updates
|
||||||
if not self.timer.isActive():
|
if not self.timer.isActive():
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
|
|
||||||
def get_audio_extensions_list(self):
|
|
||||||
audio_list = []
|
|
||||||
for player in self.mediaPlayers.values():
|
|
||||||
if player.isActive:
|
|
||||||
for item in player.audio_extensions_list:
|
|
||||||
if not item in audio_list:
|
|
||||||
audio_list.append(item)
|
|
||||||
return audio_list
|
|
||||||
|
|
||||||
def get_video_extensions_list(self):
|
|
||||||
video_list = []
|
|
||||||
for player in self.mediaPlayers.values():
|
|
||||||
if player.isActive:
|
|
||||||
video_list.extend([item for item in player.video_extensions_list
|
|
||||||
if item not in video_list])
|
|
||||||
return video_list
|
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
for controller in self.controller:
|
for controller in self.displayControllers:
|
||||||
self.video_reset(controller)
|
self.media_reset(self.displayControllers[controller])
|
||||||
|
|
||||||
|
def _define_display(self, controller):
|
||||||
|
"""
|
||||||
|
Extract the correct display for a given controller
|
||||||
|
|
||||||
|
``controller``
|
||||||
|
Controller to be used
|
||||||
|
"""
|
||||||
|
if controller.isLive:
|
||||||
|
return controller.display
|
||||||
|
return controller.previewDisplay
|
||||||
|
@ -31,8 +31,8 @@ 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 pluggable media display
|
This is the base class media Player class to provide OpenLP with a
|
||||||
framework.
|
pluggable media display framework.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent, name=u'media_player'):
|
def __init__(self, parent, name=u'media_player'):
|
||||||
@ -137,3 +137,9 @@ class MediaPlayer(object):
|
|||||||
Add html code to htmlbuilder
|
Add html code to htmlbuilder
|
||||||
"""
|
"""
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
|
def get_info(self):
|
||||||
|
"""
|
||||||
|
Returns Information about the player
|
||||||
|
"""
|
||||||
|
return u''
|
@ -31,11 +31,15 @@ import logging
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import Receiver
|
from openlp.core.lib import Receiver, translate
|
||||||
from openlp.core.lib.mediaplayer import MediaPlayer
|
from openlp.core.lib.settings import Settings
|
||||||
|
|
||||||
from openlp.core.ui.media import MediaState
|
from openlp.core.ui.media import MediaState
|
||||||
|
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -56,6 +60,20 @@ ADDITIONAL_EXT = {
|
|||||||
u'video/mpeg' : [u'.mp4', u'.mts', u'.mov'],
|
u'video/mpeg' : [u'.mp4', u'.mts', u'.mov'],
|
||||||
u'video/x-ms-wmv': [u'.wmv']}
|
u'video/x-ms-wmv': [u'.wmv']}
|
||||||
|
|
||||||
|
VIDEO_CSS = u"""
|
||||||
|
#videobackboard {
|
||||||
|
z-index:3;
|
||||||
|
background-color: %s;
|
||||||
|
}
|
||||||
|
#video1 {
|
||||||
|
background-color: %s;
|
||||||
|
z-index:4;
|
||||||
|
}
|
||||||
|
#video2 {
|
||||||
|
background-color: %s;
|
||||||
|
z-index:4;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
class PhononPlayer(MediaPlayer):
|
class PhononPlayer(MediaPlayer):
|
||||||
"""
|
"""
|
||||||
@ -205,3 +223,20 @@ class PhononPlayer(MediaPlayer):
|
|||||||
if not controller.seekSlider.isSliderDown():
|
if not controller.seekSlider.isSliderDown():
|
||||||
controller.seekSlider.setSliderPosition(
|
controller.seekSlider.setSliderPosition(
|
||||||
display.mediaObject.currentTime())
|
display.mediaObject.currentTime())
|
||||||
|
|
||||||
|
def get_media_display_css(self):
|
||||||
|
"""
|
||||||
|
Add css style sheets to htmlbuilder
|
||||||
|
"""
|
||||||
|
background = unicode(QtGui.QColor(Settings().value(
|
||||||
|
u'players/background color', QtCore.QVariant(u'#000000'))).name())
|
||||||
|
return VIDEO_CSS % (background,background,background)
|
||||||
|
|
||||||
|
def get_info(self):
|
||||||
|
return(translate('Media.player', 'Phonon is a media player which '
|
||||||
|
'interacts with the operating system to provide media capabilities'
|
||||||
|
'.') +
|
||||||
|
u'<br/> <strong>' + translate('Media.player', 'Audio') +
|
||||||
|
u'</strong><br/>' + unicode(self.audio_extensions_list) +
|
||||||
|
u'<br/><strong>' + translate('Media.player', 'Video') +
|
||||||
|
u'</strong><br/>' + unicode(self.video_extensions_list) + u'<br/>')
|
255
openlp/core/ui/media/playertab.py
Normal file
255
openlp/core/ui/media/playertab.py
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2012 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
|
# Meinert Jordan, Armin Köhler, Eric Ludin, 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, #
|
||||||
|
# Erode Woldsund, Martin Zibricky #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
from openlp.core.lib import SettingsTab, translate, Receiver
|
||||||
|
from openlp.core.lib.ui import UiStrings, create_button
|
||||||
|
from openlp.core.lib.settings import Settings
|
||||||
|
from openlp.core.ui.media import get_media_players, set_media_players
|
||||||
|
|
||||||
|
class MediaQCheckBox(QtGui.QCheckBox):
|
||||||
|
"""
|
||||||
|
MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
|
||||||
|
"""
|
||||||
|
def setPlayerName(self, name):
|
||||||
|
self.playerName = name
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerTab(SettingsTab):
|
||||||
|
"""
|
||||||
|
MediaTab is the Media settings tab in the settings dialog.
|
||||||
|
"""
|
||||||
|
def __init__(self, parent, mainWindow):
|
||||||
|
self.parent = parent
|
||||||
|
self.mainWindow = mainWindow
|
||||||
|
self.mediaPlayers = mainWindow.mediaController.mediaPlayers
|
||||||
|
self.savedUsedPlayers = None
|
||||||
|
self.iconPath = u':/media/multimedia-player.png'
|
||||||
|
player_translated = translate('OpenLP.PlayerTab', 'Players')
|
||||||
|
SettingsTab.__init__(self, parent, u'Players', player_translated)
|
||||||
|
|
||||||
|
def setupUi(self):
|
||||||
|
self.setObjectName(u'MediaTab')
|
||||||
|
SettingsTab.setupUi(self)
|
||||||
|
self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
|
self.bgColorGroupBox.setObjectName(u'FontGroupBox')
|
||||||
|
self.formLayout = QtGui.QFormLayout(self.bgColorGroupBox)
|
||||||
|
self.formLayout.setObjectName(u'FormLayout')
|
||||||
|
self.colorLayout = QtGui.QHBoxLayout()
|
||||||
|
self.backgroundColorLabel = QtGui.QLabel(self.bgColorGroupBox)
|
||||||
|
self.backgroundColorLabel.setObjectName(u'BackgroundColorLabel')
|
||||||
|
self.colorLayout.addWidget(self.backgroundColorLabel)
|
||||||
|
self.backgroundColorButton = QtGui.QPushButton(self.bgColorGroupBox)
|
||||||
|
self.backgroundColorButton.setObjectName(u'BackgroundColorButton')
|
||||||
|
self.colorLayout.addWidget(self.backgroundColorButton)
|
||||||
|
self.formLayout.addRow(self.colorLayout)
|
||||||
|
self.informationLabel = QtGui.QLabel(self.bgColorGroupBox)
|
||||||
|
self.informationLabel.setObjectName(u'InformationLabel')
|
||||||
|
self.informationLabel.setWordWrap(True)
|
||||||
|
self.formLayout.addRow(self.informationLabel)
|
||||||
|
self.leftLayout.addWidget(self.bgColorGroupBox)
|
||||||
|
self.leftLayout.addStretch()
|
||||||
|
self.rightColumn.setSizePolicy(
|
||||||
|
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
|
||||||
|
self.rightLayout.addStretch()
|
||||||
|
self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
|
self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
|
||||||
|
self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
|
||||||
|
self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
|
||||||
|
self.playerCheckBoxes = {}
|
||||||
|
self.leftLayout.addWidget(self.mediaPlayerGroupBox)
|
||||||
|
self.playerOrderGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
|
self.playerOrderGroupBox.setObjectName(u'playerOrderGroupBox')
|
||||||
|
self.playerOrderLayout = QtGui.QHBoxLayout(self.playerOrderGroupBox)
|
||||||
|
self.playerOrderLayout.setObjectName(u'playerOrderLayout')
|
||||||
|
self.playerOrderlistWidget = QtGui.QListWidget(
|
||||||
|
self.playerOrderGroupBox)
|
||||||
|
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
|
||||||
|
QtGui.QSizePolicy.Expanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.playerOrderlistWidget.\
|
||||||
|
sizePolicy().hasHeightForWidth())
|
||||||
|
self.playerOrderlistWidget.setSizePolicy(sizePolicy)
|
||||||
|
self.playerOrderlistWidget.setVerticalScrollBarPolicy(
|
||||||
|
QtCore.Qt.ScrollBarAsNeeded)
|
||||||
|
self.playerOrderlistWidget.setHorizontalScrollBarPolicy(
|
||||||
|
QtCore.Qt.ScrollBarAlwaysOff)
|
||||||
|
self.playerOrderlistWidget.setEditTriggers(
|
||||||
|
QtGui.QAbstractItemView.NoEditTriggers)
|
||||||
|
self.playerOrderlistWidget.setObjectName(u'playerOrderlistWidget')
|
||||||
|
self.playerOrderLayout.addWidget(self.playerOrderlistWidget)
|
||||||
|
self.orderingButtonLayout = QtGui.QVBoxLayout()
|
||||||
|
self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
|
||||||
|
self.orderingButtonLayout.addStretch(1)
|
||||||
|
self.orderingUpButton = create_button(self, u'orderingUpButton',
|
||||||
|
role=u'up', click=self.onUpButtonClicked)
|
||||||
|
self.orderingDownButton = create_button(self, u'orderingDownButton',
|
||||||
|
role=u'down', click=self.onDownButtonClicked)
|
||||||
|
self.orderingButtonLayout.addWidget(self.orderingUpButton)
|
||||||
|
self.orderingButtonLayout.addWidget(self.orderingDownButton)
|
||||||
|
self.orderingButtonLayout.addStretch(1)
|
||||||
|
self.playerOrderLayout.addLayout(self.orderingButtonLayout)
|
||||||
|
self.leftLayout.addWidget(self.playerOrderGroupBox)
|
||||||
|
self.leftLayout.addStretch()
|
||||||
|
self.rightLayout.addStretch()
|
||||||
|
# Signals and slots
|
||||||
|
QtCore.QObject.connect(self.backgroundColorButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'), self.onbackgroundColorButtonClicked)
|
||||||
|
|
||||||
|
def retranslateUi(self):
|
||||||
|
self.mediaPlayerGroupBox.setTitle(
|
||||||
|
translate('OpenLP.PlayerTab', 'Available Media Players'))
|
||||||
|
self.playerOrderGroupBox.setTitle(
|
||||||
|
translate('OpenLP.PlayerTab', 'Player Search Order'))
|
||||||
|
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
|
||||||
|
self.backgroundColorLabel.setText(UiStrings().DefaultColor)
|
||||||
|
self.informationLabel.setText(
|
||||||
|
translate('OpenLP.PlayerTab', 'Visible background for videos '
|
||||||
|
'with aspect ratio different to screen.'))
|
||||||
|
self.retranslatePlayers()
|
||||||
|
|
||||||
|
def onbackgroundColorButtonClicked(self):
|
||||||
|
new_color = QtGui.QColorDialog.getColor(
|
||||||
|
QtGui.QColor(self.bg_color), self)
|
||||||
|
if new_color.isValid():
|
||||||
|
self.bg_color = new_color.name()
|
||||||
|
self.backgroundColorButton.setStyleSheet(
|
||||||
|
u'background-color: %s' % self.bg_color)
|
||||||
|
|
||||||
|
def onPlayerCheckBoxChanged(self, check_state):
|
||||||
|
player = self.sender().playerName
|
||||||
|
if check_state == QtCore.Qt.Checked:
|
||||||
|
if player not in self.usedPlayers:
|
||||||
|
self.usedPlayers.append(player)
|
||||||
|
else:
|
||||||
|
if player in self.usedPlayers:
|
||||||
|
self.usedPlayers.remove(player)
|
||||||
|
self.updatePlayerList()
|
||||||
|
|
||||||
|
def updatePlayerList(self):
|
||||||
|
self.playerOrderlistWidget.clear()
|
||||||
|
for player in self.usedPlayers:
|
||||||
|
if player in self.playerCheckBoxes.keys():
|
||||||
|
if len(self.usedPlayers) == 1:
|
||||||
|
# At least one media player has to stay active
|
||||||
|
self.playerCheckBoxes[u'%s' % player].setEnabled(False)
|
||||||
|
else:
|
||||||
|
self.playerCheckBoxes[u'%s' % player].setEnabled(True)
|
||||||
|
self.playerOrderlistWidget.addItem(
|
||||||
|
self.mediaPlayers[unicode(player)].original_name)
|
||||||
|
|
||||||
|
def onUpButtonClicked(self):
|
||||||
|
row = self.playerOrderlistWidget.currentRow()
|
||||||
|
if row <= 0:
|
||||||
|
return
|
||||||
|
item = self.playerOrderlistWidget.takeItem(row)
|
||||||
|
self.playerOrderlistWidget.insertItem(row - 1, item)
|
||||||
|
self.playerOrderlistWidget.setCurrentRow(row - 1)
|
||||||
|
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
|
||||||
|
|
||||||
|
def onDownButtonClicked(self):
|
||||||
|
row = self.playerOrderlistWidget.currentRow()
|
||||||
|
if row == -1 or row > self.playerOrderlistWidget.count() - 1:
|
||||||
|
return
|
||||||
|
item = self.playerOrderlistWidget.takeItem(row)
|
||||||
|
self.playerOrderlistWidget.insertItem(row + 1, item)
|
||||||
|
self.playerOrderlistWidget.setCurrentRow(row + 1)
|
||||||
|
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
if self.savedUsedPlayers:
|
||||||
|
self.usedPlayers = self.savedUsedPlayers
|
||||||
|
self.usedPlayers = get_media_players()[0]
|
||||||
|
self.savedUsedPlayers = self.usedPlayers
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
|
settings.beginGroup(self.settingsSection)
|
||||||
|
self.updatePlayerList()
|
||||||
|
self.bg_color = unicode(settings.value(
|
||||||
|
u'background color', QtCore.QVariant(u'#000000')).toString())
|
||||||
|
self.initial_color = self.bg_color
|
||||||
|
settings.endGroup()
|
||||||
|
self.backgroundColorButton.setStyleSheet(
|
||||||
|
u'background-color: %s' % self.bg_color)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
player_string_changed = False
|
||||||
|
settings = Settings()
|
||||||
|
settings.beginGroup(self.settingsSection)
|
||||||
|
settings.setValue(u'background color', QtCore.QVariant(self.bg_color))
|
||||||
|
settings.endGroup()
|
||||||
|
old_players, override_player = get_media_players()
|
||||||
|
if self.usedPlayers != old_players:
|
||||||
|
# clean old Media stuff
|
||||||
|
set_media_players(self.usedPlayers, override_player)
|
||||||
|
player_string_changed = True
|
||||||
|
if player_string_changed:
|
||||||
|
self.parent.resetSupportedSuffixes()
|
||||||
|
Receiver.send_message(u'mediaitem_media_rebuild')
|
||||||
|
Receiver.send_message(u'config_screen_changed')
|
||||||
|
|
||||||
|
def postSetUp(self, postUpdate=False):
|
||||||
|
"""
|
||||||
|
Late setup for players as the MediaController has to be initialised
|
||||||
|
first.
|
||||||
|
"""
|
||||||
|
for key, player in self.mediaPlayers.iteritems():
|
||||||
|
player = self.mediaPlayers[key]
|
||||||
|
checkbox = MediaQCheckBox(self.mediaPlayerGroupBox)
|
||||||
|
checkbox.setEnabled(player.available)
|
||||||
|
checkbox.setObjectName(player.name + u'CheckBox')
|
||||||
|
checkbox.setToolTip(player.get_info())
|
||||||
|
checkbox.setPlayerName(player.name)
|
||||||
|
self.playerCheckBoxes[player.name] = checkbox
|
||||||
|
QtCore.QObject.connect(checkbox,QtCore.SIGNAL(u'stateChanged(int)'),
|
||||||
|
self.onPlayerCheckBoxChanged)
|
||||||
|
self.mediaPlayerLayout.addWidget(checkbox)
|
||||||
|
if player.available and player.name in self.usedPlayers:
|
||||||
|
checkbox.setChecked(True)
|
||||||
|
else:
|
||||||
|
checkbox.setChecked(False)
|
||||||
|
self.updatePlayerList()
|
||||||
|
self.retranslatePlayers()
|
||||||
|
|
||||||
|
def retranslatePlayers(self):
|
||||||
|
"""
|
||||||
|
Translations for players is dependent on their setup as well
|
||||||
|
"""
|
||||||
|
for key in self.mediaPlayers:
|
||||||
|
player = self.mediaPlayers[key]
|
||||||
|
checkbox = self.playerCheckBoxes[player.name]
|
||||||
|
checkbox.setPlayerName(player.name)
|
||||||
|
if player.available:
|
||||||
|
checkbox.setText(player.display_name)
|
||||||
|
else:
|
||||||
|
checkbox.setText(
|
||||||
|
unicode(translate('OpenLP.PlayerTab',
|
||||||
|
'%s (unavailable)')) % player.display_name)
|
28
openlp/core/ui/media/vendor/__init__.py
vendored
Normal file
28
openlp/core/ui/media/vendor/__init__.py
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2012 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
|
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||||
|
# Meinert Jordan, Armin Köhler, Eric Ludin, 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, #
|
||||||
|
# Erode Woldsund, Martin Zibricky #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
@ -35,16 +35,16 @@ import sys
|
|||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Receiver
|
from openlp.core.lib import Receiver, translate
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.lib.mediaplayer import MediaPlayer
|
|
||||||
from openlp.core.ui.media import MediaState
|
from openlp.core.ui.media import MediaState
|
||||||
|
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
VLC_AVAILABLE = False
|
VLC_AVAILABLE = False
|
||||||
try:
|
try:
|
||||||
import vlc
|
from openlp.core.ui.media.vendor import vlc
|
||||||
VLC_AVAILABLE = bool(vlc.get_default_instance())
|
VLC_AVAILABLE = bool(vlc.get_default_instance())
|
||||||
except (ImportError, NameError, NotImplementedError):
|
except (ImportError, NameError, NotImplementedError):
|
||||||
pass
|
pass
|
||||||
@ -115,8 +115,7 @@ class VlcPlayer(MediaPlayer):
|
|||||||
if not display.hasAudio:
|
if not display.hasAudio:
|
||||||
command_line_options += u' --no-audio --no-video-title-show'
|
command_line_options += u' --no-audio --no-video-title-show'
|
||||||
if Settings().value(u'advanced/hide mouse',
|
if Settings().value(u'advanced/hide mouse',
|
||||||
QtCore.QVariant(False)).toBool() and \
|
QtCore.QVariant(True)).toBool() and display.controller.isLive:
|
||||||
display.controller.isLive:
|
|
||||||
command_line_options += u' --mouse-hide-timeout=0'
|
command_line_options += u' --mouse-hide-timeout=0'
|
||||||
display.vlcInstance = vlc.Instance(command_line_options)
|
display.vlcInstance = vlc.Instance(command_line_options)
|
||||||
display.vlcInstance.set_log_verbosity(2)
|
display.vlcInstance.set_log_verbosity(2)
|
||||||
@ -188,7 +187,8 @@ class VlcPlayer(MediaPlayer):
|
|||||||
def play(self, display):
|
def play(self, display):
|
||||||
controller = display.controller
|
controller = display.controller
|
||||||
start_time = 0
|
start_time = 0
|
||||||
if 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.vlcMediaPlayer.play()
|
||||||
if not self.media_state_wait(display, vlc.State.Playing):
|
if not self.media_state_wait(display, vlc.State.Playing):
|
||||||
@ -244,3 +244,10 @@ class VlcPlayer(MediaPlayer):
|
|||||||
controller.seekSlider.setSliderPosition( \
|
controller.seekSlider.setSliderPosition( \
|
||||||
display.vlcMediaPlayer.get_time())
|
display.vlcMediaPlayer.get_time())
|
||||||
|
|
||||||
|
def get_info(self):
|
||||||
|
return(translate('Media.player', 'VLC is an external player which '
|
||||||
|
'supports a number of different formats.') +
|
||||||
|
u'<br/> <strong>' + translate('Media.player', 'Audio') +
|
||||||
|
u'</strong><br/>' + unicode(AUDIO_EXT) + u'<br/><strong>' +
|
||||||
|
translate('Media.player', 'Video') + u'</strong><br/>' +
|
||||||
|
unicode(VIDEO_EXT) + u'<br/>')
|
@ -27,22 +27,28 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from openlp.core.lib.mediaplayer import MediaPlayer
|
from openlp.core.lib import translate
|
||||||
from openlp.core.ui.media import MediaState
|
from openlp.core.ui.media import MediaState
|
||||||
|
from openlp.core.ui.media.mediaplayer import MediaPlayer
|
||||||
|
from openlp.core.lib.settings import Settings
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
VIDEO_CSS = u"""
|
VIDEO_CSS = u"""
|
||||||
#videobackboard {
|
#videobackboard {
|
||||||
z-index:3;
|
z-index:3;
|
||||||
background-color: black;
|
background-color: %s;
|
||||||
}
|
}
|
||||||
#video1 {
|
#video1 {
|
||||||
|
background-color: %s;
|
||||||
z-index:4;
|
z-index:4;
|
||||||
}
|
}
|
||||||
#video2 {
|
#video2 {
|
||||||
|
background-color: %s;
|
||||||
z-index:4;
|
z-index:4;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -277,7 +283,10 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
"""
|
"""
|
||||||
Add css style sheets to htmlbuilder
|
Add css style sheets to htmlbuilder
|
||||||
"""
|
"""
|
||||||
return VIDEO_CSS + FLASH_CSS
|
background = unicode(QtGui.QColor(Settings().value(
|
||||||
|
u'players/background color', QtCore.QVariant(u'#000000'))).name())
|
||||||
|
css = VIDEO_CSS % (background,background,background)
|
||||||
|
return css + FLASH_CSS
|
||||||
|
|
||||||
def get_media_display_javascript(self):
|
def get_media_display_javascript(self):
|
||||||
"""
|
"""
|
||||||
@ -324,7 +333,6 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def resize(self, display):
|
def resize(self, display):
|
||||||
controller = display.controller
|
|
||||||
display.webView.resize(display.size())
|
display.webView.resize(display.size())
|
||||||
|
|
||||||
def play(self, display):
|
def play(self, display):
|
||||||
@ -431,3 +439,12 @@ class WebkitPlayer(MediaPlayer):
|
|||||||
controller.seekSlider.setMaximum(length)
|
controller.seekSlider.setMaximum(length)
|
||||||
if not controller.seekSlider.isSliderDown():
|
if not controller.seekSlider.isSliderDown():
|
||||||
controller.seekSlider.setSliderPosition(currentTime)
|
controller.seekSlider.setSliderPosition(currentTime)
|
||||||
|
|
||||||
|
def get_info(self):
|
||||||
|
return(translate('Media.player', 'Webkit is a media player which runs '
|
||||||
|
'inside a web browser. This player allows text over video to be '
|
||||||
|
'rendered.') +
|
||||||
|
u'<br/> <strong>' + translate('Media.player', 'Audio') +
|
||||||
|
u'</strong><br/>' + unicode(AUDIO_EXT) + u'<br/><strong>' +
|
||||||
|
translate('Media.player', 'Video') + u'</strong><br/>' +
|
||||||
|
unicode(VIDEO_EXT) + u'<br/>')
|
@ -99,14 +99,16 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Manages the services. This involves taking text strings from plugins and
|
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
|
adding them to the service. This service can then be zipped up with all
|
||||||
the resources used into one OSZ file for use on any OpenLP v2 installation.
|
the resources used into one OSZ or oszl file for use on any OpenLP v2
|
||||||
Also handles the UI tasks of moving things up and down etc.
|
installation. Also handles the UI tasks of moving things up and down etc.
|
||||||
"""
|
"""
|
||||||
def __init__(self, mainwindow, parent=None):
|
def __init__(self, mainwindow, parent=None):
|
||||||
"""
|
"""
|
||||||
Sets up the service manager, toolbars, list view, et al.
|
Sets up the service manager, toolbars, list view, et al.
|
||||||
"""
|
"""
|
||||||
QtGui.QWidget.__init__(self, parent)
|
QtGui.QWidget.__init__(self, parent)
|
||||||
|
self.active = build_icon(QtGui.QImage(u':/media/auto-start_active.png'))
|
||||||
|
self.inactive = build_icon(QtGui.QImage(u':/media/auto-start_inactive.png'))
|
||||||
self.mainwindow = mainwindow
|
self.mainwindow = mainwindow
|
||||||
self.serviceItems = []
|
self.serviceItems = []
|
||||||
self.suffixes = []
|
self.suffixes = []
|
||||||
@ -136,7 +138,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.toolbar.addToolbarAction(u'saveService',
|
self.toolbar.addToolbarAction(u'saveService',
|
||||||
text=UiStrings().SaveService, icon=u':/general/general_save.png',
|
text=UiStrings().SaveService, icon=u':/general/general_save.png',
|
||||||
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
|
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
|
||||||
triggers=self.saveFile)
|
triggers=self.decideSaveMethod)
|
||||||
self.toolbar.addSeparator()
|
self.toolbar.addSeparator()
|
||||||
self.themeLabel = QtGui.QLabel(u'%s:' % UiStrings().Theme, self)
|
self.themeLabel = QtGui.QLabel(u'%s:' % UiStrings().Theme, self)
|
||||||
self.themeLabel.setMargin(3)
|
self.themeLabel.setMargin(3)
|
||||||
@ -307,6 +309,9 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.timeAction = create_widget_action(self.menu,
|
self.timeAction = create_widget_action(self.menu,
|
||||||
text=translate('OpenLP.ServiceManager', '&Start Time'),
|
text=translate('OpenLP.ServiceManager', '&Start Time'),
|
||||||
icon=u':/media/media_time.png', triggers=self.onStartTimeForm)
|
icon=u':/media/media_time.png', triggers=self.onStartTimeForm)
|
||||||
|
self.autoStartAction = create_widget_action(self.menu,
|
||||||
|
text=u'',
|
||||||
|
icon=u':/media/auto-start_active.png', triggers=self.onAutoStart)
|
||||||
# Add already existing delete action to the menu.
|
# Add already existing delete action to the menu.
|
||||||
self.menu.addAction(self.serviceManagerList.delete)
|
self.menu.addAction(self.serviceManagerList.delete)
|
||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
@ -359,6 +364,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.shortFileName())
|
self.shortFileName())
|
||||||
Settings(). \
|
Settings(). \
|
||||||
setValue(u'servicemanager/last file',QtCore.QVariant(fileName))
|
setValue(u'servicemanager/last file',QtCore.QVariant(fileName))
|
||||||
|
self._saveLite = True if self._fileName.endswith(u'.oszl') else False
|
||||||
|
|
||||||
def fileName(self):
|
def fileName(self):
|
||||||
"""
|
"""
|
||||||
@ -380,6 +386,13 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
u'advanced/expand service item',
|
u'advanced/expand service item',
|
||||||
QtCore.QVariant(u'False')).toBool()
|
QtCore.QVariant(u'False')).toBool()
|
||||||
|
|
||||||
|
def resetSupportedSuffixes(self):
|
||||||
|
"""
|
||||||
|
Resets the Suffixes list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.suffixes = []
|
||||||
|
|
||||||
def supportedSuffixes(self, suffix):
|
def supportedSuffixes(self, suffix):
|
||||||
"""
|
"""
|
||||||
Adds Suffixes supported to the master list. Called from Plugins.
|
Adds Suffixes supported to the master list. Called from Plugins.
|
||||||
@ -387,6 +400,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
``suffix``
|
``suffix``
|
||||||
New Suffix to be supported
|
New Suffix to be supported
|
||||||
"""
|
"""
|
||||||
|
if not suffix in self.suffixes:
|
||||||
self.suffixes.append(suffix)
|
self.suffixes.append(suffix)
|
||||||
|
|
||||||
def onNewServiceClicked(self):
|
def onNewServiceClicked(self):
|
||||||
@ -398,7 +412,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if result == QtGui.QMessageBox.Cancel:
|
if result == QtGui.QMessageBox.Cancel:
|
||||||
return False
|
return False
|
||||||
elif result == QtGui.QMessageBox.Save:
|
elif result == QtGui.QMessageBox.Save:
|
||||||
if not self.saveFile():
|
if not self.decideSaveMethod():
|
||||||
return False
|
return False
|
||||||
self.newFile()
|
self.newFile()
|
||||||
|
|
||||||
@ -416,7 +430,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if result == QtGui.QMessageBox.Cancel:
|
if result == QtGui.QMessageBox.Cancel:
|
||||||
return False
|
return False
|
||||||
elif result == QtGui.QMessageBox.Save:
|
elif result == QtGui.QMessageBox.Save:
|
||||||
self.saveFile()
|
self.decideSaveMethod()
|
||||||
if not loadFile:
|
if not loadFile:
|
||||||
fileName = unicode(QtGui.QFileDialog.getOpenFileName(
|
fileName = unicode(QtGui.QFileDialog.getOpenFileName(
|
||||||
self.mainwindow,
|
self.mainwindow,
|
||||||
@ -424,7 +438,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
SettingsManager.get_last_dir(
|
SettingsManager.get_last_dir(
|
||||||
self.mainwindow.serviceManagerSettingsSection),
|
self.mainwindow.serviceManagerSettingsSection),
|
||||||
translate('OpenLP.ServiceManager',
|
translate('OpenLP.ServiceManager',
|
||||||
'OpenLP Service Files (*.osz)')))
|
'OpenLP Service Files (*.osz *.oszl)')))
|
||||||
if not fileName:
|
if not fileName:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@ -525,7 +539,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if not item[u'service_item'].validate():
|
if not item[u'service_item'].validate():
|
||||||
self.serviceItems.remove(item)
|
self.serviceItems.remove(item)
|
||||||
else:
|
else:
|
||||||
service_item = item[u'service_item'].get_service_repr()
|
service_item = item[u'service_item'].get_service_repr(self._saveLite)
|
||||||
if service_item[u'header'][u'background_audio']:
|
if service_item[u'header'][u'background_audio']:
|
||||||
for i, filename in enumerate(
|
for i, filename in enumerate(
|
||||||
service_item[u'header'][u'background_audio']):
|
service_item[u'header'][u'background_audio']):
|
||||||
@ -596,6 +610,73 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
delete_file(temp_file_name)
|
delete_file(temp_file_name)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
def saveLocalFile(self):
|
||||||
|
"""
|
||||||
|
Save the current service file.
|
||||||
|
|
||||||
|
A temporary file is created so that we don't overwrite the existing one
|
||||||
|
and leave a mangled service file should there be an error when saving.
|
||||||
|
No files are added to this version of the service as it is deisgned
|
||||||
|
to only work on the machine it was save on if there are files.
|
||||||
|
"""
|
||||||
|
if not self.fileName():
|
||||||
|
return self.saveFileAs()
|
||||||
|
temp_file, temp_file_name = mkstemp(u'.oszl', u'openlp_')
|
||||||
|
# We don't need the file handle.
|
||||||
|
os.close(temp_file)
|
||||||
|
log.debug(temp_file_name)
|
||||||
|
path_file_name = unicode(self.fileName())
|
||||||
|
path, file_name = os.path.split(path_file_name)
|
||||||
|
basename = os.path.splitext(file_name)[0]
|
||||||
|
service_file_name = '%s.osd' % basename
|
||||||
|
log.debug(u'ServiceManager.saveFile - %s', path_file_name)
|
||||||
|
SettingsManager.set_last_dir(
|
||||||
|
self.mainwindow.serviceManagerSettingsSection,
|
||||||
|
path)
|
||||||
|
service = []
|
||||||
|
Receiver.send_message(u'cursor_busy')
|
||||||
|
# Number of items + 1 to zip it
|
||||||
|
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
|
||||||
|
for item in self.serviceItems:
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
|
service_item = item[u'service_item']. \
|
||||||
|
get_service_repr(self._saveLite)
|
||||||
|
#@todo check for file item on save.
|
||||||
|
service.append({u'serviceitem': service_item})
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
|
service_content = cPickle.dumps(service)
|
||||||
|
zip = None
|
||||||
|
success = True
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
|
try:
|
||||||
|
zip = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED,
|
||||||
|
True)
|
||||||
|
# First we add service contents.
|
||||||
|
zip.writestr(service_file_name.encode(u'utf-8'), service_content)
|
||||||
|
except IOError:
|
||||||
|
log.exception(u'Failed to save service to disk: %s', temp_file_name)
|
||||||
|
Receiver.send_message(u'openlp_error_message', {
|
||||||
|
u'title': translate(u'OpenLP.ServiceManager',
|
||||||
|
u'Error Saving File'),
|
||||||
|
u'message': translate(u'OpenLP.ServiceManager',
|
||||||
|
u'There was an error saving your file.')
|
||||||
|
})
|
||||||
|
success = False
|
||||||
|
finally:
|
||||||
|
if zip:
|
||||||
|
zip.close()
|
||||||
|
self.mainwindow.finishedProgressBar()
|
||||||
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
if success:
|
||||||
|
try:
|
||||||
|
shutil.copy(temp_file_name, path_file_name)
|
||||||
|
except:
|
||||||
|
return self.saveFileAs()
|
||||||
|
self.mainwindow.addRecentFile(path_file_name)
|
||||||
|
self.setModified(False)
|
||||||
|
delete_file(temp_file_name)
|
||||||
|
return success
|
||||||
|
|
||||||
def saveFileAs(self):
|
def saveFileAs(self):
|
||||||
"""
|
"""
|
||||||
Get a file name and then call :func:`ServiceManager.saveFile` to
|
Get a file name and then call :func:`ServiceManager.saveFile` to
|
||||||
@ -632,9 +713,19 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
directory = unicode(SettingsManager.get_last_dir(
|
directory = unicode(SettingsManager.get_last_dir(
|
||||||
self.mainwindow.serviceManagerSettingsSection))
|
self.mainwindow.serviceManagerSettingsSection))
|
||||||
path = os.path.join(directory, default_filename)
|
path = os.path.join(directory, default_filename)
|
||||||
fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow,
|
# SaveAs from osz to oszl is not valid as the files will be deleted
|
||||||
UiStrings().SaveService, path,
|
# on exit which is not sensible or usable in the long term.
|
||||||
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))
|
if self._fileName.endswith(u'oszl') or not self._fileName:
|
||||||
|
fileName = unicode(QtGui.QFileDialog.getSaveFileName(
|
||||||
|
self.mainwindow, UiStrings().SaveService, path,
|
||||||
|
translate('OpenLP.ServiceManager',
|
||||||
|
'OpenLP Service Files (*.osz);;'
|
||||||
|
'OpenLP Service Files - lite (*.oszl)')))
|
||||||
|
else:
|
||||||
|
fileName = unicode(QtGui.QFileDialog.getSaveFileName(
|
||||||
|
self.mainwindow, UiStrings().SaveService, path,
|
||||||
|
translate('OpenLP.ServiceManager',
|
||||||
|
'OpenLP Service Files (*.osz);;')))
|
||||||
if not fileName:
|
if not fileName:
|
||||||
return False
|
return False
|
||||||
if os.path.splitext(fileName)[1] == u'':
|
if os.path.splitext(fileName)[1] == u'':
|
||||||
@ -643,9 +734,23 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
ext = os.path.splitext(fileName)[1]
|
ext = os.path.splitext(fileName)[1]
|
||||||
fileName.replace(ext, u'.osz')
|
fileName.replace(ext, u'.osz')
|
||||||
self.setFileName(fileName)
|
self.setFileName(fileName)
|
||||||
|
self.decideSaveMethod()
|
||||||
|
|
||||||
|
def decideSaveMethod(self):
|
||||||
|
"""
|
||||||
|
Determine which type of save method to use.
|
||||||
|
"""
|
||||||
|
if not self.fileName():
|
||||||
|
return self.saveFileAs()
|
||||||
|
if self._saveLite:
|
||||||
|
return self.saveLocalFile()
|
||||||
|
else:
|
||||||
return self.saveFile()
|
return self.saveFile()
|
||||||
|
|
||||||
def loadFile(self, fileName):
|
def loadFile(self, fileName):
|
||||||
|
"""
|
||||||
|
Load an existing service file
|
||||||
|
"""
|
||||||
if not fileName:
|
if not fileName:
|
||||||
return False
|
return False
|
||||||
fileName = unicode(fileName)
|
fileName = unicode(fileName)
|
||||||
@ -680,11 +785,15 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
items = cPickle.load(fileTo)
|
items = cPickle.load(fileTo)
|
||||||
fileTo.close()
|
fileTo.close()
|
||||||
self.newFile()
|
self.newFile()
|
||||||
|
self.setFileName(fileName)
|
||||||
self.mainwindow.displayProgressBar(len(items))
|
self.mainwindow.displayProgressBar(len(items))
|
||||||
for item in items:
|
for item in items:
|
||||||
self.mainwindow.incrementProgressBar()
|
self.mainwindow.incrementProgressBar()
|
||||||
serviceItem = ServiceItem()
|
serviceItem = ServiceItem()
|
||||||
serviceItem.renderer = self.mainwindow.renderer
|
serviceItem.renderer = self.mainwindow.renderer
|
||||||
|
if self._saveLite:
|
||||||
|
serviceItem.set_from_service(item)
|
||||||
|
else:
|
||||||
serviceItem.set_from_service(item, self.servicePath)
|
serviceItem.set_from_service(item, self.servicePath)
|
||||||
self.validateItem(serviceItem)
|
self.validateItem(serviceItem)
|
||||||
self.load_item_uuid = 0
|
self.load_item_uuid = 0
|
||||||
@ -697,7 +806,6 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
serviceItem.temporary_edit = self.load_item_temporary
|
serviceItem.temporary_edit = self.load_item_temporary
|
||||||
self.addServiceItem(serviceItem, repaint=False)
|
self.addServiceItem(serviceItem, repaint=False)
|
||||||
delete_file(p_file)
|
delete_file(p_file)
|
||||||
self.setFileName(fileName)
|
|
||||||
self.mainwindow.addRecentFile(fileName)
|
self.mainwindow.addRecentFile(fileName)
|
||||||
self.setModified(False)
|
self.setModified(False)
|
||||||
Settings().setValue(
|
Settings().setValue(
|
||||||
@ -760,6 +868,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.maintainAction.setVisible(False)
|
self.maintainAction.setVisible(False)
|
||||||
self.notesAction.setVisible(False)
|
self.notesAction.setVisible(False)
|
||||||
self.timeAction.setVisible(False)
|
self.timeAction.setVisible(False)
|
||||||
|
self.autoStartAction.setVisible(False)
|
||||||
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanEdit)\
|
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanEdit)\
|
||||||
and serviceItem[u'service_item'].edit_id:
|
and serviceItem[u'service_item'].edit_id:
|
||||||
self.editAction.setVisible(True)
|
self.editAction.setVisible(True)
|
||||||
@ -771,6 +880,14 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if serviceItem[u'service_item']\
|
if serviceItem[u'service_item']\
|
||||||
.is_capable(ItemCapabilities.HasVariableStartTime):
|
.is_capable(ItemCapabilities.HasVariableStartTime):
|
||||||
self.timeAction.setVisible(True)
|
self.timeAction.setVisible(True)
|
||||||
|
if serviceItem[u'service_item']\
|
||||||
|
.is_capable(ItemCapabilities.CanAutoStartForLive):
|
||||||
|
self.autoStartAction.setVisible(True)
|
||||||
|
self.autoStartAction.setIcon(self.inactive)
|
||||||
|
self.autoStartAction.setText(translate('OpenLP.ServiceManager','&Auto Start - inactive'))
|
||||||
|
if serviceItem[u'service_item'].will_auto_start:
|
||||||
|
self.autoStartAction.setText(translate('OpenLP.ServiceManager', '&Auto Start - active'))
|
||||||
|
self.autoStartAction.setIcon(self.active)
|
||||||
self.themeMenu.menuAction().setVisible(False)
|
self.themeMenu.menuAction().setVisible(False)
|
||||||
# Set up the theme menu.
|
# Set up the theme menu.
|
||||||
if serviceItem[u'service_item'].is_text() and \
|
if serviceItem[u'service_item'].is_text() and \
|
||||||
@ -805,6 +922,14 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if self.startTimeForm.exec_():
|
if self.startTimeForm.exec_():
|
||||||
self.repaintServiceList(item, -1)
|
self.repaintServiceList(item, -1)
|
||||||
|
|
||||||
|
def onAutoStart(self):
|
||||||
|
"""
|
||||||
|
Toggles to Auto Start Setting.
|
||||||
|
"""
|
||||||
|
item = self.findServiceItem()[0]
|
||||||
|
self.serviceItems[item][u'service_item'].will_auto_start = \
|
||||||
|
not self.serviceItems[item][u'service_item'].will_auto_start
|
||||||
|
|
||||||
def onServiceItemEditForm(self):
|
def onServiceItemEditForm(self):
|
||||||
"""
|
"""
|
||||||
Opens a dialog to edit the service item and update the service
|
Opens a dialog to edit the service item and update the service
|
||||||
@ -1095,10 +1220,12 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
Validates the service item and if the suffix matches an accepted
|
Validates the service item and if the suffix matches an accepted
|
||||||
one it allows the item to be displayed.
|
one it allows the item to be displayed.
|
||||||
"""
|
"""
|
||||||
|
#@todo check file items exist
|
||||||
if serviceItem.is_command():
|
if serviceItem.is_command():
|
||||||
type = serviceItem._raw_frames[0][u'title'].split(u'.')[-1]
|
type = serviceItem._raw_frames[0][u'title'].split(u'.')[-1]
|
||||||
if type.lower() not in self.suffixes:
|
if type.lower() not in self.suffixes:
|
||||||
serviceItem.is_valid = False
|
serviceItem.is_valid = False
|
||||||
|
#@todo check file items exist
|
||||||
|
|
||||||
def cleanUp(self):
|
def cleanUp(self):
|
||||||
"""
|
"""
|
||||||
@ -1379,6 +1506,9 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
filename = unicode(url.toLocalFile())
|
filename = unicode(url.toLocalFile())
|
||||||
if filename.endswith(u'.osz'):
|
if filename.endswith(u'.osz'):
|
||||||
self.onLoadServiceClicked(filename)
|
self.onLoadServiceClicked(filename)
|
||||||
|
elif filename.endswith(u'.oszl'):
|
||||||
|
# todo correct
|
||||||
|
self.onLoadServiceClicked(filename)
|
||||||
elif link.hasText():
|
elif link.hasText():
|
||||||
plugin = unicode(link.text())
|
plugin = unicode(link.text())
|
||||||
item = self.serviceManagerList.itemAt(event.pos())
|
item = self.serviceManagerList.itemAt(event.pos())
|
||||||
|
@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import Receiver, build_icon, PluginStatus
|
from openlp.core.lib import Receiver, build_icon, PluginStatus
|
||||||
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
|
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
|
||||||
|
from openlp.core.ui.media import PlayerTab
|
||||||
from settingsdialog import Ui_SettingsDialog
|
from settingsdialog import Ui_SettingsDialog
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -47,6 +48,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
"""
|
"""
|
||||||
Initialise the settings form
|
Initialise the settings form
|
||||||
"""
|
"""
|
||||||
|
self.mainWindow = mainWindow
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
# General tab
|
# General tab
|
||||||
@ -55,6 +57,8 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
self.themesTab = ThemesTab(self, mainWindow)
|
self.themesTab = ThemesTab(self, mainWindow)
|
||||||
# Advanced tab
|
# Advanced tab
|
||||||
self.advancedTab = AdvancedTab(self)
|
self.advancedTab = AdvancedTab(self)
|
||||||
|
# Advanced tab
|
||||||
|
self.playerTab = PlayerTab(self, mainWindow)
|
||||||
|
|
||||||
def exec_(self):
|
def exec_(self):
|
||||||
# load all the settings
|
# load all the settings
|
||||||
@ -65,7 +69,8 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
self.insertTab(self.generalTab, 0, PluginStatus.Active)
|
self.insertTab(self.generalTab, 0, PluginStatus.Active)
|
||||||
self.insertTab(self.themesTab, 1, PluginStatus.Active)
|
self.insertTab(self.themesTab, 1, PluginStatus.Active)
|
||||||
self.insertTab(self.advancedTab, 2, PluginStatus.Active)
|
self.insertTab(self.advancedTab, 2, PluginStatus.Active)
|
||||||
count = 3
|
self.insertTab(self.playerTab, 3, PluginStatus.Active)
|
||||||
|
count = 4
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.settingsTab:
|
if plugin.settingsTab:
|
||||||
self.insertTab(plugin.settingsTab, count, plugin.status)
|
self.insertTab(plugin.settingsTab, count, plugin.status)
|
||||||
@ -94,6 +99,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
"""
|
"""
|
||||||
Process the form saving the settings
|
Process the form saving the settings
|
||||||
"""
|
"""
|
||||||
|
self.resetSuffixes = True
|
||||||
for tabIndex in range(self.stackedLayout.count()):
|
for tabIndex in range(self.stackedLayout.count()):
|
||||||
self.stackedLayout.widget(tabIndex).save()
|
self.stackedLayout.widget(tabIndex).save()
|
||||||
# Must go after all settings are save
|
# Must go after all settings are save
|
||||||
@ -115,6 +121,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
self.generalTab.postSetUp()
|
self.generalTab.postSetUp()
|
||||||
self.themesTab.postSetUp()
|
self.themesTab.postSetUp()
|
||||||
self.advancedTab.postSetUp()
|
self.advancedTab.postSetUp()
|
||||||
|
self.playerTab.postSetUp()
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.settingsTab:
|
if plugin.settingsTab:
|
||||||
plugin.settingsTab.postSetUp()
|
plugin.settingsTab.postSetUp()
|
||||||
@ -125,3 +132,13 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
"""
|
"""
|
||||||
self.stackedLayout.setCurrentIndex(tabIndex)
|
self.stackedLayout.setCurrentIndex(tabIndex)
|
||||||
self.stackedLayout.currentWidget().tabVisible()
|
self.stackedLayout.currentWidget().tabVisible()
|
||||||
|
|
||||||
|
def resetSupportedSuffixes(self):
|
||||||
|
"""
|
||||||
|
Control the resetting of the serviceManager suffix list as can be
|
||||||
|
called by a number of settings tab and only needs to be called once
|
||||||
|
per save.
|
||||||
|
"""
|
||||||
|
if self.resetSuffixes:
|
||||||
|
self.mainWindow.serviceManagerContents.resetSupportedSuffixes()
|
||||||
|
self.resetSuffixes = False
|
@ -223,10 +223,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||||||
self.alternatePushButton.setChecked(column not in [0, 1])
|
self.alternatePushButton.setChecked(column not in [0, 1])
|
||||||
if column in [0, 1]:
|
if column in [0, 1]:
|
||||||
self.primaryPushButton.setText(u'')
|
self.primaryPushButton.setText(u'')
|
||||||
self.primaryPushButton.setFocus(QtCore.Qt.OtherFocusReason)
|
self.primaryPushButton.setFocus()
|
||||||
else:
|
else:
|
||||||
self.alternatePushButton.setText(u'')
|
self.alternatePushButton.setText(u'')
|
||||||
self.alternatePushButton.setFocus(QtCore.Qt.OtherFocusReason)
|
self.alternatePushButton.setFocus()
|
||||||
|
|
||||||
def onCurrentItemChanged(self, item=None, previousItem=None):
|
def onCurrentItemChanged(self, item=None, previousItem=None):
|
||||||
"""
|
"""
|
||||||
|
@ -39,23 +39,16 @@ from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
|
|||||||
from openlp.core.lib.ui import UiStrings, create_action
|
from openlp.core.lib.ui import UiStrings, create_action
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.lib import SlideLimits, ServiceItemAction
|
from openlp.core.lib import SlideLimits, ServiceItemAction
|
||||||
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList
|
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList, \
|
||||||
|
DisplayControllerType
|
||||||
from openlp.core.utils.actions import ActionList, CategoryOrder
|
from openlp.core.utils.actions import ActionList, CategoryOrder
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SlideList(QtGui.QTableWidget):
|
|
||||||
"""
|
|
||||||
Customised version of QTableWidget which can respond to keyboard
|
|
||||||
events.
|
|
||||||
"""
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
QtGui.QTableWidget.__init__(self, parent.controller)
|
|
||||||
|
|
||||||
|
class DisplayController(QtGui.QWidget):
|
||||||
class Controller(QtGui.QWidget):
|
|
||||||
"""
|
"""
|
||||||
Controller is a general controller widget.
|
Controller is a general display controller widget.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, isLive=False):
|
def __init__(self, parent, isLive=False):
|
||||||
"""
|
"""
|
||||||
@ -64,6 +57,7 @@ class Controller(QtGui.QWidget):
|
|||||||
QtGui.QWidget.__init__(self, parent)
|
QtGui.QWidget.__init__(self, parent)
|
||||||
self.isLive = isLive
|
self.isLive = isLive
|
||||||
self.display = None
|
self.display = None
|
||||||
|
self.controllerType = DisplayControllerType.Plugin
|
||||||
|
|
||||||
def sendToPlugins(self, *args):
|
def sendToPlugins(self, *args):
|
||||||
"""
|
"""
|
||||||
@ -77,7 +71,7 @@ class Controller(QtGui.QWidget):
|
|||||||
Receiver.send_message('%s' % sender, [controller, args])
|
Receiver.send_message('%s' % sender, [controller, args])
|
||||||
|
|
||||||
|
|
||||||
class SlideController(Controller):
|
class SlideController(DisplayController):
|
||||||
"""
|
"""
|
||||||
SlideController is the slide controller widget. This widget is what the
|
SlideController is the slide controller widget. This widget is what the
|
||||||
user uses to control the displaying of verses/slides/etc on the screen.
|
user uses to control the displaying of verses/slides/etc on the screen.
|
||||||
@ -86,7 +80,7 @@ class SlideController(Controller):
|
|||||||
"""
|
"""
|
||||||
Set up the Slide Controller.
|
Set up the Slide Controller.
|
||||||
"""
|
"""
|
||||||
Controller.__init__(self, parent, isLive)
|
DisplayController.__init__(self, parent, isLive)
|
||||||
self.screens = ScreenList()
|
self.screens = ScreenList()
|
||||||
try:
|
try:
|
||||||
self.ratio = float(self.screens.current[u'size'].width()) / \
|
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||||
@ -150,7 +144,7 @@ class SlideController(Controller):
|
|||||||
self.controllerLayout.setSpacing(0)
|
self.controllerLayout.setSpacing(0)
|
||||||
self.controllerLayout.setMargin(0)
|
self.controllerLayout.setMargin(0)
|
||||||
# Controller list view
|
# Controller list view
|
||||||
self.previewListWidget = SlideList(self)
|
self.previewListWidget = QtGui.QTableWidget(self.controller)
|
||||||
self.previewListWidget.setColumnCount(1)
|
self.previewListWidget.setColumnCount(1)
|
||||||
self.previewListWidget.horizontalHeader().setVisible(False)
|
self.previewListWidget.horizontalHeader().setVisible(False)
|
||||||
self.previewListWidget.setColumnWidth(0, self.controller.width())
|
self.previewListWidget.setColumnWidth(0, self.controller.width())
|
||||||
@ -193,7 +187,9 @@ class SlideController(Controller):
|
|||||||
category=self.category, triggers=self.onSlideSelectedNextAction)
|
category=self.category, triggers=self.onSlideSelectedNextAction)
|
||||||
self.toolbar.addAction(self.nextItem)
|
self.toolbar.addAction(self.nextItem)
|
||||||
self.toolbar.addSeparator()
|
self.toolbar.addSeparator()
|
||||||
|
self.controllerType = DisplayControllerType.Preview
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
|
self.controllerType = DisplayControllerType.Live
|
||||||
# Hide Menu
|
# Hide Menu
|
||||||
self.hideMenu = QtGui.QToolButton(self.toolbar)
|
self.hideMenu = QtGui.QToolButton(self.toolbar)
|
||||||
self.hideMenu.setObjectName(u'hideMenu')
|
self.hideMenu.setObjectName(u'hideMenu')
|
||||||
@ -271,7 +267,7 @@ class SlideController(Controller):
|
|||||||
'Edit and reload song preview.'), triggers=self.onEditSong)
|
'Edit and reload song preview.'), triggers=self.onEditSong)
|
||||||
self.controllerLayout.addWidget(self.toolbar)
|
self.controllerLayout.addWidget(self.toolbar)
|
||||||
# Build the Media Toolbar
|
# Build the Media Toolbar
|
||||||
self.mediaController.add_controller_items(self, self.controllerLayout)
|
self.mediaController.register_controller(self)
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
# Build the Song Toolbar
|
# Build the Song Toolbar
|
||||||
self.songMenu = QtGui.QToolButton(self.toolbar)
|
self.songMenu = QtGui.QToolButton(self.toolbar)
|
||||||
@ -524,7 +520,7 @@ class SlideController(Controller):
|
|||||||
|
|
||||||
def liveEscape(self):
|
def liveEscape(self):
|
||||||
self.display.setVisible(False)
|
self.display.setVisible(False)
|
||||||
self.mediaController.video_stop([self])
|
self.mediaController.media_stop(self)
|
||||||
|
|
||||||
def toggleDisplay(self, action):
|
def toggleDisplay(self, action):
|
||||||
"""
|
"""
|
||||||
@ -594,14 +590,14 @@ class SlideController(Controller):
|
|||||||
float(self.screens.current[u'size'].height())
|
float(self.screens.current[u'size'].height())
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
self.ratio = 1
|
self.ratio = 1
|
||||||
self.mediaController.setup_display(self.display)
|
self.mediaController.setup_display(self.display, False)
|
||||||
self.previewSizeChanged()
|
self.previewSizeChanged()
|
||||||
self.previewDisplay.setup()
|
self.previewDisplay.setup()
|
||||||
serviceItem = ServiceItem()
|
serviceItem = ServiceItem()
|
||||||
self.previewDisplay.webView.setHtml(build_html(serviceItem,
|
self.previewDisplay.webView.setHtml(build_html(serviceItem,
|
||||||
self.previewDisplay.screen, None, self.isLive,
|
self.previewDisplay.screen, None, self.isLive,
|
||||||
plugins=PluginManager.get_instance().plugins))
|
plugins=PluginManager.get_instance().plugins))
|
||||||
self.mediaController.setup_display(self.previewDisplay)
|
self.mediaController.setup_display(self.previewDisplay,True)
|
||||||
if self.serviceItem:
|
if self.serviceItem:
|
||||||
self.refreshServiceItem()
|
self.refreshServiceItem()
|
||||||
|
|
||||||
@ -1351,9 +1347,8 @@ class SlideController(Controller):
|
|||||||
Respond to the arrival of a media service item
|
Respond to the arrival of a media service item
|
||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaStart')
|
log.debug(u'SlideController onMediaStart')
|
||||||
file = item.get_frame_path()
|
self.mediaController.video(self.controllerType, item, self.hideMode())
|
||||||
self.mediaController.video(self, file, False, False, self.hideMode())
|
if not self.isLive:
|
||||||
if not self.isLive or self.mediaController.withLivePreview:
|
|
||||||
self.previewDisplay.show()
|
self.previewDisplay.show()
|
||||||
self.slidePreview.hide()
|
self.slidePreview.hide()
|
||||||
|
|
||||||
@ -1362,7 +1357,7 @@ class SlideController(Controller):
|
|||||||
Respond to a request to close the Video
|
Respond to a request to close the Video
|
||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaClose')
|
log.debug(u'SlideController onMediaClose')
|
||||||
self.mediaController.video_reset(self)
|
self.mediaController.media_reset(self)
|
||||||
self.previewDisplay.hide()
|
self.previewDisplay.hide()
|
||||||
self.slidePreview.show()
|
self.slidePreview.show()
|
||||||
|
|
||||||
|
@ -458,7 +458,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
QtCore.QVariant(theme.theme_name))
|
QtCore.QVariant(theme.theme_name))
|
||||||
self.configUpdated()
|
self.configUpdated()
|
||||||
files = SettingsManager.get_files(self.settingsSection, u'.png')
|
files = SettingsManager.get_files(self.settingsSection, u'.png')
|
||||||
# Sort the themes by its name considering language specific characters.
|
# Sort the themes by its name considering language specific
|
||||||
files.sort(key=lambda file_name: unicode(file_name),
|
files.sort(key=lambda file_name: unicode(file_name),
|
||||||
cmp=locale_compare)
|
cmp=locale_compare)
|
||||||
# now process the file list of png files
|
# now process the file list of png files
|
||||||
|
@ -123,7 +123,7 @@ class AlertsTab(SettingsTab):
|
|||||||
translate('AlertsPlugin.AlertsTab', 'Alert timeout:'))
|
translate('AlertsPlugin.AlertsTab', 'Alert timeout:'))
|
||||||
self.timeoutSpinBox.setSuffix(UiStrings().Seconds)
|
self.timeoutSpinBox.setSuffix(UiStrings().Seconds)
|
||||||
self.previewGroupBox.setTitle(UiStrings().Preview)
|
self.previewGroupBox.setTitle(UiStrings().Preview)
|
||||||
self.fontPreview.setText(UiStrings().OLPV2)
|
self.fontPreview.setText(UiStrings().OLPV2x)
|
||||||
|
|
||||||
def onBackgroundColorButtonClicked(self):
|
def onBackgroundColorButtonClicked(self):
|
||||||
new_color = QtGui.QColorDialog.getColor(
|
new_color = QtGui.QColorDialog.getColor(
|
||||||
|
@ -538,8 +538,7 @@ class BiblesTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
self.bibleThemeComboBox.clear()
|
self.bibleThemeComboBox.clear()
|
||||||
self.bibleThemeComboBox.addItem(u'')
|
self.bibleThemeComboBox.addItem(u'')
|
||||||
for theme in theme_list:
|
self.bibleThemeComboBox.addItems(theme_list)
|
||||||
self.bibleThemeComboBox.addItem(theme)
|
|
||||||
find_and_set_in_combo_box(self.bibleThemeComboBox, self.bible_theme)
|
find_and_set_in_combo_box(self.bibleThemeComboBox, self.bible_theme)
|
||||||
|
|
||||||
def getGreyTextPalette(self, greyed):
|
def getGreyTextPalette(self, greyed):
|
||||||
|
@ -32,7 +32,7 @@ import logging
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
||||||
translate, create_separated_list
|
translate, create_separated_list, ServiceItemContext
|
||||||
from openlp.core.lib.searchedit import SearchEdit
|
from openlp.core.lib.searchedit import SearchEdit
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \
|
from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \
|
||||||
@ -894,7 +894,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
"""
|
"""
|
||||||
Generates and formats the slides for the service item as well as the
|
Generates and formats the slides for the service item as well as the
|
||||||
service item's title.
|
service item's title.
|
||||||
|
@ -76,8 +76,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
def loadThemes(self, themelist):
|
def loadThemes(self, themelist):
|
||||||
self.themeComboBox.clear()
|
self.themeComboBox.clear()
|
||||||
self.themeComboBox.addItem(u'')
|
self.themeComboBox.addItem(u'')
|
||||||
for themename in themelist:
|
self.themeComboBox.addItems(themelist)
|
||||||
self.themeComboBox.addItem(themename)
|
|
||||||
|
|
||||||
def loadCustom(self, id, preview=False):
|
def loadCustom(self, id, preview=False):
|
||||||
"""
|
"""
|
||||||
@ -106,7 +105,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
self.slideListView.addItem(slide[1])
|
self.slideListView.addItem(slide[1])
|
||||||
theme = self.customSlide.theme_name
|
theme = self.customSlide.theme_name
|
||||||
find_and_set_in_combo_box(self.themeComboBox, theme)
|
find_and_set_in_combo_box(self.themeComboBox, theme)
|
||||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.titleEdit.setFocus()
|
||||||
# If not preview hide the preview button.
|
# If not preview hide the preview button.
|
||||||
self.previewButton.setVisible(preview)
|
self.previewButton.setVisible(preview)
|
||||||
|
|
||||||
@ -128,11 +127,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
sxml = CustomXMLBuilder()
|
sxml = CustomXMLBuilder()
|
||||||
sxml.new_document()
|
sxml.new_document()
|
||||||
sxml.add_lyrics_to_song()
|
sxml.add_lyrics_to_song()
|
||||||
count = 1
|
for count in range(self.slideListView.count()):
|
||||||
for i in range(self.slideListView.count()):
|
sxml.add_verse_to_lyrics(u'custom', unicode(count + 1),
|
||||||
sxml.add_verse_to_lyrics(u'custom', unicode(count),
|
unicode(self.slideListView.item(count).text()))
|
||||||
unicode(self.slideListView.item(i).text()))
|
|
||||||
count += 1
|
|
||||||
self.customSlide.title = unicode(self.titleEdit.text())
|
self.customSlide.title = unicode(self.titleEdit.text())
|
||||||
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
|
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
|
||||||
self.customSlide.credits = unicode(self.creditEdit.text())
|
self.customSlide.credits = unicode(self.creditEdit.text())
|
||||||
@ -159,8 +156,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
def onAddButtonClicked(self):
|
def onAddButtonClicked(self):
|
||||||
self.editSlideForm.setText(u'')
|
self.editSlideForm.setText(u'')
|
||||||
if self.editSlideForm.exec_():
|
if self.editSlideForm.exec_():
|
||||||
for slide in self.editSlideForm.getText():
|
self.slideListView.addItems(self.editSlideForm.getText())
|
||||||
self.slideListView.addItem(slide)
|
|
||||||
|
|
||||||
def onEditButtonClicked(self):
|
def onEditButtonClicked(self):
|
||||||
self.editSlideForm.setText(self.slideListView.currentItem().text())
|
self.editSlideForm.setText(self.slideListView.currentItem().text())
|
||||||
@ -171,13 +167,13 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
"""
|
"""
|
||||||
Edits all slides.
|
Edits all slides.
|
||||||
"""
|
"""
|
||||||
slide_list = u''
|
slide_text = u''
|
||||||
for row in range(self.slideListView.count()):
|
for row in range(self.slideListView.count()):
|
||||||
item = self.slideListView.item(row)
|
item = self.slideListView.item(row)
|
||||||
slide_list += item.text()
|
slide_text += item.text()
|
||||||
if row != self.slideListView.count() - 1:
|
if row != self.slideListView.count() - 1:
|
||||||
slide_list += u'\n[===]\n'
|
slide_text += u'\n[===]\n'
|
||||||
self.editSlideForm.setText(slide_list)
|
self.editSlideForm.setText(slide_text)
|
||||||
if self.editSlideForm.exec_():
|
if self.editSlideForm.exec_():
|
||||||
self.updateSlideList(self.editSlideForm.getText(), True)
|
self.updateSlideList(self.editSlideForm.getText(), True)
|
||||||
|
|
||||||
@ -201,21 +197,19 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
"""
|
"""
|
||||||
if edit_all:
|
if edit_all:
|
||||||
self.slideListView.clear()
|
self.slideListView.clear()
|
||||||
for slide in slides:
|
self.slideListView.addItems(slides)
|
||||||
self.slideListView.addItem(slide)
|
|
||||||
else:
|
else:
|
||||||
old_slides = []
|
old_slides = []
|
||||||
old_row = self.slideListView.currentRow()
|
old_row = self.slideListView.currentRow()
|
||||||
# Create a list with all (old/unedited) slides.
|
# Create a list with all (old/unedited) slides.
|
||||||
old_slides = [self.slideListView.item(row).text() for row in \
|
old_slides = [self.slideListView.item(row).text() for row in
|
||||||
range(self.slideListView.count())]
|
range(self.slideListView.count())]
|
||||||
self.slideListView.clear()
|
self.slideListView.clear()
|
||||||
old_slides.pop(old_row)
|
old_slides.pop(old_row)
|
||||||
# Insert all slides to make the old_slides list complete.
|
# Insert all slides to make the old_slides list complete.
|
||||||
for slide in slides:
|
for slide in slides:
|
||||||
old_slides.insert(old_row, slide)
|
old_slides.insert(old_row, slide)
|
||||||
for slide in old_slides:
|
self.slideListView.addItems(old_slides)
|
||||||
self.slideListView.addItem(slide)
|
|
||||||
self.slideListView.repaint()
|
self.slideListView.repaint()
|
||||||
|
|
||||||
def onDeleteButtonClicked(self):
|
def onDeleteButtonClicked(self):
|
||||||
@ -242,14 +236,8 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
self.deleteButton.setEnabled(True)
|
self.deleteButton.setEnabled(True)
|
||||||
self.editButton.setEnabled(True)
|
self.editButton.setEnabled(True)
|
||||||
# Decide if the up/down buttons should be enabled or not.
|
# Decide if the up/down buttons should be enabled or not.
|
||||||
if self.slideListView.count() - 1 == row:
|
self.downButton.setEnabled(self.slideListView.count() - 1 != row)
|
||||||
self.downButton.setEnabled(False)
|
self.upButton.setEnabled(row != 0)
|
||||||
else:
|
|
||||||
self.downButton.setEnabled(True)
|
|
||||||
if row == 0:
|
|
||||||
self.upButton.setEnabled(False)
|
|
||||||
else:
|
|
||||||
self.upButton.setEnabled(True)
|
|
||||||
|
|
||||||
def _validate(self):
|
def _validate(self):
|
||||||
"""
|
"""
|
||||||
|
@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from sqlalchemy.sql import or_, func
|
from sqlalchemy.sql import or_, func
|
||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
||||||
check_item_selected, translate
|
check_item_selected, translate, ServiceItemContext
|
||||||
from openlp.core.lib.ui import UiStrings
|
from openlp.core.lib.ui import UiStrings
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.plugins.custom.forms import EditCustomForm
|
from openlp.plugins.custom.forms import EditCustomForm
|
||||||
@ -195,7 +195,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
self.searchTextEdit.setFocus()
|
self.searchTextEdit.setFocus()
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
|
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
|
||||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
|
@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import SettingsTab, translate, Receiver
|
from openlp.core.lib import SettingsTab, translate, Receiver
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
|
from openlp.core.lib.ui import UiStrings
|
||||||
|
|
||||||
class ImageTab(SettingsTab):
|
class ImageTab(SettingsTab):
|
||||||
"""
|
"""
|
||||||
@ -68,10 +69,8 @@ class ImageTab(SettingsTab):
|
|||||||
QtCore.SIGNAL(u'clicked()'), self.onbackgroundColorButtonClicked)
|
QtCore.SIGNAL(u'clicked()'), self.onbackgroundColorButtonClicked)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.bgColorGroupBox.setTitle(
|
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
|
||||||
translate('ImagesPlugin.ImageTab', 'Background Color'))
|
self.backgroundColorLabel.setText(UiStrings().DefaultColor)
|
||||||
self.backgroundColorLabel.setText(
|
|
||||||
translate('ImagesPlugin.ImageTab', 'Default Color:'))
|
|
||||||
self.informationLabel.setText(
|
self.informationLabel.setText(
|
||||||
translate('ImagesPlugin.ImageTab', 'Visible background for images '
|
translate('ImagesPlugin.ImageTab', 'Visible background for images '
|
||||||
'with aspect ratio different to screen.'))
|
'with aspect ratio different to screen.'))
|
||||||
|
@ -34,7 +34,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
||||||
SettingsManager, translate, check_item_selected, check_directory_exists, \
|
SettingsManager, translate, check_item_selected, check_directory_exists, \
|
||||||
Receiver, create_thumb, validate_thumb
|
Receiver, create_thumb, validate_thumb, ServiceItemContext
|
||||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.utils import AppLocation, delete_file, locale_compare, \
|
from openlp.core.utils import AppLocation, delete_file, locale_compare, \
|
||||||
@ -153,7 +153,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
background = QtGui.QColor(Settings().value(self.settingsSection
|
background = QtGui.QColor(Settings().value(self.settingsSection
|
||||||
+ u'/background color', QtCore.QVariant(u'#000000')))
|
+ u'/background color', QtCore.QVariant(u'#000000')))
|
||||||
if item:
|
if item:
|
||||||
|
@ -34,20 +34,21 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
||||||
SettingsManager, translate, check_item_selected, Receiver, MediaType, \
|
SettingsManager, translate, check_item_selected, Receiver, MediaType, \
|
||||||
ServiceItem, build_html
|
ServiceItem, build_html, ServiceItemContext
|
||||||
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
|
||||||
create_horizontal_adjusting_combo_box
|
create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.ui import Controller, Display
|
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players
|
from openlp.core.ui.media import get_media_players, set_media_players
|
||||||
from openlp.core.utils import locale_compare
|
from openlp.core.utils import locale_compare
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
CLAPPERBOARD = u':/media/slidecontroller_multimedia.png'
|
CLAPPERBOARD = u':/media/slidecontroller_multimedia.png'
|
||||||
VIDEO = QtGui.QImage(u':/media/media_video.png')
|
VIDEO = build_icon(QtGui.QImage(u':/media/media_video.png'))
|
||||||
AUDIO = QtGui.QImage(u':/media/media_audio.png')
|
AUDIO = build_icon(QtGui.QImage(u':/media/media_audio.png'))
|
||||||
DVD_ICON = QtGui.QImage(u':/media/media_video.png')
|
DVDICON = build_icon(QtGui.QImage(u':/media/media_video.png'))
|
||||||
ERROR = QtGui.QImage(u':/general/general_delete.png')
|
ERROR = build_icon(QtGui.QImage(u':/general/general_delete.png'))
|
||||||
|
|
||||||
class MediaMediaItem(MediaManagerItem):
|
class MediaMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
@ -58,39 +59,31 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
def __init__(self, parent, plugin, icon):
|
def __init__(self, parent, plugin, icon):
|
||||||
self.iconPath = u'images/image'
|
self.iconPath = u'images/image'
|
||||||
self.background = False
|
self.background = False
|
||||||
self.previewFunction = CLAPPERBOARD
|
|
||||||
self.automatic = u''
|
self.automatic = u''
|
||||||
MediaManagerItem.__init__(self, parent, plugin, icon)
|
MediaManagerItem.__init__(self, parent, plugin, icon)
|
||||||
self.singleServiceItem = False
|
self.singleServiceItem = False
|
||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
self.mediaObject = None
|
self.mediaObject = None
|
||||||
self.mediaController = Controller(parent)
|
self.displayController = DisplayController(parent)
|
||||||
self.mediaController.controllerLayout = QtGui.QVBoxLayout()
|
self.displayController.controllerLayout = QtGui.QVBoxLayout()
|
||||||
self.plugin.mediaController.add_controller_items(self.mediaController, \
|
self.plugin.mediaController.register_controller(self.displayController)
|
||||||
self.mediaController.controllerLayout)
|
self.plugin.mediaController.set_controls_visible(self.displayController,
|
||||||
self.plugin.mediaController.set_controls_visible(self.mediaController, \
|
|
||||||
False)
|
False)
|
||||||
self.mediaController.previewDisplay = Display(self.mediaController, \
|
self.displayController.previewDisplay = Display(self.displayController,
|
||||||
False, self.mediaController)
|
False, self.displayController)
|
||||||
self.mediaController.previewDisplay.setGeometry(
|
self.displayController.previewDisplay.hide()
|
||||||
|
self.displayController.previewDisplay.setGeometry(
|
||||||
QtCore.QRect(0, 0, 300, 300))
|
QtCore.QRect(0, 0, 300, 300))
|
||||||
self.mediaController.previewDisplay.screen = \
|
self.displayController.previewDisplay.screen = \
|
||||||
{u'size':self.mediaController.previewDisplay.geometry()}
|
{u'size':self.displayController.previewDisplay.geometry()}
|
||||||
self.mediaController.previewDisplay.setup()
|
self.displayController.previewDisplay.setup()
|
||||||
serviceItem = ServiceItem()
|
self.plugin.mediaController.setup_display(
|
||||||
self.mediaController.previewDisplay.webView.setHtml(build_html( \
|
self.displayController.previewDisplay, False)
|
||||||
serviceItem, self.mediaController.previewDisplay.screen, None, \
|
|
||||||
False, None))
|
|
||||||
self.mediaController.previewDisplay.setup()
|
|
||||||
self.plugin.mediaController.setup_display( \
|
|
||||||
self.mediaController.previewDisplay)
|
|
||||||
self.mediaController.previewDisplay.hide()
|
|
||||||
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'video_background_replaced'),
|
QtCore.SIGNAL(u'video_background_replaced'),
|
||||||
self.videobackgroundReplaced)
|
self.videobackgroundReplaced)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild)
|
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild_players)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
|
QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
|
||||||
# Allow DnD from the desktop
|
# Allow DnD from the desktop
|
||||||
@ -98,18 +91,14 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
||||||
self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
|
|
||||||
'Videos (%s);;Audio (%s);;%s (*)')) % (
|
|
||||||
u' '.join(self.plugin.video_extensions_list),
|
|
||||||
u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
|
|
||||||
self.replaceAction.setText(UiStrings().ReplaceBG)
|
self.replaceAction.setText(UiStrings().ReplaceBG)
|
||||||
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
self.resetAction.setText(UiStrings().ResetBG)
|
self.resetAction.setText(UiStrings().ResetBG)
|
||||||
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
||||||
self.automatic = translate('MediaPlugin.MediaItem',
|
self.automatic = UiStrings().Automatic
|
||||||
'Automatic')
|
|
||||||
self.displayTypeLabel.setText(
|
self.displayTypeLabel.setText(
|
||||||
translate('MediaPlugin.MediaItem', 'Use Player:'))
|
translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||||
|
self.rebuild_players()
|
||||||
|
|
||||||
def requiredIcons(self):
|
def requiredIcons(self):
|
||||||
MediaManagerItem.requiredIcons(self)
|
MediaManagerItem.requiredIcons(self)
|
||||||
@ -157,7 +146,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
Called to reset the Live background with the media selected,
|
Called to reset the Live background with the media selected,
|
||||||
"""
|
"""
|
||||||
self.plugin.liveController.mediaController.video_reset( \
|
self.plugin.liveController.mediaController.media_reset(
|
||||||
self.plugin.liveController)
|
self.plugin.liveController)
|
||||||
self.resetAction.setVisible(False)
|
self.resetAction.setVisible(False)
|
||||||
|
|
||||||
@ -177,8 +166,14 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
item = self.listView.currentItem()
|
item = self.listView.currentItem()
|
||||||
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
if self.plugin.liveController.mediaController.video( \
|
service_item = ServiceItem()
|
||||||
self.plugin.liveController, filename, True, True):
|
service_item.title = u'webkit'
|
||||||
|
service_item.shortname = service_item.title
|
||||||
|
(path, name) = os.path.split(filename)
|
||||||
|
service_item.add_from_command(path, name,CLAPPERBOARD)
|
||||||
|
if self.plugin.liveController.mediaController.video(
|
||||||
|
DisplayControllerType.Live, service_item,
|
||||||
|
videoBehindText=True):
|
||||||
self.resetAction.setVisible(True)
|
self.resetAction.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
@ -191,7 +186,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
'the media file "%s" no longer exists.')) % filename)
|
'the media file "%s" no longer exists.')) % filename)
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Live):
|
||||||
if item is None:
|
if item is None:
|
||||||
item = self.listView.currentItem()
|
item = self.listView.currentItem()
|
||||||
if item is None:
|
if item is None:
|
||||||
@ -205,34 +200,24 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
unicode(translate('MediaPlugin.MediaItem',
|
unicode(translate('MediaPlugin.MediaItem',
|
||||||
'The file %s no longer exists.')) % filename)
|
'The file %s no longer exists.')) % filename)
|
||||||
return False
|
return False
|
||||||
self.mediaLength = 0
|
service_item.title = unicode(self.displayTypeComboBox.currentText())
|
||||||
# Get media information and its length.
|
service_item.shortname = service_item.title
|
||||||
#
|
(path, name) = os.path.split(filename)
|
||||||
# This code (mediaController.video()) starts playback but we
|
service_item.add_from_command(path, name, CLAPPERBOARD)
|
||||||
# need only media information not video to start. Otherwise
|
# Only get start and end times if going to a service
|
||||||
# video is played twice. Find another way to get media info
|
if context == ServiceItemContext.Service:
|
||||||
# without loading and starting video playback.
|
# Start media and obtain the length
|
||||||
#
|
if not self.plugin.mediaController.media_length(service_item):
|
||||||
# TODO Test getting media length with other media backends
|
|
||||||
# Phonon/Webkit.
|
|
||||||
if self.plugin.mediaController.video(self.mediaController,
|
|
||||||
filename, muted=False, isBackground=False, isInfo=True,
|
|
||||||
controlsVisible=False):
|
|
||||||
self.mediaLength = self.mediaController.media_info.length
|
|
||||||
service_item.media_length = self.mediaLength
|
|
||||||
if self.mediaLength > 0:
|
|
||||||
service_item.add_capability(
|
|
||||||
ItemCapabilities.HasVariableStartTime)
|
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
service_item.media_length = self.mediaLength
|
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
|
||||||
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
|
|
||||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||||
|
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
|
||||||
|
if Settings().value(self.settingsSection + u'/media auto start',
|
||||||
|
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0]\
|
||||||
|
== QtCore.Qt.Checked:
|
||||||
|
service_item.will_auto_start = True
|
||||||
# force a non-existent theme
|
# force a non-existent theme
|
||||||
service_item.theme = -1
|
service_item.theme = -1
|
||||||
frame = CLAPPERBOARD
|
|
||||||
(path, name) = os.path.split(filename)
|
|
||||||
service_item.add_from_command(path, name, frame)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
@ -241,7 +226,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
|
self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
|
||||||
self.populateDisplayTypes()
|
self.populateDisplayTypes()
|
||||||
|
|
||||||
def rebuild(self):
|
def rebuild_players(self):
|
||||||
"""
|
"""
|
||||||
Rebuild the tab in the media manager when changes are made in
|
Rebuild the tab in the media manager when changes are made in
|
||||||
the settings
|
the settings
|
||||||
@ -249,12 +234,13 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.populateDisplayTypes()
|
self.populateDisplayTypes()
|
||||||
self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
|
self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
|
||||||
'Videos (%s);;Audio (%s);;%s (*)')) % (
|
'Videos (%s);;Audio (%s);;%s (*)')) % (
|
||||||
u' '.join(self.plugin.video_extensions_list),
|
u' '.join(self.plugin.mediaController.video_extensions_list),
|
||||||
u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
|
u' '.join(self.plugin.mediaController.audio_extensions_list),
|
||||||
|
UiStrings().AllFiles)
|
||||||
|
|
||||||
def displaySetup(self):
|
def displaySetup(self):
|
||||||
self.plugin.mediaController.setup_display( \
|
self.plugin.mediaController.setup_display(
|
||||||
self.mediaController.previewDisplay)
|
self.displayController.previewDisplay, False)
|
||||||
|
|
||||||
def populateDisplayTypes(self):
|
def populateDisplayTypes(self):
|
||||||
"""
|
"""
|
||||||
@ -305,18 +291,21 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
if not os.path.exists(track):
|
if not os.path.exists(track):
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
item_name.setIcon(build_icon(ERROR))
|
item_name.setIcon(ERROR)
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
||||||
elif track_info.isFile():
|
elif track_info.isFile():
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
item_name.setIcon(build_icon(VIDEO))
|
if u'*.%s' % (filename.split(u'.')[-1].lower()) in \
|
||||||
|
self.plugin.mediaController.audio_extensions_list:
|
||||||
|
item_name.setIcon(AUDIO)
|
||||||
|
else:
|
||||||
|
item_name.setIcon(VIDEO)
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
||||||
else:
|
else:
|
||||||
filename = os.path.split(unicode(track))[1]
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
item_name = QtGui.QListWidgetItem(filename)
|
||||||
#TODO: add the appropriate Icon
|
item_name.setIcon(build_icon(DVDICON))
|
||||||
#item_name.setIcon(build_icon(DVD_ICON))
|
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
||||||
item_name.setToolTip(track)
|
item_name.setToolTip(track)
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
@ -327,9 +316,9 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
key=lambda filename: os.path.split(unicode(filename))[1])
|
key=lambda filename: os.path.split(unicode(filename))[1])
|
||||||
ext = []
|
ext = []
|
||||||
if type == MediaType.Audio:
|
if type == MediaType.Audio:
|
||||||
ext = self.plugin.audio_extensions_list
|
ext = self.plugin.mediaController.audio_extensions_list
|
||||||
else:
|
else:
|
||||||
ext = self.plugin.video_extensions_list
|
ext = self.plugin.mediaController.video_extensions_list
|
||||||
ext = map(lambda x: x[1:], ext)
|
ext = map(lambda x: x[1:], ext)
|
||||||
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
||||||
return media
|
return media
|
||||||
|
@ -33,6 +33,7 @@ from openlp.core.lib import SettingsTab, translate, Receiver
|
|||||||
from openlp.core.lib.ui import UiStrings, create_button
|
from openlp.core.lib.ui import UiStrings, create_button
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players
|
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, playerName to the QCheckBox class.
|
||||||
@ -45,60 +46,13 @@ class MediaTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
MediaTab is the Media settings tab in the settings dialog.
|
MediaTab is the Media settings tab in the settings dialog.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, title, visible_title, media_players, icon_path):
|
def __init__(self, parent, title, visible_title, icon_path):
|
||||||
self.mediaPlayers = media_players
|
self.parent = parent
|
||||||
self.savedUsedPlayers = None
|
|
||||||
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
|
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
self.setObjectName(u'MediaTab')
|
self.setObjectName(u'MediaTab')
|
||||||
SettingsTab.setupUi(self)
|
SettingsTab.setupUi(self)
|
||||||
self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
|
|
||||||
self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
|
|
||||||
self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
|
|
||||||
self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
|
|
||||||
self.playerCheckBoxes = {}
|
|
||||||
for key, player in self.mediaPlayers.iteritems():
|
|
||||||
player = self.mediaPlayers[key]
|
|
||||||
checkbox = MediaQCheckBox(self.mediaPlayerGroupBox)
|
|
||||||
checkbox.setEnabled(player.available)
|
|
||||||
checkbox.setObjectName(player.name + u'CheckBox')
|
|
||||||
self.playerCheckBoxes[player.name] = checkbox
|
|
||||||
self.mediaPlayerLayout.addWidget(checkbox)
|
|
||||||
self.leftLayout.addWidget(self.mediaPlayerGroupBox)
|
|
||||||
self.playerOrderGroupBox = QtGui.QGroupBox(self.leftColumn)
|
|
||||||
self.playerOrderGroupBox.setObjectName(u'playerOrderGroupBox')
|
|
||||||
self.playerOrderLayout = QtGui.QHBoxLayout(self.playerOrderGroupBox)
|
|
||||||
self.playerOrderLayout.setObjectName(u'playerOrderLayout')
|
|
||||||
self.playerOrderlistWidget = QtGui.QListWidget( \
|
|
||||||
self.playerOrderGroupBox)
|
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
|
|
||||||
QtGui.QSizePolicy.Expanding)
|
|
||||||
sizePolicy.setHorizontalStretch(0)
|
|
||||||
sizePolicy.setVerticalStretch(0)
|
|
||||||
sizePolicy.setHeightForWidth(self.playerOrderlistWidget. \
|
|
||||||
sizePolicy().hasHeightForWidth())
|
|
||||||
self.playerOrderlistWidget.setSizePolicy(sizePolicy)
|
|
||||||
self.playerOrderlistWidget.setVerticalScrollBarPolicy( \
|
|
||||||
QtCore.Qt.ScrollBarAsNeeded)
|
|
||||||
self.playerOrderlistWidget.setHorizontalScrollBarPolicy( \
|
|
||||||
QtCore.Qt.ScrollBarAlwaysOff)
|
|
||||||
self.playerOrderlistWidget.setEditTriggers( \
|
|
||||||
QtGui.QAbstractItemView.NoEditTriggers)
|
|
||||||
self.playerOrderlistWidget.setObjectName(u'playerOrderlistWidget')
|
|
||||||
self.playerOrderLayout.addWidget(self.playerOrderlistWidget)
|
|
||||||
self.orderingButtonLayout = QtGui.QVBoxLayout()
|
|
||||||
self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
|
|
||||||
self.orderingButtonLayout.addStretch(1)
|
|
||||||
self.orderingUpButton = create_button(self, u'orderingUpButton',
|
|
||||||
role=u'up', click=self.onUpButtonClicked)
|
|
||||||
self.orderingDownButton = create_button(self, u'orderingDownButton',
|
|
||||||
role=u'down', click=self.onDownButtonClicked)
|
|
||||||
self.orderingButtonLayout.addWidget(self.orderingUpButton)
|
|
||||||
self.orderingButtonLayout.addWidget(self.orderingDownButton)
|
|
||||||
self.orderingButtonLayout.addStretch(1)
|
|
||||||
self.playerOrderLayout.addLayout(self.orderingButtonLayout)
|
|
||||||
self.leftLayout.addWidget(self.playerOrderGroupBox)
|
|
||||||
self.advancedGroupBox = QtGui.QGroupBox(self.leftColumn)
|
self.advancedGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
self.advancedGroupBox.setObjectName(u'advancedGroupBox')
|
self.advancedGroupBox.setObjectName(u'advancedGroupBox')
|
||||||
self.advancedLayout = QtGui.QVBoxLayout(self.advancedGroupBox)
|
self.advancedLayout = QtGui.QVBoxLayout(self.advancedGroupBox)
|
||||||
@ -106,110 +60,44 @@ class MediaTab(SettingsTab):
|
|||||||
self.overridePlayerCheckBox = QtGui.QCheckBox(self.advancedGroupBox)
|
self.overridePlayerCheckBox = QtGui.QCheckBox(self.advancedGroupBox)
|
||||||
self.overridePlayerCheckBox.setObjectName(u'overridePlayerCheckBox')
|
self.overridePlayerCheckBox.setObjectName(u'overridePlayerCheckBox')
|
||||||
self.advancedLayout.addWidget(self.overridePlayerCheckBox)
|
self.advancedLayout.addWidget(self.overridePlayerCheckBox)
|
||||||
|
self.autoStartCheckBox = QtGui.QCheckBox(self.advancedGroupBox)
|
||||||
|
self.autoStartCheckBox.setObjectName(u'autoStartCheckBox')
|
||||||
|
self.advancedLayout.addWidget(self.autoStartCheckBox)
|
||||||
self.leftLayout.addWidget(self.advancedGroupBox)
|
self.leftLayout.addWidget(self.advancedGroupBox)
|
||||||
self.leftLayout.addStretch()
|
self.leftLayout.addStretch()
|
||||||
self.rightLayout.addStretch()
|
self.rightLayout.addStretch()
|
||||||
for key in self.mediaPlayers:
|
|
||||||
player = self.mediaPlayers[key]
|
|
||||||
checkbox = self.playerCheckBoxes[player.name]
|
|
||||||
QtCore.QObject.connect(checkbox,
|
|
||||||
QtCore.SIGNAL(u'stateChanged(int)'),
|
|
||||||
self.onPlayerCheckBoxChanged)
|
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.mediaPlayerGroupBox.setTitle(
|
|
||||||
translate('MediaPlugin.MediaTab', 'Available Media Players'))
|
|
||||||
for key in self.mediaPlayers:
|
|
||||||
player = self.mediaPlayers[key]
|
|
||||||
checkbox = self.playerCheckBoxes[player.name]
|
|
||||||
checkbox.setPlayerName(player.name)
|
|
||||||
if player.available:
|
|
||||||
checkbox.setText(player.display_name)
|
|
||||||
else:
|
|
||||||
checkbox.setText(
|
|
||||||
unicode(translate('MediaPlugin.MediaTab',
|
|
||||||
'%s (unavailable)')) % player.display_name)
|
|
||||||
self.playerOrderGroupBox.setTitle(
|
|
||||||
translate('MediaPlugin.MediaTab', 'Player Order'))
|
|
||||||
self.advancedGroupBox.setTitle(UiStrings().Advanced)
|
self.advancedGroupBox.setTitle(UiStrings().Advanced)
|
||||||
self.overridePlayerCheckBox.setText(
|
self.overridePlayerCheckBox.setText(
|
||||||
translate('MediaPlugin.MediaTab',
|
translate('MediaPlugin.MediaTab',
|
||||||
'Allow media player to be overridden'))
|
'Allow media player to be overridden'))
|
||||||
|
self.autoStartCheckBox.setText(
|
||||||
def onPlayerCheckBoxChanged(self, check_state):
|
translate('MediaPlugin.MediaTab',
|
||||||
player = self.sender().playerName
|
'Start Live items automatically'))
|
||||||
if check_state == QtCore.Qt.Checked:
|
|
||||||
if player not in self.usedPlayers:
|
|
||||||
self.usedPlayers.append(player)
|
|
||||||
else:
|
|
||||||
if player in self.usedPlayers:
|
|
||||||
self.usedPlayers.remove(player)
|
|
||||||
self.updatePlayerList()
|
|
||||||
|
|
||||||
def updatePlayerList(self):
|
|
||||||
self.playerOrderlistWidget.clear()
|
|
||||||
for player in self.usedPlayers:
|
|
||||||
if player in self.playerCheckBoxes.keys():
|
|
||||||
if len(self.usedPlayers) == 1:
|
|
||||||
# At least one media player has to stay active
|
|
||||||
self.playerCheckBoxes[u'%s' % player].setEnabled(False)
|
|
||||||
else:
|
|
||||||
self.playerCheckBoxes[u'%s' % player].setEnabled(True)
|
|
||||||
self.playerOrderlistWidget.addItem(
|
|
||||||
self.mediaPlayers[unicode(player)].original_name)
|
|
||||||
|
|
||||||
def onUpButtonClicked(self):
|
|
||||||
row = self.playerOrderlistWidget.currentRow()
|
|
||||||
if row <= 0:
|
|
||||||
return
|
|
||||||
item = self.playerOrderlistWidget.takeItem(row)
|
|
||||||
self.playerOrderlistWidget.insertItem(row - 1, item)
|
|
||||||
self.playerOrderlistWidget.setCurrentRow(row - 1)
|
|
||||||
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
|
|
||||||
|
|
||||||
def onDownButtonClicked(self):
|
|
||||||
row = self.playerOrderlistWidget.currentRow()
|
|
||||||
if row == -1 or row > self.playerOrderlistWidget.count() - 1:
|
|
||||||
return
|
|
||||||
item = self.playerOrderlistWidget.takeItem(row)
|
|
||||||
self.playerOrderlistWidget.insertItem(row + 1, item)
|
|
||||||
self.playerOrderlistWidget.setCurrentRow(row + 1)
|
|
||||||
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
if self.savedUsedPlayers:
|
|
||||||
self.usedPlayers = self.savedUsedPlayers
|
|
||||||
self.usedPlayers = get_media_players()[0]
|
|
||||||
self.savedUsedPlayers = self.usedPlayers
|
|
||||||
for key in self.mediaPlayers:
|
|
||||||
player = self.mediaPlayers[key]
|
|
||||||
checkbox = self.playerCheckBoxes[player.name]
|
|
||||||
if player.available and player.name in self.usedPlayers:
|
|
||||||
checkbox.setChecked(True)
|
|
||||||
else:
|
|
||||||
checkbox.setChecked(False)
|
|
||||||
self.updatePlayerList()
|
|
||||||
self.overridePlayerCheckBox.setChecked(Settings().value(
|
self.overridePlayerCheckBox.setChecked(Settings().value(
|
||||||
self.settingsSection + u'/override player',
|
self.settingsSection + u'/override player',
|
||||||
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
|
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
|
||||||
|
self.autoStartCheckBox.setChecked(Settings().value(
|
||||||
|
self.settingsSection + u'/media auto start',
|
||||||
|
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
override_changed = False
|
override_changed = False
|
||||||
player_string_changed = False
|
|
||||||
old_players, override_player = get_media_players()
|
|
||||||
if self.usedPlayers != old_players:
|
|
||||||
# clean old Media stuff
|
|
||||||
set_media_players(self.usedPlayers, override_player)
|
|
||||||
player_string_changed = True
|
|
||||||
override_changed = True
|
|
||||||
setting_key = self.settingsSection + u'/override player'
|
setting_key = self.settingsSection + u'/override player'
|
||||||
if Settings().value(setting_key).toInt()[0] != \
|
if Settings().value(setting_key).toInt()[0] != \
|
||||||
self.overridePlayerCheckBox.checkState():
|
self.overridePlayerCheckBox.checkState():
|
||||||
Settings().setValue(setting_key,
|
Settings().setValue(setting_key,
|
||||||
QtCore.QVariant(self.overridePlayerCheckBox.checkState()))
|
QtCore.QVariant(self.overridePlayerCheckBox.checkState()))
|
||||||
override_changed = True
|
override_changed = True
|
||||||
|
setting_key = self.settingsSection + u'/media auto start'
|
||||||
|
if Settings().value(setting_key).toInt()[0] !=\
|
||||||
|
self.autoStartCheckBox.checkState():
|
||||||
|
Settings().setValue(setting_key,
|
||||||
|
QtCore.QVariant(self.autoStartCheckBox.checkState()))
|
||||||
if override_changed:
|
if override_changed:
|
||||||
|
self.parent.resetSupportedSuffixes()
|
||||||
Receiver.send_message(u'mediaitem_media_rebuild')
|
Receiver.send_message(u'mediaitem_media_rebuild')
|
||||||
if player_string_changed:
|
Receiver.send_message(u'mediaitem_suffixes')
|
||||||
Receiver.send_message(u'mediaitem_media_rebuild')
|
|
||||||
Receiver.send_message(u'config_screen_changed')
|
|
@ -48,14 +48,6 @@ class MediaPlugin(Plugin):
|
|||||||
self.icon = build_icon(self.iconPath)
|
self.icon = build_icon(self.iconPath)
|
||||||
# passed with drag and drop messages
|
# passed with drag and drop messages
|
||||||
self.dnd_id = u'Media'
|
self.dnd_id = u'Media'
|
||||||
self.audio_extensions_list = \
|
|
||||||
self.mediaController.get_audio_extensions_list()
|
|
||||||
for ext in self.audio_extensions_list:
|
|
||||||
self.serviceManager.supportedSuffixes(ext[2:])
|
|
||||||
self.video_extensions_list = \
|
|
||||||
self.mediaController.get_video_extensions_list()
|
|
||||||
for ext in self.video_extensions_list:
|
|
||||||
self.serviceManager.supportedSuffixes(ext[2:])
|
|
||||||
|
|
||||||
def createSettingsTab(self, parent):
|
def createSettingsTab(self, parent):
|
||||||
"""
|
"""
|
||||||
@ -63,7 +55,7 @@ class MediaPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
visible_name = self.getString(StringContent.VisibleName)
|
visible_name = self.getString(StringContent.VisibleName)
|
||||||
self.settingsTab = MediaTab(parent, self.name, visible_name[u'title'],
|
self.settingsTab = MediaTab(parent, self.name, visible_name[u'title'],
|
||||||
self.mediaController.mediaPlayers, self.iconPath)
|
self.iconPath)
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
|
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
|
||||||
|
@ -34,7 +34,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \
|
from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \
|
||||||
translate, check_item_selected, Receiver, ItemCapabilities, create_thumb, \
|
translate, check_item_selected, Receiver, ItemCapabilities, create_thumb, \
|
||||||
validate_thumb
|
validate_thumb, ServiceItemContext
|
||||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
|
||||||
create_horizontal_adjusting_combo_box
|
create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
@ -64,7 +64,10 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
self.singleServiceItem = False
|
self.singleServiceItem = False
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
|
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'),
|
||||||
|
self.populateDisplayTypes)
|
||||||
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
QtCore.SIGNAL(u'mediaitem_suffixes'), self.buildFileMaskString)
|
||||||
# Allow DnD from the desktop
|
# Allow DnD from the desktop
|
||||||
self.listView.activateDnD()
|
self.listView.activateDnD()
|
||||||
|
|
||||||
@ -133,14 +136,6 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
self.loadList(files, True)
|
self.loadList(files, True)
|
||||||
self.populateDisplayTypes()
|
self.populateDisplayTypes()
|
||||||
|
|
||||||
def rebuild(self):
|
|
||||||
"""
|
|
||||||
Rebuild the tab in the media manager when changes are made in
|
|
||||||
the settings
|
|
||||||
"""
|
|
||||||
self.populateDisplayTypes()
|
|
||||||
self.buildFileMaskString()
|
|
||||||
|
|
||||||
def populateDisplayTypes(self):
|
def populateDisplayTypes(self):
|
||||||
"""
|
"""
|
||||||
Load the combobox with the enabled presentation controllers,
|
Load the combobox with the enabled presentation controllers,
|
||||||
@ -260,7 +255,7 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
u'presentations', self.getFileList())
|
u'presentations', self.getFileList())
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
"""
|
"""
|
||||||
Load the relevant information for displaying the presentation
|
Load the relevant information for displaying the presentation
|
||||||
in the slidecontroller. In the case of powerpoints, an image
|
in the slidecontroller. In the case of powerpoints, an image
|
||||||
|
@ -41,6 +41,7 @@ class PresentationTab(SettingsTab):
|
|||||||
"""
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
"""
|
"""
|
||||||
|
self.parent = parent
|
||||||
self.controllers = controllers
|
self.controllers = controllers
|
||||||
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
|
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
|
||||||
self.activated = False
|
self.activated = False
|
||||||
@ -142,7 +143,9 @@ class PresentationTab(SettingsTab):
|
|||||||
QtCore.QVariant(self.OverrideAppCheckBox.checkState()))
|
QtCore.QVariant(self.OverrideAppCheckBox.checkState()))
|
||||||
changed = True
|
changed = True
|
||||||
if changed:
|
if changed:
|
||||||
|
self.parent.resetSupportedSuffixes()
|
||||||
Receiver.send_message(u'mediaitem_presentation_rebuild')
|
Receiver.send_message(u'mediaitem_presentation_rebuild')
|
||||||
|
Receiver.send_message(u'mediaitem_suffixes')
|
||||||
|
|
||||||
def tabVisible(self):
|
def tabVisible(self):
|
||||||
"""
|
"""
|
||||||
|
@ -183,8 +183,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
for plugin in self.parent().pluginManager.plugins:
|
for plugin in self.parent().pluginManager.plugins:
|
||||||
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
|
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
|
||||||
self.audioAddFromMediaButton.setVisible(True)
|
self.audioAddFromMediaButton.setVisible(True)
|
||||||
self.mediaForm.populateFiles(
|
self.mediaForm.populateFiles(plugin.mediaItem.getList(MediaType.Audio))
|
||||||
plugin.mediaItem.getList(MediaType.Audio))
|
|
||||||
break
|
break
|
||||||
|
|
||||||
def newSong(self):
|
def newSong(self):
|
||||||
@ -203,7 +202,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.authorsListView.clear()
|
self.authorsListView.clear()
|
||||||
self.topicsListView.clear()
|
self.topicsListView.clear()
|
||||||
self.audioListWidget.clear()
|
self.audioListWidget.clear()
|
||||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.titleEdit.setFocus()
|
||||||
self.songBookNumberEdit.clear()
|
self.songBookNumberEdit.clear()
|
||||||
self.loadAuthors()
|
self.loadAuthors()
|
||||||
self.loadTopics()
|
self.loadTopics()
|
||||||
@ -326,7 +325,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
media_file.setData(QtCore.Qt.UserRole,
|
media_file.setData(QtCore.Qt.UserRole,
|
||||||
QtCore.QVariant(media.file_name))
|
QtCore.QVariant(media.file_name))
|
||||||
self.audioListWidget.addItem(media_file)
|
self.audioListWidget.addItem(media_file)
|
||||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.titleEdit.setFocus()
|
||||||
# Hide or show the preview button.
|
# Hide or show the preview button.
|
||||||
self.previewButton.setVisible(preview)
|
self.previewButton.setVisible(preview)
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||||||
self.verseNumberBox.setValue(1)
|
self.verseNumberBox.setValue(1)
|
||||||
self.insertButton.setVisible(True)
|
self.insertButton.setVisible(True)
|
||||||
self.verseTextEdit.setPlainText(text)
|
self.verseTextEdit.setPlainText(text)
|
||||||
self.verseTextEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.verseTextEdit.setFocus()
|
||||||
self.verseTextEdit.moveCursor(QtGui.QTextCursor.End)
|
self.verseTextEdit.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
|
||||||
def getVerse(self):
|
def getVerse(self):
|
||||||
|
@ -37,7 +37,7 @@ from sqlalchemy.sql import or_
|
|||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
||||||
translate, check_item_selected, PluginStatus, create_separated_list, \
|
translate, check_item_selected, PluginStatus, create_separated_list, \
|
||||||
check_directory_exists
|
check_directory_exists, ServiceItemContext
|
||||||
from openlp.core.lib.ui import UiStrings, create_widget_action
|
from openlp.core.lib.ui import UiStrings, create_widget_action
|
||||||
from openlp.core.lib.settings import Settings
|
from openlp.core.lib.settings import Settings
|
||||||
from openlp.core.utils import AppLocation, locale_direct_compare
|
from openlp.core.utils import AppLocation, locale_direct_compare
|
||||||
@ -488,7 +488,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.onSongListLoad()
|
self.onSongListLoad()
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
def generateSlideData(self, service_item, item=None, xmlVersion=False,
|
||||||
remote=False):
|
remote=False, context=ServiceItemContext.Service):
|
||||||
log.debug(u'generateSlideData: %s, %s, %s' %
|
log.debug(u'generateSlideData: %s, %s, %s' %
|
||||||
(service_item, item, self.remoteSong))
|
(service_item, item, self.remoteSong))
|
||||||
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
||||||
|
BIN
resources/images/auto-start_active.png
Normal file
BIN
resources/images/auto-start_active.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 815 B |
BIN
resources/images/auto-start_inactive.png
Normal file
BIN
resources/images/auto-start_inactive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 767 B |
BIN
resources/images/multimedia-player.png
Normal file
BIN
resources/images/multimedia-player.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 597 B |
@ -133,6 +133,9 @@
|
|||||||
<file>media_audio.png</file>
|
<file>media_audio.png</file>
|
||||||
<file>media_video.png</file>
|
<file>media_video.png</file>
|
||||||
<file>slidecontroller_multimedia.png</file>
|
<file>slidecontroller_multimedia.png</file>
|
||||||
|
<file>auto-start_active.png</file>
|
||||||
|
<file>auto-start_inactive.png</file>
|
||||||
|
<file>multimedia-player.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="messagebox">
|
<qresource prefix="messagebox">
|
||||||
<file>messagebox_critical.png</file>
|
<file>messagebox_critical.png</file>
|
||||||
|
@ -17,6 +17,11 @@ Notes:
|
|||||||
<sub-class-of type="application/zip"/>
|
<sub-class-of type="application/zip"/>
|
||||||
<comment>OpenLP Service File</comment>
|
<comment>OpenLP Service File</comment>
|
||||||
<glob pattern="*.osz"/>
|
<glob pattern="*.osz"/>
|
||||||
|
</mime-type>
|
||||||
|
<mime-type type="application/x-openlp-service">
|
||||||
|
<sub-class-of type="application/zip"/>
|
||||||
|
<comment>OpenLP Service File</comment>
|
||||||
|
<glob pattern="*.oszl"/>
|
||||||
</mime-type>
|
</mime-type>
|
||||||
<mime-type type="application/x-openlp-theme">
|
<mime-type type="application/x-openlp-theme">
|
||||||
<sub-class-of type="application/zip"/>
|
<sub-class-of type="application/zip"/>
|
||||||
|
34
tests/README.txt
Normal file
34
tests/README.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Tests for OpenLP
|
||||||
|
================
|
||||||
|
|
||||||
|
This directory contains unit tests for OpenLP. The ``functional`` directory contains functional unit tests.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
-------------
|
||||||
|
|
||||||
|
In order to run the unit tests, you will need the following Python packages/libraries installed:
|
||||||
|
|
||||||
|
- Mock
|
||||||
|
- Nose
|
||||||
|
|
||||||
|
On Ubuntu you can simple install the python-mock and python-nose packages. Most other distributions will also have these
|
||||||
|
packages. On Windows and Mac OS X you will need to use ``pip`` or ``easy_install`` to install these packages.
|
||||||
|
|
||||||
|
Running the Tests
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
To run the tests, navigate to the root directory of the OpenLP project, and then run the following command::
|
||||||
|
|
||||||
|
nosetests -v tests
|
||||||
|
|
||||||
|
Or, to run only the functional tests, run the following command::
|
||||||
|
|
||||||
|
nosetests -v tests/functional
|
||||||
|
|
||||||
|
Or, to run only a particular test suite within a file, run the following command::
|
||||||
|
|
||||||
|
nosetests -v tests/functional/test_applocation.py
|
||||||
|
|
||||||
|
Finally, to only run a particular test, run the following command::
|
||||||
|
|
||||||
|
nosetests -v tests/functional/test_applocation.py:TestAppLocation.get_frozen_path_test
|
0
tests/functional/openlp_core_lib/__init__.py
Normal file
0
tests/functional/openlp_core_lib/__init__.py
Normal file
158
tests/functional/openlp_core_lib/test_lib.py
Normal file
158
tests/functional/openlp_core_lib/test_lib.py
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
"""
|
||||||
|
Package to test the openlp.core.lib package.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from mock import MagicMock, patch
|
||||||
|
|
||||||
|
from openlp.core.lib import str_to_bool, translate, check_directory_exists
|
||||||
|
|
||||||
|
class TestLib(TestCase):
|
||||||
|
|
||||||
|
def str_to_bool_with_bool_test(self):
|
||||||
|
"""
|
||||||
|
Test the str_to_bool function with boolean input
|
||||||
|
"""
|
||||||
|
#GIVEN: A boolean value set to true
|
||||||
|
true_boolean = True
|
||||||
|
|
||||||
|
# WHEN: We "convert" it to a bool
|
||||||
|
true_result = str_to_bool(true_boolean)
|
||||||
|
|
||||||
|
# THEN: We should get back a True bool
|
||||||
|
assert isinstance(true_result, bool), u'The result should be a boolean'
|
||||||
|
assert true_result is True, u'The result should be True'
|
||||||
|
|
||||||
|
#GIVEN: A boolean value set to false
|
||||||
|
false_boolean = False
|
||||||
|
|
||||||
|
# WHEN: We "convert" it to a bool
|
||||||
|
false_result = str_to_bool(false_boolean)
|
||||||
|
|
||||||
|
# THEN: We should get back a True bool
|
||||||
|
assert isinstance(false_result, bool), u'The result should be a boolean'
|
||||||
|
assert false_result is False, u'The result should be True'
|
||||||
|
|
||||||
|
def str_to_bool_with_invalid_test(self):
|
||||||
|
"""
|
||||||
|
Test the str_to_bool function with a set of invalid inputs
|
||||||
|
"""
|
||||||
|
# GIVEN: An integer value
|
||||||
|
int_string = 1
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
int_result = str_to_bool(int_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a false
|
||||||
|
assert int_result is False, u'The result should be False'
|
||||||
|
|
||||||
|
# GIVEN: An string value with completely invalid input
|
||||||
|
invalid_string = u'my feet are wet'
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
str_result = str_to_bool(invalid_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a false
|
||||||
|
assert str_result is False, u'The result should be False'
|
||||||
|
|
||||||
|
def str_to_bool_with_false_values_test(self):
|
||||||
|
"""
|
||||||
|
Test the str_to_bool function with a set of false inputs
|
||||||
|
"""
|
||||||
|
# GIVEN: A string set to "false"
|
||||||
|
false_string = u'false'
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
false_result = str_to_bool(false_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a false
|
||||||
|
assert false_result is False, u'The result should be False'
|
||||||
|
|
||||||
|
# GIVEN: An string set to "NO"
|
||||||
|
no_string = u'NO'
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
str_result = str_to_bool(no_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a false
|
||||||
|
assert str_result is False, u'The result should be False'
|
||||||
|
|
||||||
|
def str_to_bool_with_true_values_test(self):
|
||||||
|
"""
|
||||||
|
Test the str_to_bool function with a set of true inputs
|
||||||
|
"""
|
||||||
|
# GIVEN: A string set to "True"
|
||||||
|
true_string = u'True'
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
true_result = str_to_bool(true_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a true
|
||||||
|
assert true_result is True, u'The result should be True'
|
||||||
|
|
||||||
|
# GIVEN: An string set to "yes"
|
||||||
|
yes_string = u'yes'
|
||||||
|
|
||||||
|
# WHEN: we convert it to a bool
|
||||||
|
str_result = str_to_bool(yes_string)
|
||||||
|
|
||||||
|
# THEN: we should get back a true
|
||||||
|
assert str_result is True, u'The result should be True'
|
||||||
|
|
||||||
|
def translate_test(self):
|
||||||
|
"""
|
||||||
|
Test the translate() function
|
||||||
|
"""
|
||||||
|
# GIVEN: A string to translate and a mocked Qt translate function
|
||||||
|
context = u'OpenLP.Tests'
|
||||||
|
text = u'Untranslated string'
|
||||||
|
comment = u'A comment'
|
||||||
|
encoding = 1
|
||||||
|
n = 1
|
||||||
|
mocked_translate = MagicMock(return_value=u'Translated string')
|
||||||
|
|
||||||
|
# WHEN: we call the translate function
|
||||||
|
result = translate(context, text, comment, encoding, n, mocked_translate)
|
||||||
|
|
||||||
|
# THEN: the translated string should be returned, and the mocked function should have been called
|
||||||
|
mocked_translate.assert_called_with(context, text, comment, encoding, n)
|
||||||
|
assert result == u'Translated string', u'The translated string should have been returned'
|
||||||
|
|
||||||
|
def check_directory_exists_test(self):
|
||||||
|
"""
|
||||||
|
Test the check_directory_exists() function
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.lib.os.path.exists') as mocked_exists, \
|
||||||
|
patch(u'openlp.core.lib.os.makedirs') as mocked_makedirs:
|
||||||
|
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
|
||||||
|
directory_to_check = u'existing/directory'
|
||||||
|
|
||||||
|
# WHEN: os.path.exists returns True and we check to see if the directory exists
|
||||||
|
mocked_exists.return_value = True
|
||||||
|
check_directory_exists(directory_to_check)
|
||||||
|
|
||||||
|
# THEN: Only os.path.exists should have been called
|
||||||
|
mocked_exists.assert_called_with(directory_to_check)
|
||||||
|
assert not mocked_makedirs.called, u'os.makedirs should not have been called'
|
||||||
|
|
||||||
|
# WHEN: os.path.exists returns False and we check the directory exists
|
||||||
|
mocked_exists.return_value = False
|
||||||
|
check_directory_exists(directory_to_check)
|
||||||
|
|
||||||
|
# THEN: Both the mocked functions should have been called
|
||||||
|
mocked_exists.assert_called_with(directory_to_check)
|
||||||
|
mocked_makedirs.assert_called_with(directory_to_check)
|
||||||
|
|
||||||
|
# WHEN: os.path.exists raises an IOError
|
||||||
|
mocked_exists.side_effect = IOError()
|
||||||
|
check_directory_exists(directory_to_check)
|
||||||
|
|
||||||
|
# THEN: We shouldn't get an exception though the mocked exists has been called
|
||||||
|
mocked_exists.assert_called_with(directory_to_check)
|
||||||
|
|
||||||
|
# WHEN: Some other exception is raised
|
||||||
|
mocked_exists.side_effect = ValueError()
|
||||||
|
|
||||||
|
# THEN: check_directory_exists raises an exception
|
||||||
|
mocked_exists.assert_called_with(directory_to_check)
|
||||||
|
self.assertRaises(ValueError, check_directory_exists, directory_to_check)
|
1
tests/functional/openlp_core_utils/__init__.py
Normal file
1
tests/functional/openlp_core_utils/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__author__ = 'raoul'
|
98
tests/functional/openlp_core_utils/test_applocation.py
Normal file
98
tests/functional/openlp_core_utils/test_applocation.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
"""
|
||||||
|
Functional tests to test the AppLocation class and related methods.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from openlp.core.utils import AppLocation
|
||||||
|
|
||||||
|
class TestAppLocation(TestCase):
|
||||||
|
"""
|
||||||
|
A test suite to test out various methods around the AppLocation class.
|
||||||
|
"""
|
||||||
|
def get_data_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the AppLocation.get_data_path() method
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.Settings') as mocked_class, \
|
||||||
|
patch(u'openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
|
||||||
|
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists, \
|
||||||
|
patch(u'openlp.core.utils.os') as mocked_os:
|
||||||
|
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
||||||
|
mocked_settings = mocked_class.return_value
|
||||||
|
mocked_settings.contains.return_value = False
|
||||||
|
mocked_get_directory.return_value = u'test/dir'
|
||||||
|
mocked_check_directory_exists.return_value = True
|
||||||
|
mocked_os.path.normpath.return_value = u'test/dir'
|
||||||
|
# WHEN: we call AppLocation.get_data_path()
|
||||||
|
data_path = AppLocation.get_data_path()
|
||||||
|
# THEN: check that all the correct methods were called, and the result is correct
|
||||||
|
mocked_settings.contains.assert_called_with(u'advanced/data path')
|
||||||
|
mocked_get_directory.assert_called_with(AppLocation.DataDir)
|
||||||
|
mocked_check_directory_exists.assert_called_with(u'test/dir')
|
||||||
|
assert data_path == u'test/dir', u'Result should be "test/dir"'
|
||||||
|
|
||||||
|
def get_data_path_with_custom_location_test(self):
|
||||||
|
"""
|
||||||
|
Test the AppLocation.get_data_path() method when a custom location is set in the settings
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.Settings') as mocked_class,\
|
||||||
|
patch(u'openlp.core.utils.os') as mocked_os:
|
||||||
|
# GIVEN: A mocked out Settings class which returns a custom data location
|
||||||
|
mocked_settings = mocked_class.return_value
|
||||||
|
mocked_settings.contains.return_value = True
|
||||||
|
mocked_settings.value.return_value.toString.return_value = u'custom/dir'
|
||||||
|
mocked_os.path.normpath.return_value = u'custom/dir'
|
||||||
|
# WHEN: we call AppLocation.get_data_path()
|
||||||
|
data_path = AppLocation.get_data_path()
|
||||||
|
# THEN: the mocked Settings methods were called and the value returned was our set up value
|
||||||
|
mocked_settings.contains.assert_called_with(u'advanced/data path')
|
||||||
|
mocked_settings.value.assert_called_with(u'advanced/data path')
|
||||||
|
mocked_settings.value.return_value.toString.assert_called_with()
|
||||||
|
assert data_path == u'custom/dir', u'Result should be "custom/dir"'
|
||||||
|
|
||||||
|
def get_section_data_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the AppLocation.get_section_data_path() method
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
|
||||||
|
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists:
|
||||||
|
# GIVEN: A mocked out AppLocation.get_data_path()
|
||||||
|
mocked_get_data_path.return_value = u'test/dir'
|
||||||
|
mocked_check_directory_exists.return_value = True
|
||||||
|
# WHEN: we call AppLocation.get_data_path()
|
||||||
|
data_path = AppLocation.get_section_data_path(u'section')
|
||||||
|
# THEN: check that all the correct methods were called, and the result is correct
|
||||||
|
mocked_check_directory_exists.assert_called_with(u'test/dir/section')
|
||||||
|
assert data_path == u'test/dir/section', u'Result should be "test/dir/section"'
|
||||||
|
|
||||||
|
def get_directory_for_app_dir_test(self):
|
||||||
|
"""
|
||||||
|
Test the AppLocation.get_directory() method for AppLocation.AppDir
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path:
|
||||||
|
mocked_get_frozen_path.return_value = u'app/dir'
|
||||||
|
# WHEN: We call AppLocation.get_directory
|
||||||
|
directory = AppLocation.get_directory(AppLocation.AppDir)
|
||||||
|
# THEN:
|
||||||
|
assert directory == u'app/dir', u'Directory should be "app/dir"'
|
||||||
|
|
||||||
|
def get_directory_for_plugins_dir_test(self):
|
||||||
|
"""
|
||||||
|
Test the AppLocation.get_directory() method for AppLocation.PluginsDir
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path, \
|
||||||
|
patch(u'openlp.core.utils.os.path.abspath') as mocked_abspath, \
|
||||||
|
patch(u'openlp.core.utils.os.path.split') as mocked_split, \
|
||||||
|
patch(u'openlp.core.utils.sys') as mocked_sys:
|
||||||
|
mocked_abspath.return_value = u'plugins/dir'
|
||||||
|
mocked_split.return_value = [u'openlp']
|
||||||
|
mocked_get_frozen_path.return_value = u'plugins/dir'
|
||||||
|
mocked_sys.frozen = 1
|
||||||
|
mocked_sys.argv = ['openlp']
|
||||||
|
# WHEN: We call AppLocation.get_directory
|
||||||
|
directory = AppLocation.get_directory(AppLocation.PluginsDir)
|
||||||
|
# THEN:
|
||||||
|
assert directory == u'plugins/dir', u'Directory should be "plugins/dir"'
|
||||||
|
|
58
tests/functional/openlp_core_utils/test_utils.py
Normal file
58
tests/functional/openlp_core_utils/test_utils.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
"""
|
||||||
|
Functional tests to test the AppLocation class and related methods.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from openlp.core.utils import get_filesystem_encoding, _get_frozen_path
|
||||||
|
|
||||||
|
class TestUtils(TestCase):
|
||||||
|
"""
|
||||||
|
A test suite to test out various methods around the AppLocation class.
|
||||||
|
"""
|
||||||
|
def get_filesystem_encoding_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_filesystem_encoding() function
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
||||||
|
patch(u'openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns "cp1252"
|
||||||
|
mocked_getfilesystemencoding.return_value = u'cp1252'
|
||||||
|
|
||||||
|
# WHEN: get_filesystem_encoding() is called
|
||||||
|
result = get_filesystem_encoding()
|
||||||
|
|
||||||
|
# THEN: getdefaultencoding should have been called
|
||||||
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
|
assert not mocked_getdefaultencoding.called
|
||||||
|
assert result == u'cp1252', u'The result should be "cp1252"'
|
||||||
|
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
|
||||||
|
mocked_getfilesystemencoding.return_value = None
|
||||||
|
mocked_getdefaultencoding.return_value = u'utf-8'
|
||||||
|
|
||||||
|
# WHEN: get_filesystem_encoding() is called
|
||||||
|
result = get_filesystem_encoding()
|
||||||
|
|
||||||
|
# THEN: getdefaultencoding should have been called
|
||||||
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
|
mocked_getdefaultencoding.assert_called_with()
|
||||||
|
assert result == u'utf-8', u'The result should be "utf-8"'
|
||||||
|
|
||||||
|
def get_frozen_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the _get_frozen_path() function
|
||||||
|
"""
|
||||||
|
with patch(u'openlp.core.utils.sys') as mocked_sys:
|
||||||
|
# GIVEN: The sys module "without" a "frozen" attribute
|
||||||
|
mocked_sys.frozen = None
|
||||||
|
# WHEN: We call _get_frozen_path() with two parameters
|
||||||
|
# THEN: The non-frozen parameter is returned
|
||||||
|
assert _get_frozen_path(u'frozen', u'not frozen') == u'not frozen', u'Should return "not frozen"'
|
||||||
|
# GIVEN: The sys module *with* a "frozen" attribute
|
||||||
|
mocked_sys.frozen = 1
|
||||||
|
# WHEN: We call _get_frozen_path() with two parameters
|
||||||
|
# THEN: The frozen parameter is returned
|
||||||
|
assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user