From 76f6c8b87ca2598fc66f094c4c90de1bafcfb6d2 Mon Sep 17 00:00:00 2001 From: M2j Date: Tue, 29 Jun 2010 00:29:54 +0200 Subject: [PATCH 01/24] proof-of-concept songs search button --- openlp/core/lib/__init__.py | 9 ++- openlp/core/ui/servicemanager.py | 2 +- openlp/core/ui/slidecontroller.py | 2 +- openlp/plugins/songs/lib/mediaitem.py | 104 ++++++++++++++++---------- 4 files changed, 73 insertions(+), 44 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 5a4d3f5b3..ae3d15fe1 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -35,7 +35,7 @@ from PyQt4 import QtCore, QtGui log = logging.getLogger(__name__) -def translate(context, text, comment=None): +def translate(context, text, comment=None, count=-1): """ A special shortcut method to wrap around the Qt4 translation functions. This abstracts the translation procedure so that we can change it if at a @@ -47,6 +47,13 @@ def translate(context, text, comment=None): ``text`` The text to put into the translation tables for translation. + + ``comment`` + A optional comment for translators. + + ``count`` + If count is given it replaces %n in the text. A propper plural form is + chosen. """ return QtCore.QCoreApplication.translate(context, text, comment) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index cccd34195..41704bc5d 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -108,7 +108,7 @@ class ServiceManager(QtGui.QWidget): #is a new service and has not been saved self.isNew = True self.serviceNoteForm = ServiceNoteForm() - self.serviceItemEditForm = ServiceItemEditForm() + self.serviceItemEditForm = ServiceItemEditForm(self) #start with the layout self.Layout = QtGui.QVBoxLayout(self) self.Layout.setSpacing(0) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 10cd3cff0..53327eb7e 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -802,7 +802,7 @@ class SlideController(QtGui.QWidget): QtCore.QTimer.singleShot(2.5, self.grabMainDisplay) else: label = self.PreviewListWidget.cellWidget( - self.PreviewListWidget.currentRow(), 1) + self.PreviewListWidget.currentRow(), 0) self.SlidePreview.setPixmap(label.pixmap()) def grabMainDisplay(self): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index ab70c9659..1a87a6c23 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -74,45 +74,60 @@ class SongMediaItem(MediaManagerItem): u'Maintain the lists of authors, topics and books'), ':/songs/song_maintenance.png', self.onSongMaintenanceClick) self.PageLayout.setSpacing(4) - self.SearchLayout = QtGui.QFormLayout() - self.SearchLayout.setMargin(0) - self.SearchLayout.setSpacing(4) - self.SearchLayout.setObjectName(u'SearchLayout') + self.SearchLineLayout = QtGui.QHBoxLayout() + self.SearchLineLayout.setMargin(0) + self.SearchLineLayout.setSpacing(4) + self.SearchLineLayout.setObjectName(u'SearchLineLayout') + self.PageLayout.addLayout(self.SearchLineLayout) self.SearchTextLabel = QtGui.QLabel(self) - self.SearchTextLabel.setAlignment( - QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) self.SearchTextLabel.setObjectName(u'SearchTextLabel') - self.SearchLayout.setWidget( - 0, QtGui.QFormLayout.LabelRole, self.SearchTextLabel) + self.SearchLineLayout.addWidget(self.SearchTextLabel) self.SearchTextEdit = QtGui.QLineEdit(self) self.SearchTextEdit.setObjectName(u'SearchTextEdit') - self.SearchLayout.setWidget( - 0, QtGui.QFormLayout.FieldRole, self.SearchTextEdit) - self.SearchTypeLabel = QtGui.QLabel(self) - self.SearchTypeLabel.setAlignment( - QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) - self.SearchTypeLabel.setObjectName(u'SearchTypeLabel') - self.SearchLayout.setWidget( - 1, QtGui.QFormLayout.LabelRole, self.SearchTypeLabel) - self.SearchTypeComboBox = QtGui.QComboBox(self) - self.SearchTypeComboBox.setObjectName(u'SearchTypeComboBox') - self.SearchLayout.setWidget( - 1, QtGui.QFormLayout.FieldRole, self.SearchTypeComboBox) - self.PageLayout.addLayout(self.SearchLayout) + self.SearchLineLayout.addWidget(self.SearchTextEdit) self.SearchButtonLayout = QtGui.QHBoxLayout() self.SearchButtonLayout.setMargin(0) self.SearchButtonLayout.setSpacing(4) self.SearchButtonLayout.setObjectName(u'SearchButtonLayout') + self.PageLayout.addLayout(self.SearchButtonLayout) self.SearchButtonSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.SearchButtonLayout.addItem(self.SearchButtonSpacer) - self.SearchTextButton = QtGui.QPushButton(self) - self.SearchTextButton.setObjectName(u'SearchTextButton') - self.SearchButtonLayout.addWidget(self.SearchTextButton) + self.SearchButtonLayout.addSpacerItem(self.SearchButtonSpacer) self.ClearTextButton = QtGui.QPushButton(self) self.ClearTextButton.setObjectName(u'ClearTextButton') self.SearchButtonLayout.addWidget(self.ClearTextButton) - self.PageLayout.addLayout(self.SearchButtonLayout) + self.SearchTextButton = QtGui.QToolButton(self) + self.SearchTextButton.setObjectName(u'SearchTextButton') + self.SearchButtonLayout.addWidget(self.SearchTextButton) + self.SearchTitlesAction = QtGui.QAction(self) + self.SearchTitlesAction.setObjectName(u'SearchTitlesAction') + self.SearchTitlesAction.setCheckable(True) + self.SearchLyricsAction = QtGui.QAction(self) + self.SearchLyricsAction.setObjectName(u'SearchLyricsAction') + self.SearchLyricsAction.setCheckable(True) + self.SearchAuthorsAction = QtGui.QAction(self) + self.SearchAuthorsAction.setObjectName(u'SearchAuthorsAction') + self.SearchAuthorsAction.setCheckable(True) + self.SearchActionGroup = QtGui.QActionGroup(self) + self.SearchActionGroup.setObjectName(u'SearchActionGroup') + self.SearchActionGroup.setExclusive(True) + self.SearchActionGroup.addAction(self.SearchTitlesAction) + self.SearchActionGroup.addAction(self.SearchLyricsAction) + self.SearchActionGroup.addAction(self.SearchAuthorsAction) + self.SearchTypeMenu = QtGui.QMenu(self) + self.SearchTypeMenu.setObjectName(u'SearchTypeMenu') + self.SearchTypeMenu.addAction(self.SearchTitlesAction) + self.SearchTypeMenu.addAction(self.SearchLyricsAction) + self.SearchTypeMenu.addAction(self.SearchAuthorsAction) + self.SearchTextButton.setPopupMode(QtGui.QToolButton.MenuButtonPopup) + self.SearchTextButton.setMenu(self.SearchTypeMenu) + QtCore.QObject.connect(self.SearchTitlesAction, + QtCore.SIGNAL(u'triggered()'), self.onSearchTextButtonClick) + QtCore.QObject.connect(self.SearchLyricsAction, + QtCore.SIGNAL(u'triggered()'), self.onSearchTextButtonClick) + QtCore.QObject.connect(self.SearchAuthorsAction, + QtCore.SIGNAL(u'triggered()'), self.onSearchTextButtonClick) + # Signals and slots QtCore.QObject.connect(self.SearchTextEdit, QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick) @@ -142,38 +157,45 @@ class SongMediaItem(MediaManagerItem): def retranslateUi(self): self.SearchTextLabel.setText( translate(u'SongsPlugin.MediaItem', u'Search:')) - self.SearchTypeLabel.setText( - translate(u'SongsPlugin.MediaItem', u'Type:')) self.ClearTextButton.setText( translate(u'SongsPlugin.MediaItem', u'Clear')) - self.SearchTextButton.setText( - translate(u'SongsPlugin.MediaItem', u'Search')) + self.SearchTitlesAction.setText( + translate(u'SongsPlugin.MediaItem', u'Search Titles')) + self.SearchLyricsAction.setText( + translate(u'SongsPlugin.MediaItem', u'Search Lyrics')) + self.SearchAuthorsAction.setText( + translate(u'SongsPlugin.MediaItem', u'Search Authors')) + if self.SearchTitlesAction.isChecked(): + self.SearchTextButton.setText(self.SearchTitlesAction.text()) + if self.SearchLyricsAction.isChecked(): + self.SearchTextButton.setText(self.SearchLyricsAction.text()) + if self.SearchAuthorsAction.isChecked(): + self.SearchTextButton.setText(self.SearchAuthorsAction.text()) def initialise(self): - self.SearchTypeComboBox.addItem( - translate(u'SongsPlugin.MediaItem', u'Titles')) - self.SearchTypeComboBox.addItem( - translate(u'SongsPlugin.MediaItem', u'Lyrics')) - self.SearchTypeComboBox.addItem( - translate(u'SongsPlugin.MediaItem', u'Authors')) + self.SearchTitlesAction.setChecked(True) + self.SearchTextButton.setText(self.SearchTitlesAction.text()) self.configUpdated() def onSearchTextButtonClick(self): search_keywords = unicode(self.SearchTextEdit.displayText()) search_results = [] - search_type = self.SearchTypeComboBox.currentIndex() - if search_type == 0: +# search_type = self.SearchTypeComboBox.currentIndex() + if self.SearchTitlesAction.isChecked(): #search_type == 0: log.debug(u'Titles Search') + self.SearchTextButton.setText(self.SearchTitlesAction.text()) search_results = self.parent.manager.search_song_title( search_keywords) self.displayResultsSong(search_results) - elif search_type == 1: + elif self.SearchLyricsAction.isChecked(): #search_type == 1: log.debug(u'Lyrics Search') + self.SearchTextButton.setText(self.SearchLyricsAction.text()) search_results = self.parent.manager.search_song_lyrics( search_keywords) self.displayResultsSong(search_results) - elif search_type == 2: + elif self.SearchAuthorsAction.isChecked(): #search_type == 2: log.debug(u'Authors Search') + self.SearchTextButton.setText(self.SearchAuthorsAction.text()) search_results = self.parent.manager.get_song_from_author( search_keywords) self.displayResultsAuthor(search_results) @@ -228,7 +250,7 @@ class SongMediaItem(MediaManagerItem): """ if self.searchAsYouType: search_length = 1 - if self.SearchTypeComboBox.currentIndex() == 1: + if self.SearchLyricsAction.isChecked(): # self.SearchTypeComboBox.currentIndex() == 1: search_length = 7 if len(text) > search_length: self.onSearchTextButtonClick() From c3b890e1989f5ee3f749db4a11a18ecd95f437c4 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Oct 2010 15:43:51 +0100 Subject: [PATCH 02/24] Performance updates --- openlp/core/ui/slidecontroller.py | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 78ac70b86..ba2f0a7b8 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -26,6 +26,7 @@ import logging import os +import time from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon @@ -36,6 +37,24 @@ from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ log = logging.getLogger(__name__) +class SlideThread(QtCore.QThread): + """ + A special Qt thread class to speed up the display of text based frames. + This is threaded so it loads the frames in background + """ + def __init__(self, parent, prefix, count): + QtCore.QThread.__init__(self, parent) + self.prefix = prefix + self.count = count + + def run(self): + """ + Run the thread. + """ + time.sleep(1) + for i in range(0, self.count): + Receiver.send_message(u'%s_slide_cache' % self.prefix, i) + class SlideList(QtGui.QTableWidget): """ Customised version of QTableWidget which can respond to keyboard @@ -391,6 +410,8 @@ class SlideController(QtGui.QWidget): if self.isLive: QtCore.QObject.connect(self.volumeSlider, QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache) def screenSizeChanged(self): """ @@ -617,6 +638,10 @@ class SlideController(QtGui.QWidget): self.PreviewListWidget.setFocus() Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix, [serviceItem]) + if self.serviceItem.is_image(): + st = SlideThread( + self, self.typePrefix, len(self.serviceItem.get_frames())) + st.start() def onTextRequest(self): """ @@ -769,6 +794,13 @@ class SlideController(QtGui.QWidget): % self.serviceItem.name.lower(), [self.serviceItem, self.isLive]) + def slideCache(self, slide): + """ + Generate a slide cache item rendered and ready for use + in the background. + """ + self.serviceItem.get_rendered_frame(int(slide)) + def onSlideSelected(self): """ Generate the preview when you click on a slide. From 6dbb80ee9443b1294c90f46d77c7f9f327207282 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Oct 2010 18:24:56 +0100 Subject: [PATCH 03/24] Initial version of Image performance improvements --- openlp/core/lib/__init__.py | 1 + openlp/core/lib/renderer.py | 21 ++++--------- openlp/core/lib/rendermanager.py | 6 +++- openlp/core/lib/serviceitem.py | 3 +- openlp/core/ui/maindisplay.py | 7 ++--- openlp/core/ui/slidecontroller.py | 41 ++------------------------ openlp/plugins/images/lib/mediaitem.py | 4 +-- 7 files changed, 22 insertions(+), 61 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index b43c491ff..402b53798 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -314,6 +314,7 @@ def expand_tags(text): from spelltextedit import SpellTextEdit from eventreceiver import Receiver +from imagemanager import ImageManager from settingsmanager import SettingsManager from plugin import PluginStatus, StringContent, Plugin from pluginmanager import PluginManager diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index d5bcab457..b6ed0b322 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -73,7 +73,7 @@ class Renderer(object): self.theme_name = theme.theme_name if theme.background_type == u'image': if theme.background_filename: - self._bg_image_filename = unicode(theme.background_filename) + self._bg_image_filename =theme.background_filename def set_text_rectangle(self, rect_main, rect_footer): """ @@ -118,25 +118,16 @@ class Renderer(object): """ log.debug(u'set frame dest (frame) w %d h %d', frame_width, frame_height) - self.frame = QtGui.QImage(frame_width, frame_height, - QtGui.QImage.Format_ARGB32_Premultiplied) - if self._bg_image_filename and not self.bg_image: - self.bg_image = resize_image(self._bg_image_filename, - self.frame.width(), self.frame.height()) if self._theme.background_type == u'image': - self.bg_frame = QtGui.QImage(self.frame.width(), - self.frame.height(), + frame = QtGui.QImage(frame_width, frame_height, QtGui.QImage.Format_ARGB32_Premultiplied) - painter = QtGui.QPainter() - painter.begin(self.bg_frame) - painter.fillRect(self.frame.rect(), QtCore.Qt.black) - if self.bg_image: - painter.drawImage(0, 0, self.bg_image) - painter.end() - self.bg_image_bytes = image_to_byte(self.bg_frame) + self.bg_image = resize_image(self._bg_image_filename, + frame.width(), frame.height()) + self.bg_image_bytes = image_to_byte(self.bg_image) else: self.bg_frame = None self.bg_image_bytes = None + log.debug(u'end frame dest (frame)') def format_slide(self, words, line_break): """ diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index ec6a7f8cb..da19d59ec 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore -from openlp.core.lib import Renderer, ThemeLevel, ServiceItem +from openlp.core.lib import Renderer, ThemeLevel, ServiceItem, ImageManager from openlp.core.ui import MainDisplay log = logging.getLogger(__name__) @@ -56,6 +56,7 @@ class RenderManager(object): """ log.debug(u'Initilisation started') self.screens = screens + self.image_manager = ImageManager() self.display = MainDisplay(self, screens, False) self.display.setup() self.theme_manager = theme_manager @@ -78,6 +79,7 @@ class RenderManager(object): self.display.setup() self.renderer.bg_frame = None self.themedata = None + self.image_manager.update_display(self.width, self.height) def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global): """ @@ -153,6 +155,8 @@ class RenderManager(object): self.calculate_default(self.screens.current[u'size']) self.renderer.set_theme(self.themedata) self.build_text_rectangle(self.themedata) + self.image_manager.add_image(self.themedata.theme_name, + self.themedata.background_filename) self.renderer.set_frame_dest(self.width, self.height) return self.renderer._rect, self.renderer._rect_footer diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index a5417916e..7eb0d97c9 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -208,6 +208,7 @@ class ServiceItem(object): self.service_item_type = ServiceItemType.Image self._raw_frames.append( {u'title': title, u'image': image, u'path': path}) + self.render_manager.image_manager.add_image(title, path) self._new_item() def add_from_text(self, title, raw_slide, verse_tag=None): @@ -389,7 +390,7 @@ class ServiceItem(object): if self.service_item_type == ServiceItemType.Text: return None, self._display_frames[row][u'html'].split(u'\n')[0] else: - return self._raw_frames[row][u'image'], u'' + return self._raw_frames[row][u'title'], u'' def get_frame_title(self, row=0): """ diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index d8dabd315..7326c0e2f 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -222,7 +222,7 @@ class MainDisplay(DisplayWidget): shrinkItem.resize(self.screen[u'size'].width(), self.screen[u'size'].height()) - def image(self, image): + def image(self, name): """ Add an image as the background. The image is converted to a bytestream on route. @@ -231,9 +231,8 @@ class MainDisplay(DisplayWidget): The Image to be displayed can be QImage or QPixmap """ log.debug(u'image to display') - if not isinstance(image, QtGui.QImage): - image = resize_image(image, self.screen[u'size'].width(), - self.screen[u'size'].height()) + image = self.parent.parent.RenderManager.image_manager. \ + get_image(name) self.resetVideo() self.displayImage(image) # show screen diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index ba2f0a7b8..d44ff226c 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -37,24 +37,6 @@ from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ log = logging.getLogger(__name__) -class SlideThread(QtCore.QThread): - """ - A special Qt thread class to speed up the display of text based frames. - This is threaded so it loads the frames in background - """ - def __init__(self, parent, prefix, count): - QtCore.QThread.__init__(self, parent) - self.prefix = prefix - self.count = count - - def run(self): - """ - Run the thread. - """ - time.sleep(1) - for i in range(0, self.count): - Receiver.send_message(u'%s_slide_cache' % self.prefix, i) - class SlideList(QtGui.QTableWidget): """ Customised version of QTableWidget which can respond to keyboard @@ -410,8 +392,6 @@ class SlideController(QtGui.QWidget): if self.isLive: QtCore.QObject.connect(self.volumeSlider, QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache) def screenSizeChanged(self): """ @@ -606,13 +586,9 @@ class SlideController(QtGui.QWidget): label = QtGui.QLabel() label.setMargin(4) label.setScaledContents(True) - if isinstance(frame[u'image'], QtGui.QImage): - label.setPixmap(QtGui.QPixmap.fromImage(frame[u'image'])) - else: - pixmap = resize_image(frame[u'image'], - self.parent.RenderManager.width, - self.parent.RenderManager.height) - label.setPixmap(QtGui.QPixmap.fromImage(pixmap)) + image = self.parent.RenderManager.image_manager. \ + get_image(frame[u'title']) + label.setPixmap(QtGui.QPixmap.fromImage(image)) self.PreviewListWidget.setCellWidget(framenumber, 0, label) slideHeight = width * self.parent.RenderManager.screen_ratio row += 1 @@ -638,10 +614,6 @@ class SlideController(QtGui.QWidget): self.PreviewListWidget.setFocus() Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix, [serviceItem]) - if self.serviceItem.is_image(): - st = SlideThread( - self, self.typePrefix, len(self.serviceItem.get_frames())) - st.start() def onTextRequest(self): """ @@ -794,13 +766,6 @@ class SlideController(QtGui.QWidget): % self.serviceItem.name.lower(), [self.serviceItem, self.isLive]) - def slideCache(self, slide): - """ - Generate a slide cache item rendered and ready for use - in the background. - """ - self.serviceItem.get_rendered_frame(int(slide)) - def onSlideSelected(self): """ Generate the preview when you click on a slide. diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 5a3918dd9..05510fc13 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -166,9 +166,9 @@ class ImageMediaItem(MediaManagerItem): for item in items: bitem = self.listView.item(item.row()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) - frame = QtGui.QImage(unicode(filename)) + #frame = QtGui.QImage(unicode(filename)) (path, name) = os.path.split(filename) - service_item.add_from_image(path, name, frame) + service_item.add_from_image(path, name, None) return True else: return False From 76ddf975a76fa6365f3ebfaea56143d89690c358 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Oct 2010 19:56:58 +0100 Subject: [PATCH 04/24] Add ImageManager --- openlp/core/lib/imagemanager.py | 145 ++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 openlp/core/lib/imagemanager.py diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py new file mode 100644 index 000000000..83277ad6e --- /dev/null +++ b/openlp/core/lib/imagemanager.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2010 Raoul Snyman # +# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian # +# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # +# Carsten Tinggaard, Frode Woldsund # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +Provides the store and management for Images automatically caching them and +resizing them when needed. Only one copy of each image is needed in the system. +A Thread is used to convert the image to a byte array so the user does not need +to wait for the conversion to happen. +""" +import logging +import os + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import resize_image, image_to_byte + +log = logging.getLogger(__name__) + +class ImageThread(QtCore.QThread): + """ + A special Qt thread class to speed up the display of text based frames. + This is threaded so it loads the frames in background + """ + def __init__(self, manager): + QtCore.QThread.__init__(self, None) + self.image_mamager = manager + + def run(self): + """ + Run the thread. + """ + self.image_mamager.process() + + +class Image(object): + name = '' + path = '' + dirty = True + image = None + image_bytes = None + +class ImageManager(QtCore.QObject): + """ + Image Manager handles the conversion and sizing of images. + + """ + log.info(u'Image Manager loaded') + + def __init__(self): + self._cache = {} + self._thread_running = False + self._cache_dirty = False + self.image_thread = ImageThread(self) + + def update_display(self, width, height): + """ + Screen has changed size so rebuild the cache to new size + """ + log.debug(u'update_display') + self.width = width + self.height = height + # mark the images as dirty for a rebuild + for key in self._cache.keys(): + image = self._cache[key] + image.dirty = True + fullpath = os.path.join(image.path, image.name) + image.image = resize_image(fullpath, + self.width, self.height) + self._cache_dirty = True + # only one thread please + if not self._thread_running: + self.image_thread.start() + + def get_image(self, name): + return self._cache[name].image + + def get_image_bytes(self, name): + return self._cache[name].image_bytes + + def add_image(self, name, path): + """ + Add image to cache if it is not already there + """ + log.debug(u'add_image') + if not name in self._cache: + image = Image() + image.name = name + image.path = path + fullpath = os.path.join(image.path, image.name) + image.image = resize_image(fullpath, + self.width, self.height) + self._cache[name] = image + self._cache_dirty = True + # only one thread please + if not self._thread_running: + self.image_thread.start() + + def process(self): + """ + Controls the processing called from a QThread + """ + log.debug(u'process - started') + self._thread_running = True + self.clean_cache() + # data loaded since we started ? + while self._cache_dirty: + log.debug(u'process - recycle') + self.clean_cache() + self._thread_running = False + log.debug(u'process - ended') + + def clean_cache(self): + """ + Actually does the work. + """ + log.debug(u'clean_cache') + # we will clean the cache now + self._cache_dirty = False + for key in self._cache.keys(): + image = self._cache[key] + if image.dirty: + image.image_bytes = image_to_byte(image.image) + image.dirty = False From b0ba4472bd1c28ca9d2282299241a144ce02bc11 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 23 Oct 2010 08:23:49 +0100 Subject: [PATCH 05/24] Fix up themes now --- openlp/core/lib/htmlbuilder.py | 13 +++++----- openlp/core/lib/imagemanager.py | 19 +++++++++++--- openlp/core/lib/renderer.py | 36 -------------------------- openlp/core/lib/rendermanager.py | 1 - openlp/core/lib/serviceitem.py | 1 - openlp/core/ui/maindisplay.py | 19 +++++++++----- openlp/plugins/images/lib/mediaitem.py | 6 ++--- 7 files changed, 39 insertions(+), 56 deletions(-) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 511046fe3..dc3a48565 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -90,16 +90,16 @@ body { var transition = %s; function show_video(state, path, volume, loop){ - // Note, the preferred method for looping would be to use the + // Note, the preferred method for looping would be to use the // video tag loop attribute. // But QtWebKit doesn't support this. Neither does it support the // onended event, hence the setInterval() // In addition, setting the currentTime attribute to zero to restart // the video raises an INDEX_SIZE_ERROR: DOM Exception 1 - // To complicate it further, sometimes vid.currentTime stops + // To complicate it further, sometimes vid.currentTime stops // slightly short of vid.duration and vid.ended is intermittent! // - // Note, currently the background may go black between loops. Not + // Note, currently the background may go black between loops. Not // desirable. Need to investigate using two