This commit is contained in:
Tim Bentley 2013-01-02 22:05:54 +00:00
commit d6ad079a0b
7 changed files with 117 additions and 49 deletions

View File

@ -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):

View File

@ -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, Settings
translate, str_to_bool, check_directory_exists, Settings, PluginStatus
from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib.ui import UiStrings, critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
@ -252,6 +252,9 @@ 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)
@ -751,6 +754,7 @@ class ServiceManager(QtGui.QWidget):
pos = item.data(0, QtCore.Qt.UserRole)
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)
@ -770,6 +774,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:
@ -1306,6 +1315,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

View File

@ -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),
self.slideListView.item(count).text())

View File

@ -48,18 +48,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
@ -67,11 +74,21 @@ 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 = (check_state == QtCore.Qt.Checked)
def load(self):
self.displayFooter = Settings().value(
self.settingsSection + u'/display footer', True)
settings = Settings()
settings.beginGroup(self.settingsSection)
self.displayFooter = settings.value(u'display footer', True)
self.update_load = settings.value(u'add custom from service', True)
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',
self.displayFooter)
settings = Settings()
settings.beginGroup(self.settingsSection)
settings.setValue(u'display footer', self.displayFooter)
settings.setValue(u'add custom from service', self.update_load)
settings.endGroup()

View File

@ -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):
"""

View File

@ -30,13 +30,13 @@
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, Settings
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, check_item_selected, translate, \
ServiceItemContext, Settings, PluginStatus
from openlp.core.lib.ui import UiStrings
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__)
@ -85,6 +85,12 @@ 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)
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(self.settingsSection + u'/add custom from service', True)
def retranslateUi(self):
self.searchTextLabel.setText(u'%s:' % UiStrings().Search)
@ -102,6 +108,7 @@ class CustomMediaItem(MediaManagerItem):
CustomSlide, order_by_ref=CustomSlide.title))
self.searchTextEdit.setCurrentSearchType(Settings().value(
u'%s/last search type' % self.settingsSection, CustomSearch.Titles))
self.config_updated()
def loadList(self, custom_slides):
# Sort out what custom we want to select after loading the list.
@ -198,6 +205,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
@ -252,6 +260,49 @@ 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 self.plugin.status != PluginStatus.Active:
return
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:
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):
"""
Create a custom slide from a text service item
"""
custom = CustomSlide()
custom.title = item.title
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):
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()
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):
"""
Clear the search text.

View File

@ -93,6 +93,12 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
self.verseNumberBox.value())
def onVerseTypeComboBoxChanged(self):
self.updateSuggestedVerseNumber()
def onCursorPositionChanged(self):
self.updateSuggestedVerseNumber()
def updateSuggestedVerseNumber(self):
"""
Adjusts the verse number SpinBox in regard to the selected verse type
and the cursor's position.
@ -116,43 +122,10 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
if match:
verse_tag = match.group(1)
try:
verse_num = int(match.group(2))
verse_num = int(match.group(2)) + 1
except ValueError:
verse_num = 1
if VerseType.from_loose_input(verse_tag, False):
self.verseNumberBox.setValue(verse_num)
def onCursorPositionChanged(self):
"""
Determines the previous verse type and number in regard to the cursor's
position and adjusts the ComboBox and SpinBox to these values.
"""
position = self.verseTextEdit.textCursor().position()
text = self.verseTextEdit.toPlainText()
if not text:
return
if text.rfind(u'[', 0, position) > text.rfind(u']', 0, position) and \
text.find(u']', position) < text.find(u'[', position):
return
position = text.rfind(u'---[', 0, position)
if position == -1:
return
text = text[position:]
position = text.find(u']---')
if position == -1:
return
text = text[:position + 4]
match = VERSE_REGEX.match(text)
if match:
verse_type = match.group(1)
verse_type_index = VerseType.from_loose_input(verse_type, None)
try:
verse_number = int(match.group(2))
except ValueError:
verse_number = 1
if verse_type_index is not None:
self.verseTypeComboBox.setCurrentIndex(verse_type_index)
self.verseNumberBox.setValue(verse_number)
self.verseNumberBox.setValue(verse_num)
def setVerse(self, text, single=False,
tag=u'%s1' % VerseType.Tags[VerseType.Verse]):