This commit is contained in:
Tim Bentley 2011-03-20 18:43:51 +00:00
commit 63309d4f1a
12 changed files with 135 additions and 62 deletions

View File

@ -4,6 +4,7 @@ recursive-include openlp *.csv
recursive-include openlp *.html recursive-include openlp *.html
recursive-include openlp *.js recursive-include openlp *.js
recursive-include openlp *.css recursive-include openlp *.css
recursive-include openlp *.png
recursive-include documentation * recursive-include documentation *
recursive-include resources * recursive-include resources *
recursive-include scripts * recursive-include scripts *

View File

@ -184,8 +184,9 @@ class ServiceItem(object):
else: else:
log.error(u'Invalid value renderer :%s' % self.service_item_type) log.error(u'Invalid value renderer :%s' % self.service_item_type)
self.title = clean_tags(self.title) self.title = clean_tags(self.title)
# The footer should never be None, but to be compatible with older # The footer should never be None, but to be compatible with a few
# release of OpenLP, we have to correct this to avoid tracebacks. # nightly builds between 1.9.4 and 1.9.5, we have to correct this to
# avoid tracebacks.
if self.raw_footer is None: if self.raw_footer is None:
self.raw_footer = [] self.raw_footer = []
self.foot_text = \ self.foot_text = \

View File

@ -110,7 +110,7 @@ class MainDisplay(DisplayWidget):
Phonon.createPath(self.mediaObject, self.audio) Phonon.createPath(self.mediaObject, self.audio)
QtCore.QObject.connect(self.mediaObject, QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'), QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart) self.videoState)
QtCore.QObject.connect(self.mediaObject, QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'finished()'), QtCore.SIGNAL(u'finished()'),
self.videoFinished) self.videoFinished)
@ -378,11 +378,13 @@ class MainDisplay(DisplayWidget):
Receiver.send_message(u'maindisplay_active') Receiver.send_message(u'maindisplay_active')
return self.preview() return self.preview()
def videoStart(self, newState, oldState): def videoState(self, newState, oldState):
""" """
Start the video at a predetermined point. Start the video at a predetermined point.
""" """
if newState == Phonon.PlayingState: if newState == Phonon.PlayingState \
and oldState != Phonon.PausedState \
and self.serviceItem.start_time > 0:
# set start time in milliseconds # set start time in milliseconds
self.mediaObject.seek(self.serviceItem.start_time * 1000) self.mediaObject.seek(self.serviceItem.start_time * 1000)

View File

@ -46,7 +46,6 @@ class SlideList(QtGui.QTableWidget):
QtGui.QTableWidget.__init__(self, parent.controller) QtGui.QTableWidget.__init__(self, parent.controller)
self.parent = parent self.parent = parent
class SlideController(QtGui.QWidget): class SlideController(QtGui.QWidget):
""" """
SlideController is the slide controller widget. This widget is what the SlideController is the slide controller widget. This widget is what the
@ -858,6 +857,7 @@ class SlideController(QtGui.QWidget):
self.serviceItem.bg_image_bytes = None self.serviceItem.bg_image_bytes = None
self.slidePreview.setPixmap(QtGui.QPixmap.fromImage(frame)) self.slidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
self.selectedRow = row self.selectedRow = row
self.__checkUpdateSelectedSlide(row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row) row)

View File

@ -424,12 +424,12 @@ class ThemeManager(QtGui.QWidget):
unicode(translate('OpenLP.ThemeManager', unicode(translate('OpenLP.ThemeManager',
'OpenLP Themes (*.theme *.otz)'))) 'OpenLP Themes (*.theme *.otz)')))
log.info(u'New Themes %s', unicode(files)) log.info(u'New Themes %s', unicode(files))
if not files:
return
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
if files: for file in files:
for file in files: SettingsManager.set_last_dir(self.settingsSection, unicode(file))
SettingsManager.set_last_dir( self.unzipTheme(file, self.path)
self.settingsSection, unicode(file))
self.unzipTheme(file, self.path)
self.loadThemes() self.loadThemes()
Receiver.send_message(u'cursor_normal') Receiver.send_message(u'cursor_normal')
@ -502,16 +502,16 @@ class ThemeManager(QtGui.QWidget):
def unzipTheme(self, filename, dir): def unzipTheme(self, filename, dir):
""" """
Unzip the theme, remove the preview file if stored Unzip the theme, remove the preview file if stored
Generate a new preview fileCheck the XML theme version and upgrade if Generate a new preview file. Check the XML theme version and upgrade if
necessary. necessary.
""" """
log.debug(u'Unzipping theme %s', filename) log.debug(u'Unzipping theme %s', filename)
filename = unicode(filename) filename = unicode(filename)
zip = None zip = None
outfile = None outfile = None
filexml = None
try: try:
zip = zipfile.ZipFile(filename) zip = zipfile.ZipFile(filename)
filexml = None
themename = None themename = None
for file in zip.namelist(): for file in zip.namelist():
ucsfile = file_is_unicode(file) ucsfile = file_is_unicode(file)
@ -547,7 +547,7 @@ class ThemeManager(QtGui.QWidget):
else: else:
outfile = open(fullpath, u'wb') outfile = open(fullpath, u'wb')
outfile.write(zip.read(file)) outfile.write(zip.read(file))
except (IOError, NameError): except (IOError, NameError, zipfile.BadZipfile):
critical_error_message_box( critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.')) translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
@ -562,7 +562,9 @@ class ThemeManager(QtGui.QWidget):
if filexml: if filexml:
theme = self._createThemeFromXml(filexml, self.path) theme = self._createThemeFromXml(filexml, self.path)
self.generateAndSaveImage(dir, themename, theme) self.generateAndSaveImage(dir, themename, theme)
else: # Only show the error message, when IOError was not raised (in this
# case the error message has already been shown).
elif zip is not None:
critical_error_message_box( critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',

View File

@ -36,7 +36,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaMediaItem(MediaManagerItem): class MediaMediaItem(MediaManagerItem):
""" """
This is the custom media manager item for Media Slides. This is the custom media manager item for Media Slides.
@ -54,9 +54,6 @@ class MediaMediaItem(MediaManagerItem):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'), QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced) self.videobackgroundReplaced)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
def retranslateUi(self): def retranslateUi(self):
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
@ -125,41 +122,67 @@ class MediaMediaItem(MediaManagerItem):
if item is None: if item is None:
return False return False
filename = unicode(item.data(QtCore.Qt.UserRole).toString()) filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if not os.path.exists(filename):
self.mediaState = None
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
self.mediaObject.play()
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
service_item.add_capability(ItemCapabilities.RequiresMedia)
# force a nonexistent theme
service_item.theme = -1
frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename)
file_size = os.path.getsize(filename)
# File too big for processing
if file_size <= 52428800: # 50MiB
start = datetime.now()
while not self.mediaState:
Receiver.send_message(u'openlp_process_events')
tme = datetime.now() - start
if tme.seconds > 5:
break
if self.mediaState:
service_item.media_length = self.mediaLength
service_item.add_capability(
ItemCapabilities.AllowsVariableStartTime)
service_item.add_from_command(path, name, frame)
return True
else:
# File is no longer present # File is no longer present
critical_error_message_box( critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'Missing Media File'),
unicode(translate('MediaPlugin.MediaItem', unicode(translate('MediaPlugin.MediaItem',
'The file %s no longer exists.')) % filename) 'The file %s no longer exists.')) % filename)
return False return False
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
if not self.mediaStateWait(Phonon.StoppedState):
# Due to string freeze, borrow a message from presentations
# This will be corrected in 1.9.6
critical_error_message_box(
translate('PresentationPlugin.MediaItem', 'Unsupported File'),
unicode(translate('PresentationPlugin.MediaItem',
'Unsupported File')))
return False
# File too big for processing
if os.path.getsize(filename) <= 52428800: # 50MiB
self.mediaObject.play()
if not self.mediaStateWait(Phonon.PlayingState) \
or self.mediaObject.currentSource().type() \
== Phonon.MediaSource.Invalid:
# Due to string freeze, borrow a message from presentations
# This will be corrected in 1.9.6
self.mediaObject.stop()
critical_error_message_box(
translate('PresentationPlugin.MediaItem',
'Unsupported File'),
unicode(translate('PresentationPlugin.MediaItem',
'Unsupported File')))
return False
self.mediaLength = self.mediaObject.totalTime() / 1000
self.mediaObject.stop()
service_item.media_length = self.mediaLength
service_item.add_capability(
ItemCapabilities.AllowsVariableStartTime)
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
service_item.add_capability(ItemCapabilities.RequiresMedia)
# force a non-existent theme
service_item.theme = -1
frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename)
service_item.add_from_command(path, name, frame)
return True
def mediaStateWait(self, mediaState):
"""
Wait for the video to change its state
Wait no longer than 5 seconds.
"""
start = datetime.now()
while self.mediaObject.state() != mediaState:
if self.mediaObject.state() == Phonon.ErrorState:
return False
Receiver.send_message(u'openlp_process_events')
if (datetime.now() - start).seconds > 5:
return False
return True
def initialise(self): def initialise(self):
self.listView.clear() self.listView.clear()
self.listView.setIconSize(QtCore.QSize(88, 50)) self.listView.setIconSize(QtCore.QSize(88, 50))
@ -187,12 +210,3 @@ class MediaMediaItem(MediaManagerItem):
item_name.setIcon(build_icon(img)) item_name.setIcon(build_icon(img))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name) self.listView.addItem(item_name)
def videoStart(self, newState, oldState):
"""
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
self.mediaState = newState
self.mediaLength = self.mediaObject.totalTime()/1000
self.mediaObject.stop()

View File

@ -275,14 +275,33 @@ def clean_song(manager, song):
sxml = SongXML() sxml = SongXML()
# Rebuild the song's verses, to remove any wrong verse names (for example # Rebuild the song's verses, to remove any wrong verse names (for example
# translated ones), which might have been added prior to 1.9.5. # translated ones), which might have been added prior to 1.9.5.
# List for later comparison.
compare_order = []
for verse in verses: for verse in verses:
type = VerseType.Tags[VerseType.from_loose_input(verse[0][u'type'])]
sxml.add_verse_to_lyrics( sxml.add_verse_to_lyrics(
VerseType.Tags[VerseType.from_loose_input(verse[0][u'type'])], type,
verse[0][u'label'], verse[0][u'label'],
verse[1], verse[1],
verse[0][u'lang'] if verse[0].has_key(u'lang') else None verse[0][u'lang'] if verse[0].has_key(u'lang') else None
) )
compare_order.append((u'%s%s' % (type, verse[0][u'label'])).upper())
song.lyrics = unicode(sxml.extract_xml(), u'utf-8') song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
# Rebuild the verse order, to convert translated verse tags, which might
# have been added prior to 1.9.5.
order = song.verse_order.strip().split()
new_order = []
for verse_def in order:
new_order.append((u'%s%s' % (
VerseType.Tags[VerseType.from_loose_input(verse_def[0])],
verse_def[1:])).upper()
)
song.verse_order = u' '.join(new_order)
# Check if the verse order contains tags for verses which do not exist.
for order in new_order:
if order not in compare_order:
song.verse_order = u''
break
# The song does not have any author, add one. # The song does not have any author, add one.
if not song.authors: if not song.authors:
name = SongStrings.AuthorUnknown name = SongStrings.AuthorUnknown

View File

@ -461,5 +461,5 @@ class SongMediaItem(MediaManagerItem):
""" """
Locale aware collation of song titles Locale aware collation of song titles
""" """
return locale.strcoll(unicode(song_1.title.lower()), return locale.strcoll(unicode(song_1.title.lower()),
unicode(song_2.title.lower())) unicode(song_2.title.lower()))

View File

@ -309,7 +309,7 @@ class SofImport(OooImport):
self.add_verse(lyrics, tag) self.add_verse(lyrics, tag)
if not self.is_chorus and u'C1' in self.verse_order_list_generated: if not self.is_chorus and u'C1' in self.verse_order_list_generated:
self.verse_order_list_generated.append(u'C1') self.verse_order_list_generated.append(u'C1')
self.verse_order_list_generated_useful = True self.verse_order_list_generated_useful = True
def uncap_text(self, text): def uncap_text(self, text):
""" """

View File

@ -225,7 +225,7 @@ class SongImport(QtCore.QObject):
self.verse_counts[verse_def[0]] = int(verse_def[1:]) self.verse_counts[verse_def[0]] = int(verse_def[1:])
self.verses.append([verse_def, verse_text.rstrip(), lang]) self.verses.append([verse_def, verse_text.rstrip(), lang])
self.verse_order_list_generated.append(verse_def) self.verse_order_list_generated.append(verse_def)
def repeat_verse(self): def repeat_verse(self):
""" """
Repeat the previous verse in the verse order Repeat the previous verse in the verse order

View File

@ -131,7 +131,7 @@ class SongShowPlusImport(SongImport):
lengthDescriptor, = struct.unpack("B", songData.read(1)) lengthDescriptor, = struct.unpack("B", songData.read(1))
data = songData.read(lengthDescriptor) data = songData.read(lengthDescriptor)
if blockKey == TITLE: if blockKey == TITLE:
self.title = unicode(data, u'cp1252') self.title = unicode(data, u'cp1252')
elif blockKey == AUTHOR: elif blockKey == AUTHOR:
authors = data.split(" / ") authors = data.split(" / ")
for author in authors: for author in authors:

View File

@ -62,7 +62,41 @@ setup(
description="Open source Church presentation and lyrics projection application.", description="Open source Church presentation and lyrics projection application.",
long_description="""\ long_description="""\
OpenLP (previously openlp.org) is free church presentation software, or lyrics projection software, used to display slides of songs, Bible verses, videos, images, and even presentations (if PowerPoint is installed) for church worship using a computer and a data projector.""", OpenLP (previously openlp.org) is free church presentation software, or lyrics projection software, used to display slides of songs, Bible verses, videos, images, and even presentations (if PowerPoint is installed) for church worship using a computer and a data projector.""",
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[
'Development Status :: 4 - Beta',
'Environment :: MacOS X',
'Environment :: Win32 (MS Windows)',
'Environment :: X11 Applications',
'Environment :: X11 Applications :: Qt',
'Intended Audience :: End Users/Desktop',
'Intended Audience :: Religion',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Natural Language :: Afrikaans',
'Natural Language :: Dutch',
'Natural Language :: English',
'Natural Language :: French',
'Natural Language :: German',
'Natural Language :: Hungarian',
'Natural Language :: Indonesian',
'Natural Language :: Japanese',
'Natural Language :: Norwegian',
'Natural Language :: Portuguese (Brazilian)',
'Natural Language :: Russian',
'Natural Language :: Swedish',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: BSD :: FreeBSD',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Topic :: Desktop Environment :: Gnome',
'Topic :: Desktop Environment :: K Desktop Environment (KDE)',
'Topic :: Multimedia',
'Topic :: Multimedia :: Graphics :: Presentation',
'Topic :: Multimedia :: Sound/Audio',
'Topic :: Multimedia :: Video',
'Topic :: Religion'
], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='open source church presentation lyrics projection song bible display project', keywords='open source church presentation lyrics projection song bible display project',
author='Raoul Snyman', author='Raoul Snyman',
author_email='raoulsnyman@openlp.org', author_email='raoulsnyman@openlp.org',