From 9f5c5f7133bc7c18df10090d95cb450cf00a78e3 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Sat, 22 Dec 2012 22:40:58 +0000 Subject: [PATCH 1/6] Add missing customs in service to media manager --- openlp/plugins/custom/forms/editcustomform.py | 2 - openlp/plugins/custom/lib/customtab.py | 29 +++++++++--- openlp/plugins/custom/lib/customxmlhandler.py | 2 + openlp/plugins/custom/lib/mediaitem.py | 44 +++++++++++++++++-- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index e8a587494..6eaf6af4d 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -125,8 +125,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): if not self._validate(): return False sxml = CustomXMLBuilder() - sxml.new_document() - sxml.add_lyrics_to_song() for count in range(self.slideListView.count()): sxml.add_verse_to_lyrics(u'custom', unicode(count + 1), unicode(self.slideListView.item(count).text())) diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 71066ec70..b5a894a79 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -49,18 +49,25 @@ class CustomTab(SettingsTab): self.displayFooterCheckBox = QtGui.QCheckBox(self.customModeGroupBox) self.displayFooterCheckBox.setObjectName(u'displayFooterCheckBox') self.customModeLayout.addRow(self.displayFooterCheckBox) + self.add_from_service_checkbox = QtGui.QCheckBox(self.customModeGroupBox) + self.add_from_service_checkbox.setObjectName(u'add_from_service_checkbox') + self.customModeLayout.addRow(self.add_from_service_checkbox) self.leftLayout.addWidget(self.customModeGroupBox) self.leftLayout.addStretch() self.rightLayout.addStretch() QtCore.QObject.connect(self.displayFooterCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onDisplayFooterCheckBoxChanged) + QtCore.QObject.connect(self.add_from_service_checkbox, + QtCore.SIGNAL(u'stateChanged(int)'), self.on_add_from_service_check_box_changed) def retranslateUi(self): self.customModeGroupBox.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display')) self.displayFooterCheckBox.setText( translate('CustomPlugin.CustomTab', 'Display footer')) + self.add_from_service_checkbox.setText(translate('CustomPlugin.CustomTab', + 'Import missing custom slides from service files')) def onDisplayFooterCheckBoxChanged(self, check_state): self.displayFooter = False @@ -68,12 +75,24 @@ class CustomTab(SettingsTab): if check_state == QtCore.Qt.Checked: self.displayFooter = True + def on_add_from_service_check_box_changed(self, check_state): + self.update_load = False + # we have a set value convert to True/False + if check_state == QtCore.Qt.Checked: + self.update_load = True + def load(self): - self.displayFooter = Settings().value( - self.settingsSection + u'/display footer', - QtCore.QVariant(True)).toBool() + settings = Settings() + settings.beginGroup(self.settingsSection) + self.displayFooter = settings.value(u'/display footer', QtCore.QVariant(True)).toBool() + self.update_load = settings.value(u'add custom from service', QtCore.QVariant(True)).toBool() self.displayFooterCheckBox.setChecked(self.displayFooter) + self.add_from_service_checkbox.setChecked(self.update_load) + settings.endGroup() def save(self): - Settings().setValue(self.settingsSection + u'/display footer', - QtCore.QVariant(self.displayFooter)) + settings = Settings() + settings.beginGroup(self.settingsSection) + settings.setValue(self.settingsSection + u'/display footer', QtCore.QVariant(self.displayFooter)) + settings.setValue(u'add custom from service', QtCore.QVariant(self.update_load)) + settings.endGroup() diff --git a/openlp/plugins/custom/lib/customxmlhandler.py b/openlp/plugins/custom/lib/customxmlhandler.py index f0904dfcd..bd321eb93 100644 --- a/openlp/plugins/custom/lib/customxmlhandler.py +++ b/openlp/plugins/custom/lib/customxmlhandler.py @@ -62,6 +62,8 @@ class CustomXMLBuilder(object): """ # Create the minidom document self.custom_xml = Document() + self.new_document() + self.add_lyrics_to_song() def new_document(self): """ diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 77b1d8c0b..04ec2ce97 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -32,12 +32,12 @@ import logging from PyQt4 import QtCore, QtGui from sqlalchemy.sql import or_, func -from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ - check_item_selected, translate, ServiceItemContext +from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, check_item_selected, translate, \ + ServiceItemContext, PluginStatus from openlp.core.lib.ui import UiStrings from openlp.core.lib.settings import Settings from openlp.plugins.custom.forms import EditCustomForm -from openlp.plugins.custom.lib import CustomXMLParser +from openlp.plugins.custom.lib import CustomXMLParser, CustomXMLBuilder from openlp.plugins.custom.lib.db import CustomSlide log = logging.getLogger(__name__) @@ -86,6 +86,11 @@ class CustomMediaItem(MediaManagerItem): QtCore.SIGNAL(u'custom_load_list'), self.loadList) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick) + QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.config_updated) + + def config_updated(self): + self.add_custom_from_service = Settings().value( + self.settingsSection + u'/add custom from service', QtCore.QVariant(u'True')).toBool() def retranslateUi(self): self.searchTextLabel.setText(u'%s:' % UiStrings().Search) @@ -104,6 +109,7 @@ class CustomMediaItem(MediaManagerItem): self.searchTextEdit.setCurrentSearchType(Settings().value( u'%s/last search type' % self.settingsSection, QtCore.QVariant(CustomSearch.Titles)).toInt()[0]) + self.config_updated() def loadList(self, custom_slides): # Sort out what custom we want to select after loading the list. @@ -201,6 +207,7 @@ class CustomMediaItem(MediaManagerItem): service_item.add_capability(ItemCapabilities.CanPreview) service_item.add_capability(ItemCapabilities.CanLoop) service_item.add_capability(ItemCapabilities.CanSoftBreak) + service_item.add_capability(ItemCapabilities.OnLoadUpdate) customSlide = self.plugin.manager.get_object(CustomSlide, item_id) title = customSlide.title credit = customSlide.credits @@ -256,6 +263,37 @@ class CustomMediaItem(MediaManagerItem): elif not text: self.onClearTextButtonClick() + def serviceLoad(self, item): + """ + Triggered by a song being loaded by the service manager. + """ + log.debug(u'serviceLoad') + if not self.add_custom_from_service: + return + if self.plugin.status != PluginStatus.Active: + return + custom = self.plugin.manager.get_object_filtered(CustomSlide, CustomSlide.title == item.title) + if custom: + return + custom = CustomSlide() + custom.title = item.title + custom.theme_name = item.theme + footer = u' '.join(item.raw_footer) + if footer: + if footer.startswith(item.title): + custom.credits = footer[len(item.title) + 1:] + else: + custom.credits = footer + else: + custom.credits = u'' + custom_xml = CustomXMLBuilder() + for (idx, slide) in enumerate(item._raw_frames): + custom_xml.add_verse_to_lyrics(u'custom', unicode(idx + 1), slide['raw_slide']) + custom.text = unicode(custom_xml.extract_xml(), u'utf-8') + self.plugin.manager.save_object(custom) + self.onSearchTextButtonClicked() + Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) + def onClearTextButtonClick(self): """ Clear the search text. From 0092fc696010e931ba41bd1990e8ba9befa7de6d Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Sun, 23 Dec 2012 00:00:24 +0000 Subject: [PATCH 2/6] Save any service text item as a custom slide --- openlp/core/ui/servicemanager.py | 17 ++++++++++++++++- openlp/plugins/custom/lib/mediaitem.py | 16 ++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index cef2824d7..eecec43d4 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -40,7 +40,7 @@ log = logging.getLogger(__name__) from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, ItemCapabilities, SettingsManager, \ - translate, str_to_bool, check_directory_exists + translate, str_to_bool, check_directory_exists, PluginStatus from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings, critical_error_message_box, create_widget_action, find_and_set_in_combo_box @@ -258,6 +258,8 @@ class ServiceManager(QtGui.QWidget): icon=u':/media/auto-start_active.png', triggers=self.onAutoStart) # Add already existing delete action to the menu. self.menu.addAction(self.serviceManagerList.delete) + self.create_custom_action = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', + 'Create New &Custom Slide'), icon=u':/general/general_edit.png', triggers=self.create_custom) self.menu.addSeparator() self.previewAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'), icon=u':/general/general_preview.png', triggers=self.makePreview) @@ -759,6 +761,7 @@ class ServiceManager(QtGui.QWidget): pos = item.parent().data(0, QtCore.Qt.UserRole).toInt()[0] serviceItem = self.serviceItems[pos - 1] self.editAction.setVisible(False) + self.create_custom_action.setVisible(False) self.maintainAction.setVisible(False) self.notesAction.setVisible(False) self.timeAction.setVisible(False) @@ -778,6 +781,11 @@ class ServiceManager(QtGui.QWidget): if serviceItem[u'service_item'].will_auto_start: self.autoStartAction.setText(translate('OpenLP.ServiceManager', '&Auto Start - active')) self.autoStartAction.setIcon(self.active) + if serviceItem[u'service_item'].is_text(): + for plugin in self.mainwindow.pluginManager.plugins: + if plugin.name == u'custom' and plugin.status == PluginStatus.Active: + self.create_custom_action.setVisible(True) + break self.themeMenu.menuAction().setVisible(False) # Set up the theme menu. if serviceItem[u'service_item'].is_text() and self.mainwindow.renderer.theme_level == ThemeLevel.Song: @@ -1317,6 +1325,13 @@ class ServiceManager(QtGui.QWidget): Receiver.send_message(u'%s_edit' % self.serviceItems[item][u'service_item'].name.lower(), u'L:%s' % self.serviceItems[item][u'service_item'].edit_id) + def create_custom(self): + """ + Saves the current text item as a custom slide + """ + item = self.findServiceItem()[0] + Receiver.send_message(u'custom_create_from_service', self.serviceItems[item][u'service_item']) + def findServiceItem(self): """ Finds the first selected ServiceItem in the list and returns the diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 04ec2ce97..dbe37321b 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -87,6 +87,8 @@ class CustomMediaItem(MediaManagerItem): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.config_updated) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'custom_create_from_service'), self.create_from_service_item) def config_updated(self): self.add_custom_from_service = Settings().value( @@ -275,9 +277,18 @@ class CustomMediaItem(MediaManagerItem): custom = self.plugin.manager.get_object_filtered(CustomSlide, CustomSlide.title == item.title) if custom: return + self.create_from_service_item(item) + + def create_from_service_item(self, item): + """ + Create a custom slide from a text service item + """ custom = CustomSlide() custom.title = item.title - custom.theme_name = item.theme + if item.theme: + custom.theme_name = item.theme + else: + custom.theme_name = u'' footer = u' '.join(item.raw_footer) if footer: if footer.startswith(item.title): @@ -292,7 +303,8 @@ class CustomMediaItem(MediaManagerItem): custom.text = unicode(custom_xml.extract_xml(), u'utf-8') self.plugin.manager.save_object(custom) self.onSearchTextButtonClicked() - Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) + if item.name.lower() == u'custom': + Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) def onClearTextButtonClick(self): """ From 35d4cb2590a365e71425522e492ace31251a9b4b Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Sun, 23 Dec 2012 19:56:19 +0000 Subject: [PATCH 3/6] Ability to editexisting customs in saved service --- openlp/plugins/custom/lib/mediaitem.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index dbe37321b..f69b11967 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -30,7 +30,7 @@ import logging from PyQt4 import QtCore, QtGui -from sqlalchemy.sql import or_, func +from sqlalchemy.sql import or_, func, and_ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, check_item_selected, translate, \ ServiceItemContext, PluginStatus @@ -270,14 +270,16 @@ class CustomMediaItem(MediaManagerItem): Triggered by a song being loaded by the service manager. """ log.debug(u'serviceLoad') - if not self.add_custom_from_service: - return if self.plugin.status != PluginStatus.Active: return - custom = self.plugin.manager.get_object_filtered(CustomSlide, CustomSlide.title == item.title) + custom = self.plugin.manager.get_object_filtered(CustomSlide, + and_(CustomSlide.title == item.title, CustomSlide.theme_name == item.theme, + CustomSlide.credits == item.raw_footer[0][len(item.title) + 1:])) if custom: - return - self.create_from_service_item(item) + Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) + else: + if self.add_custom_from_service: + self.create_from_service_item(item) def create_from_service_item(self, item): """ @@ -304,6 +306,7 @@ class CustomMediaItem(MediaManagerItem): self.plugin.manager.save_object(custom) self.onSearchTextButtonClicked() if item.name.lower() == u'custom': + self.plugin.serviceManager.replaceServiceItem(item) Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) def onClearTextButtonClick(self): From d1eca2d4c400a7b06168e94cc7e525ed838b79c8 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Fri, 28 Dec 2012 22:46:27 +0000 Subject: [PATCH 4/6] Missed a QVariant --- openlp/plugins/custom/lib/mediaitem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 72a002e69..58ccd8fb9 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -90,8 +90,7 @@ class CustomMediaItem(MediaManagerItem): QtCore.SIGNAL(u'custom_create_from_service'), self.create_from_service_item) def config_updated(self): - self.add_custom_from_service = Settings().value( - self.settingsSection + u'/add custom from service', QtCore.QVariant(u'True')).toBool() + self.add_custom_from_service = Settings().value(self.settingsSection + u'/add custom from service', True) def retranslateUi(self): self.searchTextLabel.setText(u'%s:' % UiStrings().Search) From 54b9dfc01c49b340b8cc5a1b2a4e14e1578cda77 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Fri, 28 Dec 2012 23:19:42 +0000 Subject: [PATCH 5/6] Remove .replaceServiceItem call which doesn't appear to do what I thought it did --- openlp/plugins/custom/lib/mediaitem.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 58ccd8fb9..b9805b409 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -301,7 +301,6 @@ class CustomMediaItem(MediaManagerItem): self.plugin.manager.save_object(custom) self.onSearchTextButtonClicked() if item.name.lower() == u'custom': - self.plugin.serviceManager.replaceServiceItem(item) Receiver.send_message(u'service_item_update', u'%s:%s:%s' % (custom.id, item._uuid, False)) def onClearTextButtonClick(self): From fee8ae78bbaaf880848c3fe2ca67ee64a71b550c Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Wed, 2 Jan 2013 12:26:21 +0100 Subject: [PATCH 6/6] Fix bug #1095268 - issue with QPyNullVariant. --- openlp/core/lib/__init__.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index dc4c5170e..d0a5e9880 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -141,10 +141,21 @@ class Settings(QtCore.QSettings): if defaultValue is None and not super(Settings, self).contains(key): return None setting = super(Settings, self).value(key, defaultValue) - # An empty list saved to the settings results in a None type being - # returned. + # On OS X (and probably on other platforms too) empty value from QSettings + # is represented as type PyQt4.QtCore.QPyNullVariant. This type has to be + # converted to proper 'None' Python type. + if isinstance(setting, QtCore.QPyNullVariant) and setting.isNull(): + setting = None + # Handle 'None' type (empty value) properly. if setting is None: - return [] + # An empty string saved to the settings results in a None type being + # returned. Convert it to empty unicode string. + if isinstance(defaultValue, unicode): + return u'' + # An empty list saved to the settings results in a None type being + # returned. + else: + return [] # Convert the setting to the correct type. if isinstance(defaultValue, bool): if isinstance(setting, bool):