- stop the imageManager when closing OpenLP

bzr-revno: 1980
This commit is contained in:
Andreas Preikschat 2012-06-04 12:37:46 +02:00
commit a12dc37d70
8 changed files with 85 additions and 75 deletions

View File

@ -163,143 +163,144 @@ class ImageManager(QtCore.QObject):
def __init__(self): def __init__(self):
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
current_screen = ScreenList().current currentScreen = ScreenList().current
self.width = current_screen[u'size'].width() self.width = currentScreen[u'size'].width()
self.height = current_screen[u'size'].height() self.height = currentScreen[u'size'].height()
self._cache = {} self._cache = {}
self._imageThread = ImageThread(self) self.imageThread = ImageThread(self)
self._conversion_queue = PriorityQueue() self._conversionQueue = PriorityQueue()
self.stopManager = False
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.process_updates) QtCore.SIGNAL(u'config_updated'), self.processUpdates)
def update_display(self): def updateDisplay(self):
""" """
Screen has changed size so rebuild the cache to new size. Screen has changed size so rebuild the cache to new size.
""" """
log.debug(u'update_display') log.debug(u'updateDisplay')
current_screen = ScreenList().current currentScreen = ScreenList().current
self.width = current_screen[u'size'].width() self.width = currentScreen[u'size'].width()
self.height = current_screen[u'size'].height() self.height = currentScreen[u'size'].height()
# Mark the images as dirty for a rebuild by setting the image and byte # Mark the images as dirty for a rebuild by setting the image and byte
# stream to None. # stream to None.
for image in self._cache.values(): for image in self._cache.values():
self._reset_image(image) self._resetImage(image)
def update_images(self, image_type, background): def updateImages(self, imageType, background):
""" """
Border has changed so update all the images affected. Border has changed so update all the images affected.
""" """
log.debug(u'update_images') log.debug(u'updateImages')
# Mark the images as dirty for a rebuild by setting the image and byte # Mark the images as dirty for a rebuild by setting the image and byte
# stream to None. # stream to None.
for image in self._cache.values(): for image in self._cache.values():
if image.source == image_type: if image.source == imageType:
image.background = background image.background = background
self._reset_image(image) self._resetImage(image)
def update_image(self, name, image_type, background): def updateImage(self, name, imageType, background):
""" """
Border has changed so update the image affected. Border has changed so update the image affected.
""" """
log.debug(u'update_images') log.debug(u'updateImage')
# Mark the images as dirty for a rebuild by setting the image and byte # Mark the images as dirty for a rebuild by setting the image and byte
# stream to None. # stream to None.
for image in self._cache.values(): for image in self._cache.values():
if image.source == image_type and image.name == name: if image.source == imageType and image.name == name:
image.background = background image.background = background
self._reset_image(image) self._resetImage(image)
def _reset_image(self, image): def _resetImage(self, image):
image.image = None image.image = None
image.image_bytes = None image.image_bytes = None
self._conversion_queue.modify_priority(image, Priority.Normal) self._conversionQueue.modify_priority(image, Priority.Normal)
def process_updates(self): def processUpdates(self):
""" """
Flush the queue to updated any data to update Flush the queue to updated any data to update
""" """
# We want only one thread. # We want only one thread.
if not self._imageThread.isRunning(): if not self.imageThread.isRunning():
self._imageThread.start() self.imageThread.start()
def get_image(self, name): def getImage(self, name):
""" """
Return the ``QImage`` from the cache. If not present wait for the Return the ``QImage`` from the cache. If not present wait for the
background thread to process it. background thread to process it.
""" """
log.debug(u'get_image %s' % name) log.debug(u'getImage %s' % name)
image = self._cache[name] image = self._cache[name]
if image.image is None: if image.image is None:
self._conversion_queue.modify_priority(image, Priority.High) self._conversionQueue.modify_priority(image, Priority.High)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
self.process_updates() self.processUpdates()
while image.image is None: while image.image is None:
log.debug(u'get_image - waiting') log.debug(u'getImage - waiting')
time.sleep(0.1) time.sleep(0.1)
elif image.image_bytes is None: elif image.image_bytes is None:
# Set the priority to Low, because the image was requested but the # Set the priority to Low, because the image was requested but the
# byte stream was not generated yet. However, we only need to do # byte stream was not generated yet. However, we only need to do
# this, when the image was generated before it was requested # this, when the image was generated before it was requested
# (otherwise this is already taken care of). # (otherwise this is already taken care of).
self._conversion_queue.modify_priority(image, Priority.Low) self._conversionQueue.modify_priority(image, Priority.Low)
return image.image return image.image
def get_image_bytes(self, name): def getImageBytes(self, name):
""" """
Returns the byte string for an image. If not present wait for the Returns the byte string for an image. If not present wait for the
background thread to process it. background thread to process it.
""" """
log.debug(u'get_image_bytes %s' % name) log.debug(u'getImageBytes %s' % name)
image = self._cache[name] image = self._cache[name]
if image.image_bytes is None: if image.image_bytes is None:
self._conversion_queue.modify_priority(image, Priority.Urgent) self._conversionQueue.modify_priority(image, Priority.Urgent)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
self.process_updates() self.processUpdates()
while image.image_bytes is None: while image.image_bytes is None:
log.debug(u'get_image_bytes - waiting') log.debug(u'getImageBytes - waiting')
time.sleep(0.1) time.sleep(0.1)
return image.image_bytes return image.image_bytes
def del_image(self, name): def deleteImage(self, name):
""" """
Delete the Image from the cache. Delete the Image from the cache.
""" """
log.debug(u'del_image %s' % name) log.debug(u'deleteImage %s' % name)
if name in self._cache: if name in self._cache:
self._conversion_queue.remove(self._cache[name]) self._conversionQueue.remove(self._cache[name])
del self._cache[name] del self._cache[name]
def add_image(self, name, path, source, background): def addImage(self, name, path, source, background):
""" """
Add image to cache if it is not already there. Add image to cache if it is not already there.
""" """
log.debug(u'add_image %s:%s' % (name, path)) log.debug(u'addImage %s:%s' % (name, path))
if not name in self._cache: if not name in self._cache:
image = Image(name, path, source, background) image = Image(name, path, source, background)
self._cache[name] = image self._cache[name] = image
self._conversion_queue.put( self._conversionQueue.put(
(image.priority, image.secondary_priority, image)) (image.priority, image.secondary_priority, image))
else: else:
log.debug(u'Image in cache %s:%s' % (name, path)) log.debug(u'Image in cache %s:%s' % (name, path))
# We want only one thread. # We want only one thread.
if not self._imageThread.isRunning(): if not self.imageThread.isRunning():
self._imageThread.start() self.imageThread.start()
def _process(self): def _process(self):
""" """
Controls the processing called from a ``QtCore.QThread``. Controls the processing called from a ``QtCore.QThread``.
""" """
log.debug(u'_process - started') log.debug(u'_process - started')
while not self._conversion_queue.empty(): while not self._conversionQueue.empty() and not self.stopManager:
self._process_cache() self._processCache()
log.debug(u'_process - ended') log.debug(u'_process - ended')
def _process_cache(self): def _processCache(self):
""" """
Actually does the work. Actually does the work.
""" """
log.debug(u'_process_cache') log.debug(u'_processCache')
image = self._conversion_queue.get()[2] image = self._conversionQueue.get()[2]
# Generate the QImage for the image. # Generate the QImage for the image.
if image.image is None: if image.image is None:
image.image = resize_image(image.path, self.width, self.height, image.image = resize_image(image.path, self.width, self.height,
@ -307,14 +308,14 @@ class ImageManager(QtCore.QObject):
# Set the priority to Lowest and stop here as we need to process # Set the priority to Lowest and stop here as we need to process
# more important images first. # more important images first.
if image.priority == Priority.Normal: if image.priority == Priority.Normal:
self._conversion_queue.modify_priority(image, Priority.Lowest) self._conversionQueue.modify_priority(image, Priority.Lowest)
return return
# For image with high priority we set the priority to Low, as the # For image with high priority we set the priority to Low, as the
# byte stream might be needed earlier the byte stream of image with # byte stream might be needed earlier the byte stream of image with
# Normal priority. We stop here as we need to process more important # Normal priority. We stop here as we need to process more important
# images first. # images first.
elif image.priority == Priority.High: elif image.priority == Priority.High:
self._conversion_queue.modify_priority(image, Priority.Low) self._conversionQueue.modify_priority(image, Priority.Low)
return return
# Generate the byte stream for the image. # Generate the byte stream for the image.
if image.image_bytes is None: if image.image_bytes is None:

View File

@ -132,7 +132,7 @@ class Renderer(object):
""" """
# if No file do not update cache # if No file do not update cache
if temp_theme.background_filename: if temp_theme.background_filename:
self.imageManager.add_image(temp_theme.theme_name, self.imageManager.addImage(temp_theme.theme_name,
temp_theme.background_filename, u'theme', temp_theme.background_filename, u'theme',
QtGui.QColor(temp_theme.background_border_color)) QtGui.QColor(temp_theme.background_border_color))
@ -204,7 +204,7 @@ class Renderer(object):
# make big page for theme edit dialog to get line count # make big page for theme edit dialog to get line count
serviceItem.add_from_text(u'', VERSE_FOR_LINE_COUNT) serviceItem.add_from_text(u'', VERSE_FOR_LINE_COUNT)
else: else:
self.imageManager.del_image(theme_data.theme_name) self.imageManager.deleteImage(theme_data.theme_name)
serviceItem.add_from_text(u'', VERSE) serviceItem.add_from_text(u'', VERSE)
serviceItem.renderer = self serviceItem.renderer = self
serviceItem.raw_footer = FOOTER serviceItem.raw_footer = FOOTER

View File

@ -211,7 +211,7 @@ class ServiceItem(object):
self.image_border = background self.image_border = background
self.service_item_type = ServiceItemType.Image self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path}) self._raw_frames.append({u'title': title, u'path': path})
self.renderer.imageManager.add_image(title, path, u'image', self.renderer.imageManager.addImage(title, path, u'image',
self.image_border) self.image_border)
self._new_item() self._new_item()

View File

@ -277,7 +277,7 @@ class MainDisplay(Display):
""" """
API for replacement backgrounds so Images are added directly to cache. API for replacement backgrounds so Images are added directly to cache.
""" """
self.imageManager.add_image(name, path, u'image', background) self.imageManager.addImage(name, path, u'image', background)
if hasattr(self, u'serviceItem'): if hasattr(self, u'serviceItem'):
self.override[u'image'] = name self.override[u'image'] = name
self.override[u'theme'] = self.serviceItem.themedata.theme_name self.override[u'theme'] = self.serviceItem.themedata.theme_name
@ -297,7 +297,7 @@ class MainDisplay(Display):
The name of the image to be displayed. The name of the image to be displayed.
""" """
log.debug(u'image to display') log.debug(u'image to display')
image = self.imageManager.get_image_bytes(name) image = self.imageManager.getImageBytes(name)
self.controller.mediaController.video_reset(self.controller) self.controller.mediaController.video_reset(self.controller)
self.displayImage(image) self.displayImage(image)
@ -382,14 +382,14 @@ class MainDisplay(Display):
else: else:
# replace the background # replace the background
background = self.imageManager. \ background = self.imageManager. \
get_image_bytes(self.override[u'image']) getImageBytes(self.override[u'image'])
self.setTransparency(self.serviceItem.themedata.background_type == self.setTransparency(self.serviceItem.themedata.background_type ==
BackgroundType.to_string(BackgroundType.Transparent)) BackgroundType.to_string(BackgroundType.Transparent))
if self.serviceItem.themedata.background_filename: if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.imageManager. \ self.serviceItem.bg_image_bytes = self.imageManager. \
get_image_bytes(self.serviceItem.themedata.theme_name) getImageBytes(self.serviceItem.themedata.theme_name)
if image: if image:
image_bytes = self.imageManager.get_image_bytes(image) image_bytes = self.imageManager.getImageBytes(image)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.serviceItem, self.screen, self.isLive, html = build_html(self.serviceItem, self.screen, self.isLive,

View File

@ -30,6 +30,7 @@ import os
import sys import sys
import shutil import shutil
from tempfile import gettempdir from tempfile import gettempdir
import time
from datetime import datetime from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -1121,7 +1122,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
log.debug(u'screenChanged') log.debug(u'screenChanged')
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
self.imageManager.update_display() self.imageManager.updateDisplay()
self.renderer.update_display() self.renderer.update_display()
self.previewController.screenSizeChanged() self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged() self.liveController.screenSizeChanged()
@ -1140,6 +1141,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
return return
# If we just did a settings import, close without saving changes. # If we just did a settings import, close without saving changes.
if self.settingsImported: if self.settingsImported:
self.cleanUp(False)
event.accept() event.accept()
if self.serviceManagerContents.isModified(): if self.serviceManagerContents.isModified():
ret = self.serviceManagerContents.saveModifiedService() ret = self.serviceManagerContents.saveModifiedService()
@ -1162,8 +1164,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
translate('OpenLP.MainWindow', translate('OpenLP.MainWindow',
'Are you sure you want to close OpenLP?'), 'Are you sure you want to close OpenLP?'),
QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Yes | QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
QtGui.QMessageBox.No),
QtGui.QMessageBox.Yes) QtGui.QMessageBox.Yes)
if ret == QtGui.QMessageBox.Yes: if ret == QtGui.QMessageBox.Yes:
self.cleanUp() self.cleanUp()
@ -1174,12 +1175,19 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.cleanUp() self.cleanUp()
event.accept() event.accept()
def cleanUp(self): def cleanUp(self, save_settings=True):
""" """
Runs all the cleanup code before OpenLP shuts down Runs all the cleanup code before OpenLP shuts down.
``save_settings``
Switch to prevent saving settings. Defaults to **True**.
""" """
self.imageManager.stopManager = True
while self.imageManager.imageThread.isRunning():
time.sleep(0.1)
# Clean temporary files used by services # Clean temporary files used by services
self.serviceManagerContents.cleanUp() self.serviceManagerContents.cleanUp()
if save_settings:
if QtCore.QSettings().value(u'advanced/save current plugin', if QtCore.QSettings().value(u'advanced/save current plugin',
QtCore.QVariant(False)).toBool(): QtCore.QVariant(False)).toBool():
QtCore.QSettings().setValue(u'advanced/current media plugin', QtCore.QSettings().setValue(u'advanced/current media plugin',
@ -1187,6 +1195,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# Call the cleanup method to shutdown plugins. # Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins') log.info(u'cleanup plugins')
self.pluginManager.finalise_plugins() self.pluginManager.finalise_plugins()
if save_settings:
# Save settings # Save settings
self.saveSettings() self.saveSettings()
# Close down the display # Close down the display

View File

@ -859,8 +859,8 @@ class SlideController(Controller):
# If current slide set background to image # If current slide set background to image
if framenumber == slideno: if framenumber == slideno:
self.serviceItem.bg_image_bytes = \ self.serviceItem.bg_image_bytes = \
self.imageManager.get_image_bytes(frame[u'title']) self.imageManager.getImageBytes(frame[u'title'])
image = self.imageManager.get_image(frame[u'title']) image = self.imageManager.getImage(frame[u'title'])
label.setPixmap(QtGui.QPixmap.fromImage(image)) label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label) self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * self.parent().renderer.screen_ratio slideHeight = width * self.parent().renderer.screen_ratio

View File

@ -664,9 +664,9 @@ class ThemeManager(QtGui.QWidget):
self._writeTheme(theme, image_from, image_to) self._writeTheme(theme, image_from, image_to)
if theme.background_type == \ if theme.background_type == \
BackgroundType.to_string(BackgroundType.Image): BackgroundType.to_string(BackgroundType.Image):
self.mainwindow.imageManager.update_image(theme.theme_name, self.mainwindow.imageManager.updateImage(theme.theme_name,
u'theme', QtGui.QColor(theme.background_border_color)) u'theme', QtGui.QColor(theme.background_border_color))
self.mainwindow.imageManager.process_updates() self.mainwindow.imageManager.processUpdates()
self.loadThemes() self.loadThemes()
def _writeTheme(self, theme, image_from, image_to): def _writeTheme(self, theme, image_from, image_to):

View File

@ -96,4 +96,4 @@ class ImagePlugin(Plugin):
""" """
background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection
+ u'/background color', QtCore.QVariant(u'#000000'))) + u'/background color', QtCore.QVariant(u'#000000')))
self.liveController.imageManager.update_images(u'image', background) self.liveController.imageManager.updateImages(u'image', background)