Fix up Main display

This commit is contained in:
Tim Bentley 2014-01-11 17:52:01 +00:00
parent 3a5c15a29a
commit 7fe95731f9
9 changed files with 139 additions and 106 deletions

View File

@ -33,7 +33,8 @@ import logging
import inspect import inspect
from openlp.core.common import trace_error_handler from openlp.core.common import trace_error_handler
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event'] DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed',
'preview_size_changed', 'resizeEvent']
class OpenLPMixin(object): class OpenLPMixin(object):

View File

@ -60,6 +60,8 @@ class Renderer(OpenLPMixin, RegistryMixin):
print("Renderer - before super") print("Renderer - before super")
super(Renderer, self).__init__(None) super(Renderer, self).__init__(None)
print("Renderer - after super") print("Renderer - after super")
# Need live behaviour if this is also working as a pseudo MainDisplay.
self.is_live = True
self.screens = ScreenList() self.screens = ScreenList()
self.theme_level = ThemeLevel.Global self.theme_level = ThemeLevel.Global
self.global_theme_name = '' self.global_theme_name = ''
@ -77,7 +79,7 @@ class Renderer(OpenLPMixin, RegistryMixin):
""" """
Initialise functions Initialise functions
""" """
self.display = MainDisplay(None, False, self) self.display = MainDisplay(self)
self.display.setup() self.display.setup()
def update_display(self): def update_display(self):
@ -87,7 +89,7 @@ class Renderer(OpenLPMixin, RegistryMixin):
self._calculate_default() self._calculate_default()
if self.display: if self.display:
self.display.close() self.display.close()
self.display = MainDisplay(None, False, self) self.display = MainDisplay(self)
self.display.setup() self.display.setup()
self._theme_dimensions = {} self._theme_dimensions = {}
@ -114,6 +116,7 @@ class Renderer(OpenLPMixin, RegistryMixin):
:param theme_name: The theme name :param theme_name: The theme name
""" """
self.log_debug("_set_theme with theme %s" % theme_name)
if theme_name not in self._theme_dimensions: if theme_name not in self._theme_dimensions:
theme_data = self.theme_manager.get_theme_data(theme_name) theme_data = self.theme_manager.get_theme_data(theme_name)
main_rect = self.get_main_rectangle(theme_data) main_rect = self.get_main_rectangle(theme_data)
@ -169,9 +172,6 @@ class Renderer(OpenLPMixin, RegistryMixin):
def set_global_theme(self): def set_global_theme(self):
""" """
Set the global-level theme name. Set the global-level theme name.
``global_theme_name``
The global-level theme's name.
""" """
global_theme_name = Settings().value('themes/global theme') global_theme_name = Settings().value('themes/global theme')
self._set_theme(global_theme_name) self._set_theme(global_theme_name)
@ -192,6 +192,7 @@ class Renderer(OpenLPMixin, RegistryMixin):
:param item_theme_name: The item theme's name. :param item_theme_name: The item theme's name.
""" """
self.log_debug("set_item_theme with theme %s" % item_theme_name)
self._set_theme(item_theme_name) self._set_theme(item_theme_name)
self.item_theme_name = item_theme_name self.item_theme_name = item_theme_name
@ -202,7 +203,6 @@ class Renderer(OpenLPMixin, RegistryMixin):
:param theme_data: The theme to generated a preview for. :param theme_data: The theme to generated a preview for.
:param force_page: Flag to tell message lines per page need to be generated. :param force_page: Flag to tell message lines per page need to be generated.
""" """
self.log_debug('generate preview')
# save value for use in format_slide # save value for use in format_slide
self.force_page = force_page self.force_page = force_page
# build a service item to generate preview # build a service item to generate preview

View File

@ -31,8 +31,8 @@ The :mod:`serviceitem` provides the service item functionality including the
type and capability of an item. type and capability of an item.
""" """
import cgi
import datetime import datetime
import html
import logging import logging
import os import os
import uuid import uuid
@ -241,9 +241,8 @@ class ServiceItem(object):
self.theme_data, self.main, self.footer = self.renderer.pre_render() self.theme_data, self.main, self.footer = self.renderer.pre_render()
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
log.debug('Formatting slides: %s' % self.title) log.debug('Formatting slides: %s' % self.title)
# Save rendered pages to this dict. In the case that a slide is used # Save rendered pages to this dict. In the case that a slide is used twice we can use the pages saved to
# twice we can use the pages saved to the dict instead of rendering # the dict instead of rendering them again.
# them again.
previous_pages = {} previous_pages = {}
for slide in self._raw_frames: for slide in self._raw_frames:
verse_tag = slide['verseTag'] verse_tag = slide['verseTag']
@ -254,11 +253,11 @@ class ServiceItem(object):
previous_pages[verse_tag] = (slide['raw_slide'], pages) previous_pages[verse_tag] = (slide['raw_slide'], pages)
for page in pages: for page in pages:
page = page.replace('<br>', '{br}') page = page.replace('<br>', '{br}')
html = expand_tags(cgi.escape(page.rstrip())) html_data = expand_tags(html.escape(page.rstrip()))
self._display_frames.append({ self._display_frames.append({
'title': clean_tags(page), 'title': clean_tags(page),
'text': clean_tags(page.rstrip()), 'text': clean_tags(page.rstrip()),
'html': html.replace('&amp;nbsp;', '&nbsp;'), 'html': html_data.replace('&amp;nbsp;', '&nbsp;'),
'verseTag': verse_tag 'verseTag': verse_tag
}) })
elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command: elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command:

View File

@ -44,7 +44,7 @@ import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
from openlp.core.common import Registry, Settings, translate from openlp.core.common import Registry, OpenLPMixin, Settings, translate
from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte
from openlp.core.lib.theme import BackgroundType from openlp.core.lib.theme import BackgroundType
@ -59,20 +59,22 @@ class Display(QtGui.QGraphicsView):
This is a general display screen class. Here the general display settings will done. It will be used as This is a general display screen class. Here the general display settings will done. It will be used as
specialized classes by Main Display and Preview display. specialized classes by Main Display and Preview display.
""" """
def __init__(self, parent, live, controller): def __init__(self, parent):
""" """
Constructor Constructor
""" """
print("Display - before super") print("Display - before super", parent, type(parent))
if live: self.is_live = False
if hasattr(parent, 'is_live') and parent.is_live:
self.is_live = True
if self.is_live:
super(Display, self).__init__() super(Display, self).__init__()
# Overwrite the parent() method. # Overwrite the parent() method.
self.parent = lambda: parent self.parent = lambda: parent
else: else:
super(Display, self).__init__(parent) super(Display, self).__init__(parent)
print("Display - after super") print("Display - after super")
self.is_live = live self.controller = parent
self.controller = controller
self.screen = {} self.screen = {}
# FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with # FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with
# OpenGL. Only white blank screen is shown on the 2nd monitor all the # OpenGL. Only white blank screen is shown on the 2nd monitor all the
@ -85,9 +87,7 @@ class Display(QtGui.QGraphicsView):
""" """
Set up and build the screen base Set up and build the screen base
""" """
log.debug('Start Display base setup (live = %s)' % self.is_live)
self.setGeometry(self.screen['size']) self.setGeometry(self.screen['size'])
log.debug('Setup webView')
self.web_view = QtWebKit.QWebView(self) self.web_view = QtWebKit.QWebView(self)
self.web_view.setGeometry(0, 0, self.screen['size'].width(), self.screen['size'].height()) self.web_view.setGeometry(0, 0, self.screen['size'].width(), self.screen['size'].height())
self.web_view.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) self.web_view.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
@ -108,27 +108,28 @@ class Display(QtGui.QGraphicsView):
def resizeEvent(self, event): def resizeEvent(self, event):
""" """
React to resizing of this display React to resizing of this display
:param event: The event to be handled
""" """
self.web_view.setGeometry(0, 0, self.width(), self.height()) self.web_view.setGeometry(0, 0, self.width(), self.height())
def is_web_loaded(self): def is_web_loaded(self, field=None):
""" """
Called by webView event to show display is fully loaded Called by webView event to show display is fully loaded
""" """
log.debug('is web loaded')
self.web_loaded = True self.web_loaded = True
class MainDisplay(Display): class MainDisplay(OpenLPMixin, Display):
""" """
This is the display screen as a specialized class from the Display class This is the display screen as a specialized class from the Display class
""" """
def __init__(self, parent, live, controller): def __init__(self, parent):
""" """
Constructor Constructor
""" """
print("MainDisplay - before super") print("MainDisplay - before super")
super(MainDisplay, self).__init__(parent, live, controller) super(MainDisplay, self).__init__(parent)
print("MainDisplay - after super") print("MainDisplay - after super")
self.screens = ScreenList() self.screens = ScreenList()
self.rebuild_css = False self.rebuild_css = False
@ -136,7 +137,7 @@ class MainDisplay(Display):
self.override = {} self.override = {}
self.retranslateUi() self.retranslateUi()
self.media_object = None self.media_object = None
if live: if self.is_live:
self.audio_player = AudioPlayer(self) self.audio_player = AudioPlayer(self)
else: else:
self.audio_player = None self.audio_player = None
@ -167,6 +168,8 @@ class MainDisplay(Display):
def set_transparency(self, enabled): def set_transparency(self, enabled):
""" """
Set the transparency of the window Set the transparency of the window
:param enabled: Is transparency enabled
""" """
if enabled: if enabled:
self.setAutoFillBackground(False) self.setAutoFillBackground(False)
@ -192,7 +195,7 @@ class MainDisplay(Display):
""" """
Set up and build the output screen Set up and build the output screen
""" """
log.debug('Start MainDisplay setup (live = %s)' % self.is_live) self.log_debug('Start MainDisplay setup (live = %s)' % self.is_live)
self.screen = self.screens.current self.screen = self.screens.current
self.setVisible(False) self.setVisible(False)
Display.setup(self) Display.setup(self)
@ -219,20 +222,15 @@ class MainDisplay(Display):
service_item.bg_image_bytes = image_to_byte(self.initial_fame) service_item.bg_image_bytes = image_to_byte(self.initial_fame)
self.web_view.setHtml(build_html(service_item, self.screen, self.is_live, None, self.web_view.setHtml(build_html(service_item, self.screen, self.is_live, None,
plugins=self.plugin_manager.plugins)) plugins=self.plugin_manager.plugins))
self.__hideMouse() self._hide_mouse()
log.debug('Finished MainDisplay setup')
def text(self, slide, animate=True): def text(self, slide, animate=True):
""" """
Add the slide text from slideController Add the slide text from slideController
``slide`` :param slide: The slide text to be displayed
The slide text to be displayed :param animate: Perform transitions if applicable when setting the text
``animate``
Perform transitions if applicable when setting the text
""" """
log.debug('text to display')
# Wait for the webview to update before displaying text. # Wait for the webview to update before displaying text.
while not self.web_loaded: while not self.web_loaded:
self.application.process_events() self.application.process_events()
@ -251,10 +249,9 @@ class MainDisplay(Display):
""" """
Display an alert. Display an alert.
``text`` :param text: The text to be displayed.
The text to be displayed. :param location: Where on the screen is the text to be displayed
""" """
log.debug('alert to display')
# First we convert <>& marks to html variants, then apply # First we convert <>& marks to html variants, then apply
# formattingtags, finally we double all backslashes for JavaScript. # formattingtags, finally we double all backslashes for JavaScript.
text_prepared = expand_tags(cgi.escape(text)).replace('\\', '\\\\').replace('\"', '\\\"') text_prepared = expand_tags(cgi.escape(text)).replace('\\', '\\\\').replace('\"', '\\\"')
@ -281,6 +278,9 @@ class MainDisplay(Display):
def direct_image(self, path, background): def direct_image(self, path, background):
""" """
API for replacement backgrounds so Images are added directly to cache. API for replacement backgrounds so Images are added directly to cache.
:param path: Path to Image
:param background: The background color
""" """
self.image_manager.add_image(path, ImageSource.ImagePlugin, background) self.image_manager.add_image(path, ImageSource.ImagePlugin, background)
if not hasattr(self, 'service_item'): if not hasattr(self, 'service_item'):
@ -298,12 +298,9 @@ class MainDisplay(Display):
Add an image as the background. The image has already been added to the Add an image as the background. The image has already been added to the
cache. cache.
``path`` :param path: The path to the image to be displayed. **Note**, the path is only passed to identify the image.
The path to the image to be displayed. **Note**, the path is only If the image has changed it has to be re-added to the image manager.
passed to identify the image. If the image has changed it has to be
re-added to the image manager.
""" """
log.debug('image to display')
image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin) image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin)
self.controller.media_controller.media_reset(self.controller) self.controller.media_controller.media_reset(self.controller)
self.display_image(image) self.display_image(image)
@ -311,6 +308,8 @@ class MainDisplay(Display):
def display_image(self, image): def display_image(self, image):
""" """
Display an image, as is. Display an image, as is.
:param image: The image to be displayed
""" """
self.setGeometry(self.screen['size']) self.setGeometry(self.screen['size'])
if image: if image:
@ -321,10 +320,8 @@ class MainDisplay(Display):
def reset_image(self): def reset_image(self):
""" """
Reset the background image to the service item image. Used after the Reset the background image to the service item image. Used after the image plugin has changed the background.
image plugin has changed the background.
""" """
log.debug('reset_image')
if hasattr(self, 'service_item'): if hasattr(self, 'service_item'):
self.display_image(self.service_item.bg_image_bytes) self.display_image(self.service_item.bg_image_bytes)
else: else:
@ -339,7 +336,6 @@ class MainDisplay(Display):
""" """
Generates a preview of the image displayed. Generates a preview of the image displayed.
""" """
log.debug('preview for %s', self.is_live)
was_visible = self.isVisible() was_visible = self.isVisible()
self.application.process_events() self.application.process_events()
# We must have a service item to preview. # We must have a service item to preview.
@ -371,10 +367,11 @@ class MainDisplay(Display):
def build_html(self, service_item, image_path=''): def build_html(self, service_item, image_path=''):
""" """
Store the service_item and build the new HTML from it. Add the Store the service_item and build the new HTML from it. Add the HTML to the display
HTML to the display
:param service_item: The Service item to be used
:param image_path: Where the image resides.
""" """
log.debug('build_html')
self.web_loaded = False self.web_loaded = False
self.initial_fame = None self.initial_fame = None
self.service_item = service_item self.service_item = service_item
@ -396,17 +393,14 @@ class MainDisplay(Display):
BackgroundType.to_string(BackgroundType.Transparent)) BackgroundType.to_string(BackgroundType.Transparent))
if self.service_item.theme_data.background_filename: if self.service_item.theme_data.background_filename:
self.service_item.bg_image_bytes = self.image_manager.get_image_bytes( self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(
self.service_item.theme_data.background_filename, ImageSource.Theme self.service_item.theme_data.background_filename, ImageSource.Theme)
)
if image_path: if image_path:
image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin) image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes, html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes,
plugins=self.plugin_manager.plugins) plugins=self.plugin_manager.plugins)
log.debug('buildHtml - pre setHtml')
self.web_view.setHtml(html) self.web_view.setHtml(html)
log.debug('buildHtml - post setHtml')
if service_item.foot_text: if service_item.foot_text:
self.footer(service_item.foot_text) self.footer(service_item.foot_text)
# if was hidden keep it hidden # if was hidden keep it hidden
@ -415,22 +409,24 @@ class MainDisplay(Display):
Registry().execute('slidecontroller_live_unblank') Registry().execute('slidecontroller_live_unblank')
else: else:
self.hide_display(self.hide_mode) self.hide_display(self.hide_mode)
self.__hideMouse() self._hide_mouse()
def footer(self, text): def footer(self, text):
""" """
Display the Footer Display the Footer
:param text: footer text to be displayed
""" """
log.debug('footer')
js = 'show_footer(\'' + text.replace('\\', '\\\\').replace('\'', '\\\'') + '\')' js = 'show_footer(\'' + text.replace('\\', '\\\\').replace('\'', '\\\'') + '\')'
self.frame.evaluateJavaScript(js) self.frame.evaluateJavaScript(js)
def hide_display(self, mode=HideMode.Screen): def hide_display(self, mode=HideMode.Screen):
""" """
Hide the display by making all layers transparent Hide the display by making all layers transparent Store the images so they can be replaced when required
Store the images so they can be replaced when required
:param mode: How the screen is to be hidden
""" """
log.debug('hide_display mode = %d', mode) self.log_debug('hide_display mode = %d' % mode)
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
if not Settings().value('core/display on monitor'): if not Settings().value('core/display on monitor'):
@ -453,7 +449,6 @@ class MainDisplay(Display):
Show the stored layers so the screen reappears as it was originally. Show the stored layers so the screen reappears as it was originally.
Make the stored images None to release memory. Make the stored images None to release memory.
""" """
log.debug('show_display')
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
if not Settings().value('core/display on monitor'): if not Settings().value('core/display on monitor'):
@ -466,7 +461,7 @@ class MainDisplay(Display):
if self.is_live: if self.is_live:
Registry().execute('live_display_active') Registry().execute('live_display_active')
def __hideMouse(self): def _hide_mouse(self):
""" """
Hide mouse cursor when moved over display. Hide mouse cursor when moved over display.
""" """
@ -522,11 +517,10 @@ class MainDisplay(Display):
live_controller = property(_get_live_controller) live_controller = property(_get_live_controller)
class AudioPlayer(QtCore.QObject): class AudioPlayer(OpenLPMixin, QtCore.QObject):
""" """
This Class will play audio only allowing components to work with a soundtrack independent of the user interface. This Class will play audio only allowing components to work with a soundtrack independent of the user interface.
""" """
log.info('AudioPlayer Loaded')
def __init__(self, parent): def __init__(self, parent):
""" """
@ -535,7 +529,6 @@ class AudioPlayer(QtCore.QObject):
``parent`` ``parent``
The parent widget. The parent widget.
""" """
log.debug('AudioPlayer Initialisation started')
super(AudioPlayer, self).__init__(parent) super(AudioPlayer, self).__init__(parent)
self.current_index = -1 self.current_index = -1
self.playlist = [] self.playlist = []
@ -569,7 +562,7 @@ class AudioPlayer(QtCore.QObject):
When the audio track finishes. When the audio track finishes.
""" """
if self.repeat: if self.repeat:
log.debug('Repeat is enabled... here we go again!') self.log_debug('Repeat is enabled... here we go again!')
self.media_object.clearQueue() self.media_object.clearQueue()
self.media_object.clear() self.media_object.clear()
self.current_index = -1 self.current_index = -1
@ -594,7 +587,6 @@ class AudioPlayer(QtCore.QObject):
""" """
We want to play the file so start it We want to play the file so start it
""" """
log.debug('AudioPlayer.play() called')
if self.current_index == -1: if self.current_index == -1:
self.on_about_to_finish() self.on_about_to_finish()
self.media_object.play() self.media_object.play()
@ -603,22 +595,19 @@ class AudioPlayer(QtCore.QObject):
""" """
Pause the Audio Pause the Audio
""" """
log.debug('AudioPlayer.pause() called')
self.media_object.pause() self.media_object.pause()
def stop(self): def stop(self):
""" """
Stop the Audio and clean up Stop the Audio and clean up
""" """
log.debug('AudioPlayer.stop() called')
self.media_object.stop() self.media_object.stop()
def add_to_playlist(self, file_names): def add_to_playlist(self, file_names):
""" """
Add another file to the playlist. Add another file to the playlist.
``file_names`` :param file_names: A list with files to be added to the playlist.
A list with files to be added to the playlist.
""" """
if not isinstance(file_names, list): if not isinstance(file_names, list):
file_names = [file_names] file_names = [file_names]
@ -643,6 +632,8 @@ class AudioPlayer(QtCore.QObject):
def go_to(self, index): def go_to(self, index):
""" """
Go to a particular track in the list Go to a particular track in the list
:param index: The track to go to
""" """
is_playing = self.media_object.state() == Phonon.PlayingState is_playing = self.media_object.state() == Phonon.PlayingState
self.media_object.clearQueue() self.media_object.clearQueue()
@ -655,6 +646,9 @@ class AudioPlayer(QtCore.QObject):
def connectSlot(self, signal, slot): def connectSlot(self, signal, slot):
""" """
Connect a slot to a signal on the media object. Used by slidecontroller to connect to audio object. Connect a slot to a signal on the media object. Used by slidecontroller to connect to audio object.
:param slot: The slot the signal is attached to.
:param signal: The signal to be fired
""" """
QtCore.QObject.connect(self.media_object, signal, slot) QtCore.QObject.connect(self.media_object, signal, slot)

View File

@ -548,6 +548,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.live_controller.panel.setVisible(Settings().value('user interface/live panel')) self.live_controller.panel.setVisible(Settings().value('user interface/live panel'))
self.load_settings() self.load_settings()
self.restore_current_media_manager_item() self.restore_current_media_manager_item()
Registry().execute('theme_update_global')
def restore_current_media_manager_item(self): def restore_current_media_manager_item(self):
""" """
@ -676,7 +677,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
else: else:
self.active_plugin.toggle_status(PluginStatus.Inactive) self.active_plugin.toggle_status(PluginStatus.Inactive)
# Set global theme and # Set global theme and
Registry().execute('theme_update_global', self.theme_manager_contents.global_theme) Registry().execute('theme_update_global')
self.theme_manager_contents.load_first_time_themes() self.theme_manager_contents.load_first_time_themes()
# Check if any Bibles downloaded. If there are, they will be processed. # Check if any Bibles downloaded. If there are, they will be processed.
Registry().execute('bibles_load_list', True) Registry().execute('bibles_load_list', True)

View File

@ -1024,9 +1024,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
""" """
Called by the SlideController to select the next service item. Called by the SlideController to select the next service item.
""" """
if not self.service_manager_list.selected_items(): if not self.service_manager_list.selectedItems():
return return
selected = self.service_manager_list.selected_items()[0] selected = self.service_manager_list.selectedItems()[0]
look_for = 0 look_for = 0
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list) service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
while service_iterator.value(): while service_iterator.value():
@ -1044,9 +1044,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage
:param last_slide: Is this the last slide in the service_item. :param last_slide: Is this the last slide in the service_item.
""" """
if not self.service_manager_list.selected_items(): if not self.service_manager_list.selectedItems():
return return
selected = self.service_manager_list.selected_items()[0] selected = self.service_manager_list.selectedItems()[0]
prev_item = None prev_item = None
prev_item_last_slide = None prev_item_last_slide = None
service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list) service_iterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)

View File

@ -93,8 +93,7 @@ class DisplayController(QtGui.QWidget):
def send_to_plugins(self, *args): def send_to_plugins(self, *args):
""" """
This is the generic function to send signal for control widgets, This is the generic function to send signal for control widgets, created from within other plugins
created from within other plugins
This function is needed to catch the current controller This function is needed to catch the current controller
""" """
sender = self.sender().objectName() if self.sender().objectName() else self.sender().text() sender = self.sender().objectName() if self.sender().objectName() else self.sender().text()
@ -277,7 +276,8 @@ class SlideController(DisplayController):
self.toolbar.add_toolbar_widget(self.song_menu) self.toolbar.add_toolbar_widget(self.song_menu)
# Stuff for items with background audio. # Stuff for items with background audio.
# FIXME: object name should be changed. But this requires that we migrate the shortcut. # FIXME: object name should be changed. But this requires that we migrate the shortcut.
self.audio_pause_item = self.toolbar.add_toolbar_action('audioPauseItem', self.audio_pause_item = self.toolbar.add_toolbar_action(
'audioPauseItem',
icon=':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'), icon=':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'),
tooltip=translate('OpenLP.SlideController', 'Pause audio.'), tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut, checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut,
@ -318,7 +318,7 @@ class SlideController(DisplayController):
self.slide_layout.setSpacing(0) self.slide_layout.setSpacing(0)
self.slide_layout.setMargin(0) self.slide_layout.setMargin(0)
self.slide_layout.setObjectName('SlideLayout') self.slide_layout.setObjectName('SlideLayout')
self.preview_display = Display(self, self.is_live, self) self.preview_display = Display(self)
self.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300)) self.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300))
self.preview_display.screen = {'size': self.preview_display.geometry()} self.preview_display.screen = {'size': self.preview_display.geometry()}
self.preview_display.setup() self.preview_display.setup()
@ -532,7 +532,7 @@ class SlideController(DisplayController):
# rebuild display as screen size changed # rebuild display as screen size changed
if self.display: if self.display:
self.display.close() self.display.close()
self.display = MainDisplay(self, self.is_live, self) self.display = MainDisplay(self)
self.display.setup() self.display.setup()
if self.is_live: if self.is_live:
self.__add_actions_to_widget(self.display) self.__add_actions_to_widget(self.display)
@ -566,17 +566,15 @@ class SlideController(DisplayController):
def preview_size_changed(self): def preview_size_changed(self):
""" """
Takes care of the SlidePreview's size. Is called when one of the the Takes care of the SlidePreview's size. Is called when one of the the splitters is moved or when the screen
splitters is moved or when the screen size is changed. Note, that this size is changed. Note, that this method is (also) called frequently from the mainwindow *paintEvent*.
method is (also) called frequently from the mainwindow *paintEvent*.
""" """
if self.ratio < self.preview_frame.width() / self.preview_frame.height(): if self.ratio < self.preview_frame.width() / self.preview_frame.height():
# We have to take the height as limit. # We have to take the height as limit.
max_height = self.preview_frame.height() - self.grid.margin() * 2 max_height = self.preview_frame.height() - self.grid.margin() * 2
self.slide_preview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height)) self.slide_preview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.preview_display.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height)) self.preview_display.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.preview_display.screen = { self.preview_display.screen = {'size': self.preview_display.geometry()}
'size': self.preview_display.geometry()}
else: else:
# We have to take the width as limit. # We have to take the width as limit.
max_width = self.preview_frame.width() - self.grid.margin() * 2 max_width = self.preview_frame.width() - self.grid.margin() * 2
@ -683,6 +681,8 @@ class SlideController(DisplayController):
def enable_preview_tool_bar(self, item): def enable_preview_tool_bar(self, item):
""" """
Allows the Preview toolbar to be customised Allows the Preview toolbar to be customised
:param item: The current service item
""" """
# Work-around for OS X, hide and then show the toolbar # Work-around for OS X, hide and then show the toolbar
# See bug #791050 # See bug #791050
@ -712,6 +712,8 @@ class SlideController(DisplayController):
""" """
Method to install the service item into the controller Method to install the service item into the controller
Called by plugins Called by plugins
:param item: The current service item
""" """
item.render() item.render()
slide_no = 0 slide_no = 0
@ -723,6 +725,8 @@ class SlideController(DisplayController):
def replace_service_manager_item(self, item): def replace_service_manager_item(self, item):
""" """
Replacement item following a remote edit Replacement item following a remote edit
:param item: The current service item
""" """
if item == self.service_item: if item == self.service_item:
self._process_item(item, self.preview_widget.current_slide_number()) self._process_item(item, self.preview_widget.current_slide_number())
@ -731,6 +735,9 @@ class SlideController(DisplayController):
""" """
Method to install the service item into the controller and request the correct toolbar for the plugin. Called by Method to install the service item into the controller and request the correct toolbar for the plugin. Called by
:class:`~openlp.core.ui.ServiceManager` :class:`~openlp.core.ui.ServiceManager`
:param item: The current service item
:param slide_no: The slide number to select
""" """
# If no valid slide number is specified we take the first one, but we remember the initial value to see if we # If no valid slide number is specified we take the first one, but we remember the initial value to see if we
# should reload the song or not # should reload the song or not
@ -755,6 +762,9 @@ class SlideController(DisplayController):
def _process_item(self, service_item, slide_no): def _process_item(self, service_item, slide_no):
""" """
Loads a ServiceItem into the system from ServiceManager. Display the slide number passed. Loads a ServiceItem into the system from ServiceManager. Display the slide number passed.
:param service_item: The current service item
:param slide_no: The slide number to select
""" """
self.on_stop_loop() self.on_stop_loop()
old_item = self.service_item old_item = self.service_item
@ -762,8 +772,9 @@ class SlideController(DisplayController):
self.service_item = copy.copy(service_item) self.service_item = copy.copy(service_item)
if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self._reset_blank() self._reset_blank()
Registry().execute( if service_item.is_command():
'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slide_no]) Registry().execute(
'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slide_no])
self.slide_list = {} self.slide_list = {}
if self.is_live: if self.is_live:
self.song_menu.menu().clear() self.song_menu.menu().clear()
@ -789,7 +800,7 @@ class SlideController(DisplayController):
self.set_audio_items_visibility(True) self.set_audio_items_visibility(True)
row = 0 row = 0
width = self.main_window.control_splitter.sizes()[self.split] width = self.main_window.control_splitter.sizes()[self.split]
for framenumber, frame in enumerate(self.service_item.get_frames()): for frame_number, frame in enumerate(self.service_item.get_frames()):
if self.service_item.is_text(): if self.service_item.is_text():
if frame['verseTag']: if frame['verseTag']:
# These tags are already translated. # These tags are already translated.
@ -798,7 +809,7 @@ class SlideController(DisplayController):
two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:]) two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
row = two_line_def row = two_line_def
if verse_def not in self.slide_list: if verse_def not in self.slide_list:
self.slide_list[verse_def] = framenumber self.slide_list[verse_def] = frame_number
if self.is_live: if self.is_live:
self.song_menu.menu().addAction(verse_def, self.on_song_bar_handler) self.song_menu.menu().addAction(verse_def, self.on_song_bar_handler)
else: else:
@ -808,7 +819,7 @@ class SlideController(DisplayController):
row += 1 row += 1
self.slide_list[str(row)] = row - 1 self.slide_list[str(row)] = row - 1
# If current slide set background to image # If current slide set background to image
if not self.service_item.is_command() and framenumber == slide_no: if not self.service_item.is_command() and frame_number == slide_no:
self.service_item.bg_image_bytes = \ self.service_item.bg_image_bytes = \
self.image_manager.get_image_bytes(frame['path'], ImageSource.ImagePlugin) self.image_manager.get_image_bytes(frame['path'], ImageSource.ImagePlugin)
self.preview_widget.replace_service_item(self.service_item, width, slide_no) self.preview_widget.replace_service_item(self.service_item, width, slide_no)
@ -832,10 +843,11 @@ class SlideController(DisplayController):
self.on_media_close() self.on_media_close()
Registry().execute('slidecontroller_%s_started' % self.type_prefix, [service_item]) Registry().execute('slidecontroller_%s_started' % self.type_prefix, [service_item])
# Screen event methods
def on_slide_selected_index(self, message): def on_slide_selected_index(self, message):
""" """
Go to the requested slide Go to the requested slide
:param message: remote message to be processed.
""" """
index = int(message[0]) index = int(message[0])
if not self.service_item: if not self.service_item:
@ -880,6 +892,8 @@ class SlideController(DisplayController):
def on_blank_display(self, checked=None): def on_blank_display(self, checked=None):
""" """
Handle the blank screen button actions Handle the blank screen button actions
:param checked: the new state of the of the widget
""" """
if checked is None: if checked is None:
checked = self.blank_screen.isChecked() checked = self.blank_screen.isChecked()
@ -899,6 +913,8 @@ class SlideController(DisplayController):
def on_theme_display(self, checked=None): def on_theme_display(self, checked=None):
""" """
Handle the Theme screen button Handle the Theme screen button
:param checked: the new state of the of the widget
""" """
if checked is None: if checked is None:
checked = self.theme_screen.isChecked() checked = self.theme_screen.isChecked()
@ -918,6 +934,8 @@ class SlideController(DisplayController):
def on_hide_display(self, checked=None): def on_hide_display(self, checked=None):
""" """
Handle the Hide screen button Handle the Hide screen button
:param checked: the new state of the of the widget
""" """
if checked is None: if checked is None:
checked = self.desktop_screen.isChecked() checked = self.desktop_screen.isChecked()
@ -984,8 +1002,9 @@ class SlideController(DisplayController):
def slide_selected(self, start=False): def slide_selected(self, start=False):
""" """
Generate the preview when you click on a slide. Generate the preview when you click on a slide. If this is the Live Controller also display on the screen
if this is the Live Controller also display on the screen
:param start:
""" """
row = self.preview_widget.current_slide_number() row = self.preview_widget.current_slide_number()
self.selected_row = 0 self.selected_row = 0
@ -1008,12 +1027,13 @@ class SlideController(DisplayController):
self.update_preview() self.update_preview()
self.selected_row = row self.selected_row = row
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
Registry().execute('slidecontroller_%s_changed' % self.type_prefix, row)
self.display.setFocus() self.display.setFocus()
def on_slide_change(self, row): def on_slide_change(self, row):
""" """
The slide has been changed. Update the slidecontroller accordingly The slide has been changed. Update the slidecontroller accordingly
:param row: Row to be selected
""" """
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
self.update_preview() self.update_preview()
@ -1046,20 +1066,24 @@ class SlideController(DisplayController):
def on_slide_selected_next_action(self, checked): def on_slide_selected_next_action(self, checked):
""" """
Wrapper function from create_action so we can throw away the Wrapper function from create_action so we can throw away the incorrect parameter
incorrect parameter
:param checked: the new state of the of the widget
""" """
self.on_slide_selected_next() self.on_slide_selected_next()
def on_slide_selected_next(self, wrap=None): def on_slide_selected_next(self, wrap=None):
""" """
Go to the next slide. Go to the next slide.
:param wrap: Are we wrapping round the service item
""" """
if not self.service_item: if not self.service_item:
return return
Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) if self.service_item.is_command():
if self.service_item.is_command() and self.is_live: Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live])
self.update_preview() if self.is_live:
self.update_preview()
else: else:
row = self.preview_widget.current_slide_number() + 1 row = self.preview_widget.current_slide_number() + 1
if row == self.preview_widget.slide_count(): if row == self.preview_widget.slide_count():
@ -1084,9 +1108,10 @@ class SlideController(DisplayController):
""" """
if not self.service_item: if not self.service_item:
return return
Registry().execute('%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live]) if self.service_item.is_command():
if self.service_item.is_command() and self.is_live: Registry().execute('%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live])
self.update_preview() if self.is_live:
self.update_preview()
else: else:
row = self.preview_widget.current_slide_number() - 1 row = self.preview_widget.current_slide_number() - 1
if row == -1: if row == -1:
@ -1129,6 +1154,8 @@ class SlideController(DisplayController):
def on_play_slides_loop(self, checked=None): def on_play_slides_loop(self, checked=None):
""" """
Start or stop 'Play Slides in Loop' Start or stop 'Play Slides in Loop'
:param checked: is the check box checked.
""" """
if checked is None: if checked is None:
checked = self.play_slides_loop.isChecked() checked = self.play_slides_loop.isChecked()
@ -1150,6 +1177,8 @@ class SlideController(DisplayController):
def on_play_slides_once(self, checked=None): def on_play_slides_once(self, checked=None):
""" """
Start or stop 'Play Slides to End' Start or stop 'Play Slides to End'
:param checked: is the check box checked.
""" """
if checked is None: if checked is None:
checked = self.play_slides_once.isChecked() checked = self.play_slides_once.isChecked()
@ -1177,6 +1206,8 @@ class SlideController(DisplayController):
def set_audio_pause_clicked(self, checked): def set_audio_pause_clicked(self, checked):
""" """
Pause the audio player Pause the audio player
:param checked: is the check box checked.
""" """
if not self.audio_pause_item.isVisible(): if not self.audio_pause_item.isVisible():
return return
@ -1188,6 +1219,8 @@ class SlideController(DisplayController):
def timerEvent(self, event): def timerEvent(self, event):
""" """
If the timer event is for this window select next slide If the timer event is for this window select next slide
:param event: The triggered event
""" """
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:
self.on_slide_selected_next(self.play_slides_loop.isChecked()) self.on_slide_selected_next(self.play_slides_loop.isChecked())
@ -1235,6 +1268,8 @@ class SlideController(DisplayController):
def on_media_start(self, item): def on_media_start(self, item):
""" """
Respond to the arrival of a media service item Respond to the arrival of a media service item
:param item: The service item to be processed
""" """
self.media_controller.video(self.controller_type, item, self.hide_mode()) self.media_controller.video(self.controller_type, item, self.hide_mode())
if not self.is_live: if not self.is_live:
@ -1288,6 +1323,8 @@ class SlideController(DisplayController):
def on_audio_time_remaining(self, time): def on_audio_time_remaining(self, time):
""" """
Update how much time is remaining Update how much time is remaining
:param time: the time remainings
""" """
seconds = self.display.audio_player.media_object.remainingTime() // 1000 seconds = self.display.audio_player.media_object.remainingTime() // 1000
minutes = seconds // 60 minutes = seconds // 60
@ -1335,7 +1372,7 @@ class SlideController(DisplayController):
""" """
Adds the service manager to the class dynamically Adds the service manager to the class dynamically
""" """
if not hasattr(self, '_service_manager'): if not hasattr(self, '_service_manager') or not self._service_manager:
self._service_manager = Registry().get('service_manager') self._service_manager = Registry().get('service_manager')
return self._service_manager return self._service_manager

View File

@ -515,8 +515,9 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager):
def over_write_message_box(self, theme_name): def over_write_message_box(self, theme_name):
""" """
Display a warning box to the user that a theme already exists Display a warning box to the user that a theme already exists
:param theme_name: Name of the theme. :param theme_name: Name of the theme.
:return Confirm if the theme is to be overeritten. :return Confirm if the theme is to be overwritten.
""" """
ret = QtGui.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'), ret = QtGui.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',

View File

@ -74,7 +74,7 @@ class MediaMediaItem(MediaManagerItem):
self.display_controller.controller_layout = QtGui.QVBoxLayout() self.display_controller.controller_layout = QtGui.QVBoxLayout()
self.media_controller.register_controller(self.display_controller) self.media_controller.register_controller(self.display_controller)
self.media_controller.set_controls_visible(self.display_controller, False) self.media_controller.set_controls_visible(self.display_controller, False)
self.display_controller.preview_display = Display(self.display_controller, False, self.display_controller) self.display_controller.preview_display = Display(self.display_controller)
self.display_controller.preview_display.hide() self.display_controller.preview_display.hide()
self.display_controller.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300)) self.display_controller.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300))
self.display_controller.preview_display.screen = {'size': self.display_controller.preview_display.geometry()} self.display_controller.preview_display.screen = {'size': self.display_controller.preview_display.geometry()}