This commit is contained in:
Jonathan Corwin 2010-09-03 21:10:05 +01:00
commit b2563f0ce0
10 changed files with 453 additions and 134 deletions

View File

@ -47,26 +47,13 @@ class Renderer(object):
Initialise the renderer. Initialise the renderer.
""" """
self._rect = None self._rect = None
self._debug = False
self._display_shadow_size_footer = 0
self._display_outline_size_footer = 0
self.theme_name = None self.theme_name = None
self._theme = None self._theme = None
self._bg_image_filename = None self._bg_image_filename = None
self.frame = None self.frame = None
self.frame_opaque = None
self.bg_frame = None self.bg_frame = None
self.bg_image = None self.bg_image = None
def set_debug(self, debug):
"""
Set the debug mode of the renderer.
``debug``
The debug mode.
"""
self._debug = debug
def set_theme(self, theme): def set_theme(self, theme):
""" """
Set the theme to be used. Set the theme to be used.
@ -159,7 +146,7 @@ class Renderer(object):
doc = QtGui.QTextDocument() doc = QtGui.QTextDocument()
doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height())) doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height()))
df = doc.defaultFont() df = doc.defaultFont()
df.setPixelSize(self._theme.font_main_proportion) df.setPointSize(self._theme.font_main_proportion)
df.setFamily(self._theme.font_main_name) df.setFamily(self._theme.font_main_name)
main_weight = 50 main_weight = 50
if self._theme.font_main_weight == u'Bold': if self._theme.font_main_weight == u'Bold':
@ -188,7 +175,7 @@ class Renderer(object):
# Text too long so gone to next mage # Text too long so gone to next mage
if layout.pageCount() != 1: if layout.pageCount() != 1:
formatted.append(shell % old_html_text) formatted.append(shell % old_html_text)
temp_text = line temp_text = line + line_end
old_html_text = temp_text old_html_text = temp_text
formatted.append(shell % old_html_text) formatted.append(shell % old_html_text)
log.debug(u'format_slide - End') log.debug(u'format_slide - End')

View File

@ -93,6 +93,7 @@ class RenderManager(object):
""" """
self.global_theme = global_theme self.global_theme = global_theme
self.theme_level = theme_level self.theme_level = theme_level
self.themedata = None
def set_service_theme(self, service_theme): def set_service_theme(self, service_theme):
""" """
@ -102,6 +103,7 @@ class RenderManager(object):
The service-level theme to be set. The service-level theme to be set.
""" """
self.service_theme = service_theme self.service_theme = service_theme
self.themedata = None
def set_override_theme(self, theme, overrideLevels=False): def set_override_theme(self, theme, overrideLevels=False):
""" """
@ -111,6 +113,10 @@ class RenderManager(object):
``theme`` ``theme``
The name of the song-level theme. None means the service The name of the song-level theme. None means the service
item wants to use the given value. item wants to use the given value.
``overrideLevels``
Used to force the theme data passed in to be used.
""" """
log.debug(u'set override theme to %s', theme) log.debug(u'set override theme to %s', theme)
theme_level = self.theme_level theme_level = self.theme_level
@ -137,6 +143,7 @@ class RenderManager(object):
if self.theme != self.renderer.theme_name or self.themedata is None \ if self.theme != self.renderer.theme_name or self.themedata is None \
or overrideLevels: or overrideLevels:
log.debug(u'theme is now %s', self.theme) log.debug(u'theme is now %s', self.theme)
# Force the theme to be the one passed in.
if overrideLevels: if overrideLevels:
self.themedata = theme self.themedata = theme
else: else:

View File

@ -322,9 +322,6 @@ class MainDisplay(DisplayWidget):
# Make display show up if in single screen mode # Make display show up if in single screen mode
if self.isLive: if self.isLive:
self.setVisible(True) self.setVisible(True)
# save preview for debugging
if log.isEnabledFor(logging.DEBUG):
preview.save(u'temp.png', u'png')
return preview return preview
def buildHtml(self, serviceItem): def buildHtml(self, serviceItem):

View File

@ -574,7 +574,7 @@ class ServiceManager(QtGui.QWidget):
* An osd which is a pickle of the service items * An osd which is a pickle of the service items
* All image, presentation and video files needed to run the service. * All image, presentation and video files needed to run the service.
""" """
log.debug(u'onSaveService') log.debug(u'onSaveService %s' % quick)
if not quick or self.isNew: if not quick or self.isNew:
filename = QtGui.QFileDialog.getSaveFileName(self, filename = QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.ServiceManager', 'Save Service'), translate('OpenLP.ServiceManager', 'Save Service'),
@ -755,6 +755,7 @@ class ServiceManager(QtGui.QWidget):
""" """
Set the theme for the current service Set the theme for the current service
""" """
log.debug(u'onThemeComboBoxSelected')
self.service_theme = unicode(self.themeComboBox.currentText()) self.service_theme = unicode(self.themeComboBox.currentText())
self.parent.RenderManager.set_service_theme(self.service_theme) self.parent.RenderManager.set_service_theme(self.service_theme)
QtCore.QSettings().setValue( QtCore.QSettings().setValue(
@ -767,6 +768,7 @@ class ServiceManager(QtGui.QWidget):
The theme may have changed in the settings dialog so make The theme may have changed in the settings dialog so make
sure the theme combo box is in the correct state. sure the theme combo box is in the correct state.
""" """
log.debug(u'themeChange')
if self.parent.RenderManager.theme_level == ThemeLevel.Global: if self.parent.RenderManager.theme_level == ThemeLevel.Global:
self.toolbar.actions[u'ThemeLabel'].setVisible(False) self.toolbar.actions[u'ThemeLabel'].setVisible(False)
self.toolbar.actions[u'ThemeWidget'].setVisible(False) self.toolbar.actions[u'ThemeWidget'].setVisible(False)
@ -779,6 +781,7 @@ class ServiceManager(QtGui.QWidget):
Rebuild the service list as things have changed and a Rebuild the service list as things have changed and a
repaint is the easiest way to do this. repaint is the easiest way to do this.
""" """
log.debug(u'regenerateServiceItems')
# force reset of renderer as theme data has changed # force reset of renderer as theme data has changed
self.parent.RenderManager.themedata = None self.parent.RenderManager.themedata = None
if self.serviceItems: if self.serviceItems:
@ -800,6 +803,7 @@ class ServiceManager(QtGui.QWidget):
``item`` ``item``
Service Item to be added Service Item to be added
""" """
log.debug(u'addServiceItem')
sitem = self.findServiceItem()[0] sitem = self.findServiceItem()[0]
item.render() item.render()
if replace: if replace:

View File

@ -51,9 +51,9 @@ class CSVBible(BibleDB):
if u'booksfile' not in kwargs: if u'booksfile' not in kwargs:
raise KeyError(u'You have to supply a file to import books from.') raise KeyError(u'You have to supply a file to import books from.')
self.booksfile = kwargs[u'booksfile'] self.booksfile = kwargs[u'booksfile']
if u'versesfile' not in kwargs: if u'versefile' not in kwargs:
raise KeyError(u'You have to supply a file to import verses from.') raise KeyError(u'You have to supply a file to import verses from.')
self.versesfile = kwargs[u'versesfile'] self.versesfile = kwargs[u'versefile']
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import) QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import)

View File

@ -47,7 +47,6 @@ class BibleListView(BaseListWithDnD):
self.parent().onListViewResize(event.size().width(), self.parent().onListViewResize(event.size().width(),
event.size().width()) event.size().width())
class BibleMediaItem(MediaManagerItem): class BibleMediaItem(MediaManagerItem):
""" """
This is the custom media manager item for Bibles. This is the custom media manager item for Bibles.
@ -466,19 +465,27 @@ class BibleMediaItem(MediaManagerItem):
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None):
""" """
Generates and formats the slides for the service item. Generates and formats the slides for the service item as well as the
service item's title.
""" """
log.debug(u'generating slide data') log.debug(u'generating slide data')
items = self.listView.selectedIndexes() items = self.listView.selectedIndexes()
if len(items) == 0: if len(items) == 0:
return False return False
has_dual_bible = False
bible_text = u'' bible_text = u''
old_chapter = u'' old_chapter = u''
raw_footer = [] raw_footer = []
raw_slides = [] raw_slides = []
service_item.add_capability(ItemCapabilities.AllowsPreview) for item in items:
service_item.add_capability(ItemCapabilities.AllowsLoop) bitem = self.listView.item(item.row())
service_item.add_capability(ItemCapabilities.AllowsAdditions) reference = bitem.data(QtCore.Qt.UserRole)
if isinstance(reference, QtCore.QVariant):
reference = reference.toPyObject()
dual_bible = self._decodeQtObject(reference, 'dual_bible')
if dual_bible:
has_dual_bible = True
break
# Let's loop through the main lot, and assemble our verses. # Let's loop through the main lot, and assemble our verses.
for item in items: for item in items:
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
@ -491,7 +498,7 @@ class BibleMediaItem(MediaManagerItem):
bible = self._decodeQtObject(reference, 'bible') bible = self._decodeQtObject(reference, 'bible')
version = self._decodeQtObject(reference, 'version') version = self._decodeQtObject(reference, 'version')
copyright = self._decodeQtObject(reference, 'copyright') copyright = self._decodeQtObject(reference, 'copyright')
#permission = self._decodeQtObject(reference, 'permission') permission = self._decodeQtObject(reference, 'permission')
text = self._decodeQtObject(reference, 'text') text = self._decodeQtObject(reference, 'text')
dual_bible = self._decodeQtObject(reference, 'dual_bible') dual_bible = self._decodeQtObject(reference, 'dual_bible')
if dual_bible: if dual_bible:
@ -499,70 +506,57 @@ class BibleMediaItem(MediaManagerItem):
'dual_version') 'dual_version')
dual_copyright = self._decodeQtObject(reference, dual_copyright = self._decodeQtObject(reference,
'dual_copyright') 'dual_copyright')
#dual_permission = self._decodeQtObject(reference, dual_permission = self._decodeQtObject(reference,
# 'dual_permission') 'dual_permission')
dual_text = self._decodeQtObject(reference, 'dual_text') dual_text = self._decodeQtObject(reference, 'dual_text')
if self.parent.settings_tab.display_style == 1: verse_text = self.formatVerse(old_chapter, chapter, verse)
verse_text = self.formatVerse(old_chapter, chapter, verse, footer = u'%s (%s %s %s)' % (book, version, copyright, permission)
u'{su}(', u'){/su}')
elif self.parent.settings_tab.display_style == 2:
verse_text = self.formatVerse(old_chapter, chapter, verse,
u'{su}{', u'}{/su}')
elif self.parent.settings_tab.display_style == 3:
verse_text = self.formatVerse(old_chapter, chapter, verse,
u'{su}[', u']{/su}')
else:
verse_text = self.formatVerse(old_chapter, chapter, verse,
u'{su}', u'{/su}')
old_chapter = chapter
footer = u'%s (%s %s)' % (book, version, copyright)
# If not found add to footer
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
if dual_bible: if has_dual_bible:
footer = u'%s (%s %s)' % (book, dual_version, if dual_bible:
dual_copyright) footer = u'%s (%s %s %s)' % (book, dual_version,
# If not found add second version and copyright to footer. dual_copyright, dual_permission)
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
bible_text = u'%s %s \n\n %s %s' % (verse_text, text, # If there is an old bible_text we have to add it.
verse_text, dual_text) if bible_text:
raw_slides.append(bible_text)
bible_text = u''
else:
# If we are 'Verse Per Line' then force a new line.
if self.parent.settings_tab.layout_style == 1:
text = text + u'\n'
else:
# split the line but do not replace line breaks in renderer
service_item.add_capability(ItemCapabilities.NoLineBreaks)
text = text + u'\n'
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
# If we are 'Verse Per Slide' then create a new slide.
if self.parent.settings_tab.layout_style == 0:
raw_slides.append(bible_text)
bible_text = u''
# If we are not 'Verse Per Slide' we have to make sure, that we
# add more verses.
else:
if item.row() < len(items) - 1:
bitem = items[item.row() + 1]
reference = bitem.data(QtCore.Qt.UserRole)
if isinstance(reference, QtCore.QVariant):
reference = reference.toPyObject()
bible_new = self._decodeQtObject(reference, 'bible')
dual_bible_new = self._decodeQtObject(reference,
'dual_bible')
if dual_bible_new:
raw_slides.append(bible_text)
bible_text = u''
elif bible != bible_new:
raw_slides.append(bible_text)
bible_text = u''
else:
raw_slides.append(bible_text) raw_slides.append(bible_text)
bible_text = u'' bible_text = u''
# service item title bible_text = u'%s %s\n\n%s %s' % (verse_text, text,
verse_text, dual_text)
raw_slides.append(bible_text)
bible_text = u''
elif self.parent.settings_tab.layout_style == 0:
bible_text = u'%s %s' % (verse_text, text)
raw_slides.append(bible_text)
bible_text = u''
else:
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
# If we are 'Verse Per Slide' then create a new slide.
elif self.parent.settings_tab.layout_style == 0:
bible_text = u'%s %s' % (verse_text, text)
raw_slides.append(bible_text)
bible_text = u''
# If we are 'Verse Per Line' then force a new line.
elif self.parent.settings_tab.layout_style == 1:
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
# We have to be 'Continuous'.
else:
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
old_chapter = chapter
# If there are no more items we check whether we have to add bible_text.
if bible_text:
raw_slides.append(bible_text)
bible_text = u''
# Service Item: Capabilities
if self.parent.settings_tab.layout_style == 2 and not has_dual_bible:
# split the line but do not replace line breaks in renderer
service_item.add_capability(ItemCapabilities.NoLineBreaks)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
service_item.add_capability(ItemCapabilities.AllowsAdditions)
# Service Item: Title
if not service_item.title: if not service_item.title:
if dual_bible: if dual_bible:
service_item.title = u'%s (%s, %s) %s' % (book, version, service_item.title = u'%s (%s, %s) %s' % (book, version,
@ -573,7 +567,7 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'etc')) == -1: translate('BiblesPlugin.MediaItem', 'etc')) == -1:
service_item.title = u'%s, %s' % (service_item.title, service_item.title = u'%s, %s' % (service_item.title,
translate('BiblesPlugin.MediaItem', 'etc')) translate('BiblesPlugin.MediaItem', 'etc'))
# item theme # Service Item: Theme
if len(self.parent.settings_tab.bible_theme) == 0: if len(self.parent.settings_tab.bible_theme) == 0:
service_item.theme = None service_item.theme = None
else: else:
@ -587,14 +581,20 @@ class BibleMediaItem(MediaManagerItem):
service_item.raw_footer = raw_footer service_item.raw_footer = raw_footer
return True return True
def formatVerse(self, old_chapter, chapter, verse, opening, closing): def formatVerse(self, old_chapter, chapter, verse):
verse_text = opening if not self.parent.settings_tab.show_new_chapters or \
if old_chapter != chapter: old_chapter != chapter:
verse_text += chapter + u':' verse_text = chapter + u':' + verse
elif not self.parent.settings_tab.show_new_chapters: else:
verse_text += chapter + u':' verse_text = verse
verse_text += verse if self.parent.settings_tab.display_style == 1:
verse_text += closing verse_text = u'{su}(' + verse_text + u'){/su}'
elif self.parent.settings_tab.display_style == 2:
verse_text = u'{su}{' + verse_text + u'}{/su}'
elif self.parent.settings_tab.display_style == 3:
verse_text = u'{su}[' + verse_text + u']{/su}'
else:
verse_text = u'{su}' + verse_text + u'{/su}'
return verse_text return verse_text
def reloadBibles(self): def reloadBibles(self):
@ -639,14 +639,14 @@ class BibleMediaItem(MediaManagerItem):
for i in range(int(range_from), int(range_to) + 1): for i in range(int(range_from), int(range_to) + 1):
combo.addItem(unicode(i)) combo.addItem(unicode(i))
def displayResults(self, bible, dual_bible=None): def displayResults(self, bible, dual_bible=u''):
""" """
Displays the search results in the media manager. All data needed for Displays the search results in the media manager. All data needed for
further action is saved for/in each row. further action is saved for/in each row.
""" """
version = self.parent.manager.get_meta_data(bible, u'Version') version = self.parent.manager.get_meta_data(bible, u'Version')
copyright = self.parent.manager.get_meta_data(bible, u'Copyright') copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
#permission = self.parent.manager.get_meta_data(bible, u'Permissions') permission = self.parent.manager.get_meta_data(bible, u'Permissions')
if dual_bible: if dual_bible:
dual_version = self.parent.manager.get_meta_data(dual_bible, dual_version = self.parent.manager.get_meta_data(dual_bible,
u'Version') u'Version')
@ -654,43 +654,41 @@ class BibleMediaItem(MediaManagerItem):
u'Copyright') u'Copyright')
dual_permission = self.parent.manager.get_meta_data(dual_bible, dual_permission = self.parent.manager.get_meta_data(dual_bible,
u'Permissions') u'Permissions')
if dual_permission: if not dual_permission:
dual_permission = dual_permission.value
else:
dual_permission = u'' dual_permission = u''
# We count the number of rows which are maybe already present. # We count the number of rows which are maybe already present.
start_count = self.listView.count() start_count = self.listView.count()
for count, verse in enumerate(self.search_results): for count, verse in enumerate(self.search_results):
if dual_bible: if dual_bible:
vdict = { vdict = {
'book':QtCore.QVariant(verse.book.name), 'book': QtCore.QVariant(verse.book.name),
'chapter':QtCore.QVariant(verse.chapter), 'chapter': QtCore.QVariant(verse.chapter),
'verse':QtCore.QVariant(verse.verse), 'verse': QtCore.QVariant(verse.verse),
'bible':QtCore.QVariant(bible), 'bible': QtCore.QVariant(bible),
'version':QtCore.QVariant(version.value), 'version': QtCore.QVariant(version.value),
'copyright':QtCore.QVariant(copyright.value), 'copyright': QtCore.QVariant(copyright.value),
#'permission':QtCore.QVariant(permission.value), 'permission': QtCore.QVariant(permission.value),
'text':QtCore.QVariant(verse.text), 'text': QtCore.QVariant(verse.text),
'dual_bible':QtCore.QVariant(dual_bible), 'dual_bible': QtCore.QVariant(dual_bible),
'dual_version':QtCore.QVariant(dual_version.value), 'dual_version': QtCore.QVariant(dual_version.value),
'dual_copyright':QtCore.QVariant(dual_copyright.value), 'dual_copyright': QtCore.QVariant(dual_copyright.value),
#'dual_permission':QtCore.QVariant(dual_permission), 'dual_permission': QtCore.QVariant(dual_permission.value),
'dual_text':QtCore.QVariant( 'dual_text': QtCore.QVariant(
self.dual_search_results[count].text) self.dual_search_results[count].text)
} }
bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name,
verse.chapter, verse.verse, version.value, dual_version.value) verse.chapter, verse.verse, version.value, dual_version.value)
else: else:
vdict = { vdict = {
'book':QtCore.QVariant(verse.book.name), 'book': QtCore.QVariant(verse.book.name),
'chapter':QtCore.QVariant(verse.chapter), 'chapter': QtCore.QVariant(verse.chapter),
'verse':QtCore.QVariant(verse.verse), 'verse': QtCore.QVariant(verse.verse),
'bible':QtCore.QVariant(bible), 'bible': QtCore.QVariant(bible),
'version':QtCore.QVariant(version.value), 'version': QtCore.QVariant(version.value),
'copyright':QtCore.QVariant(copyright.value), 'copyright': QtCore.QVariant(copyright.value),
#'permission':QtCore.QVariant(permission.value), 'permission': QtCore.QVariant(permission.value),
'text':QtCore.QVariant(verse.text), 'text': QtCore.QVariant(verse.text),
'dual_bible':QtCore.QVariant(dual_bible) 'dual_bible': QtCore.QVariant(dual_bible)
} }
bible_text = u' %s %d:%d (%s)' % (verse.book.name, bible_text = u' %s %d:%d (%s)' % (verse.book.name,
verse.chapter, verse.verse, version.value) verse.chapter, verse.verse, version.value)

View File

@ -83,6 +83,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton, QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onWordsOfWorshipRemoveButtonClicked) self.onWordsOfWorshipRemoveButtonClicked)
QtCore.QObject.connect(self.ccliAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onCCLIAddButtonClicked)
QtCore.QObject.connect(self.ccliRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onCCLIRemoveButtonClicked)
QtCore.QObject.connect(self.songsOfFellowshipAddButton, QtCore.QObject.connect(self.songsOfFellowshipAddButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onSongsOfFellowshipAddButtonClicked) self.onSongsOfFellowshipAddButtonClicked)
@ -277,6 +283,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
def onWordsOfWorshipRemoveButtonClicked(self): def onWordsOfWorshipRemoveButtonClicked(self):
self.removeSelectedItems(self.wordsOfWorshipFileListWidget) self.removeSelectedItems(self.wordsOfWorshipFileListWidget)
def onCCLIAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select CCLI Files'),
self.ccliFileListWidget
)
def onCCLIRemoveButtonClicked(self):
self.removeSelectedItems(self.ccliFileListWidget)
def onSongsOfFellowshipAddButtonClicked(self): def onSongsOfFellowshipAddButtonClicked(self):
self.getFiles( self.getFiles(
translate('SongsPlugin.ImportWizardForm', translate('SongsPlugin.ImportWizardForm',

View File

@ -0,0 +1,310 @@
# -*- 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, Derek Scotney #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
import logging
import os
import chardet
import codecs
from songimport import SongImport
log = logging.getLogger(__name__)
class CCLIFileImportError(Exception):
pass
class CCLIFileImport(SongImport):
"""
The :class:`CCLIFileImport` class provides OpenLP with the
ability to import CCLI SongSelect song files in both .txt and
.usr formats. See http://www.ccli.com
"""
def __init__(self, manager, **kwargs):
"""
Initialise the import.
``manager``
The song manager for the running OpenLP installation.
``filenames``
The files to be imported.
"""
SongImport.__init__(self, manager)
if u'filenames' in kwargs:
self.filenames = kwargs[u'filenames']
log.debug(self.filenames)
else:
raise KeyError(u'Keyword argument "filenames" not supplied.')
def do_import(self):
"""
Import either a .usr or a .txt SongSelect file
"""
log.debug(u'Starting CCLI File Import')
song_total = len(self.filenames)
self.import_wizard.importProgressBar.setMaximum(song_total)
song_count = 1
for filename in self.filenames:
self.import_wizard.incrementProgressBar(
u'Importing song %s of %s' % (song_count, song_total))
filename = unicode(filename)
log.debug(u'Importing CCLI File: %s', filename)
lines = []
if os.path.isfile(filename):
detect_file = open(filename, u'r')
details = chardet.detect(detect_file.read(2048))
detect_file.close()
infile = codecs.open(filename, u'r', details['encoding'])
lines = infile.readlines()
ext = os.path.splitext(filename)[1]
if ext.lower() == ".usr":
log.info(u'SongSelect .usr format file found %s: ' , filename)
self.do_import_usr_file(lines)
elif ext.lower() == ".txt":
log.info(u'SongSelect .txt format file found %s: ', filename)
self.do_import_txt_file(lines)
else:
log.info(u'Extension %s is not valid', filename)
pass
song_count += 1
if self.stop_import_flag:
return False
return True
def do_import_usr_file(self, textList):
"""
The :method:`do_import_usr_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*USR* file format
``textList``
An array of strings containing the usr file content.
**SongSelect .usr file format**
``[File]``
USR file format first line
``Type=``
Indicates the file type
e.g. *Type=SongSelect Import File*
``Version=3.0``
File format version
``[S A2672885]``
Contains the CCLI Song number e.g. *2672885*
``Title=``
Contains the song title (e.g. *Title=Above All*)
``Author=``
Contains a | delimited list of the song authors
e.g. *Author=LeBlanc, Lenny | Baloche, Paul*
``Copyright=``
Contains a | delimited list of the song copyrights
e.g. Copyright=1999 Integrity's Hosanna! Music |
LenSongs Publishing (Verwaltet von Gerth Medien
Musikverlag)
``Admin=``
Contains the song administrator
e.g. *Admin=Gerth Medien Musikverlag*
``Themes=``
Contains a /t delimited list of the song themes
e.g. *Themes=Cross/tKingship/tMajesty/tRedeemer*
``Keys=``
Contains the keys in which the music is played??
e.g. *Keys=A*
``Fields=``
Contains a list of the songs fields in order /t delimited
e.g. *Fields=Vers 1/tVers 2/tChorus 1/tAndere 1*
``Words=``
Contains the songs various lyrics in order as shown by the
*Fields* description
e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF]
"""
log.debug(u'USR file text: %s', textList)
lyrics = []
self.set_defaults()
for line in textList:
if line.startswith(u'Title='):
song_name = line[6:].strip()
elif line.startswith(u'Author='):
song_author = line[7:].strip()
elif line.startswith(u'Copyright='):
song_copyright = line[10:].strip()
elif line.startswith(u'[S A'):
song_ccli = line[4:-3].strip()
elif line.startswith(u'Fields='):
#Fields contain single line indicating verse, chorus, etc,
#/t delimited, same as with words field. store seperately
#and process at end.
song_fields = line[7:].strip()
elif line.startswith(u'Words='):
song_words = line[6:].strip()
#Unhandled usr keywords:Type,Version,Admin,Themes,Keys
#Process Fields and words sections
field_list = song_fields.split(u'/t')
words_list = song_words.split(u'/t')
for counter in range(0, len(field_list)):
if field_list[counter].startswith(u'Ver'):
verse_type = u'V'
elif field_list[counter].startswith(u'Ch'):
verse_type = u'C'
elif field_list[counter].startswith(u'Br'):
verse_type = u'B'
else: #Other
verse_type = u'O'
verse_text = unicode(words_list[counter])
verse_text = verse_text.replace("/n", "\n")
if len(verse_text) > 0:
self.add_verse(verse_text, verse_type);
#Handle multiple authors
author_list = song_author.split(u'/')
if len(author_list) < 2:
author_list = song_author.split(u'|')
for author in author_list:
seperated = author.split(u',')
self.add_author(seperated[1].strip() + " " + seperated[0].strip())
self.title = song_name
self.copyright = song_copyright
self.ccli_number = song_ccli
self.finish()
def do_import_txt_file(self, textList):
"""
The :method:`do_import_txt_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*TXT* file format
``textList``
An array of strings containing the txt file content.
**SongSelect .txt file format**
``Song Title``
Contains the song title
<Empty line>
``Title of following verse/chorus and number``
e.g. Verse 1, Chorus 1
``Verse/Chorus lyrics``
<Empty line>
<Empty line>
``Title of next verse/chorus (repeats)``
``Verse/Chorus lyrics``
<Empty line>
<Empty line>
``Song CCLI Number``
e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
``Song Copyright``
e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
``Song Authors``
e.g. Lenny LeBlanc | Paul Baloche
``Licencing info``
e.g. For use solely with the SongSelect Terms of Use.
All rights Reserved. www.ccli.com
``CCLI Licence number of user``
e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14
"""
log.debug(u'TXT file text: %s', textList)
self.set_defaults()
line_number = 0
verse_text = u''
song_comments = u''
song_copyright = u'';
verse_start = False
for line in textList:
clean_line = line.strip()
if not clean_line:
if line_number==0:
continue
elif verse_start:
if verse_text:
self.add_verse(verse_text, verse_type)
verse_text = ''
verse_start = False
else:
#line_number=0, song title
if line_number==0:
song_name = clean_line
line_number += 1
#line_number=1, verses
elif line_number==1:
#line_number=1, ccli number, first line after verses
if clean_line.startswith(u'CCLI'):
line_number += 1
ccli_parts = clean_line.split(' ')
song_ccli = ccli_parts[len(ccli_parts)-1]
elif not verse_start:
# We have the verse descriptor
verse_desc_parts = clean_line.split(' ')
if len(verse_desc_parts) == 2:
if verse_desc_parts[0].startswith(u'Ver'):
verse_type = u'V'
elif verse_desc_parts[0].startswith(u'Ch'):
verse_type = u'C'
elif verse_desc_parts[0].startswith(u'Br'):
verse_type = u'B'
else:
verse_type = u'O'
verse_number = verse_desc_parts[1]
else:
verse_type = u'O'
verse_number = 1
verse_start = True
else:
# We have verse content or the start of the
# last part. Add l so as to keep the CRLF
verse_text = verse_text + line
else:
#line_number=2, copyright
if line_number==2:
line_number += 1
song_copyright = clean_line
#n=3, authors
elif line_number==3:
line_number += 1
song_author = clean_line
#line_number=4, comments lines before last line
elif (line_number==4) and (not clean_line.startswith(u'CCL')):
song_comments = song_comments + clean_line
# split on known separators
author_list = song_author.split(u'/')
if len(author_list) < 2:
author_list = song_author.split(u'|')
#Clean spaces before and after author names
for author_name in author_list:
self.add_author(author_name.strip())
self.title = song_name
self.copyright = song_copyright
self.ccli_number = song_ccli
self.comments = song_comments
self.finish()

View File

@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport
try: try:
from sofimport import SofImport from sofimport import SofImport
from oooimport import OooImport from oooimport import OooImport
from cclifileimport import CCLIFileImport
from wowimport import WowImport from wowimport import WowImport
except ImportError: except ImportError:
pass pass
@ -68,6 +69,8 @@ class SongFormat(object):
return WowImport return WowImport
elif format == SongFormat.Generic: elif format == SongFormat.Generic:
return OooImport return OooImport
elif format == SongFormat.CCLI:
return CCLIFileImport
# else: # else:
return None return None

View File

@ -43,12 +43,6 @@ class SongImport(QtCore.QObject):
whether the authors etc already exist and add them or refer to them whether the authors etc already exist and add them or refer to them
as necessary as necessary
""" """
COPYRIGHT_STRING = unicode(translate(
'SongsPlugin.SongImport', 'copyright'))
COPYRIGHT_SYMBOL = unicode(translate(
'SongsPlugin.SongImport', '\xa9'))
def __init__(self, manager): def __init__(self, manager):
""" """
Initialise and create defaults for properties Initialise and create defaults for properties
@ -58,11 +52,11 @@ class SongImport(QtCore.QObject):
""" """
self.manager = manager self.manager = manager
self.stop_import_flag = False self.stop_import_flag = False
self.set_defaults()
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
self.setDefaults()
def set_defaults(self):
def setDefaults(self):
self.title = u'' self.title = u''
self.song_number = u'' self.song_number = u''
self.alternate_title = u'' self.alternate_title = u''
@ -78,6 +72,10 @@ class SongImport(QtCore.QObject):
self.verses = [] self.verses = []
self.versecount = 0 self.versecount = 0
self.choruscount = 0 self.choruscount = 0
self.copyright_string = unicode(translate(
'SongsPlugin.SongImport', 'copyright'))
self.copyright_symbol = unicode(translate(
'SongsPlugin.SongImport', '\xa9'))
def stop_import(self): def stop_import(self):
""" """
@ -163,8 +161,7 @@ class SongImport(QtCore.QObject):
def parse_author(self, text): def parse_author(self, text):
""" """
Add the author. OpenLP stores them individually so split by 'and', '&' Add the author. OpenLP stores them individually so split by 'and', '&'
and comma. and comma. However need to check for 'Mr and Mrs Smith' and turn it to
However need to check for 'Mr and Mrs Smith' and turn it to
'Mr Smith' and 'Mrs Smith'. 'Mr Smith' and 'Mrs Smith'.
""" """
for author in text.split(u','): for author in text.split(u','):
@ -241,7 +238,7 @@ class SongImport(QtCore.QObject):
""" """
All fields have been set to this song. Write it away All fields have been set to this song. Write it away
""" """
if len(self.authors) == 0: if not self.authors:
self.authors.append(u'Author unknown') self.authors.append(u'Author unknown')
self.commit_song() self.commit_song()