forked from openlp/openlp
[merge] merge with trunk r1739
This commit is contained in:
commit
bd503f5c7d
@ -27,3 +27,9 @@
|
|||||||
"""
|
"""
|
||||||
The :mod:`openlp` module contains all the project produced OpenLP functionality
|
The :mod:`openlp` module contains all the project produced OpenLP functionality
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import core
|
||||||
|
import plugins
|
||||||
|
|
||||||
|
__all__ = [u'core', u'plugins']
|
||||||
|
|
||||||
|
@ -25,7 +25,12 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
__all__ = ('OpenLP', 'main')
|
"""
|
||||||
|
The :mod:`core` module provides all core application functions
|
||||||
|
|
||||||
|
All the core functions of the OpenLP application including the GUI, settings,
|
||||||
|
logging and a plugin framework are contained within the openlp.core module.
|
||||||
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@ -46,16 +51,11 @@ from openlp.core.ui import SplashScreen, ScreenList
|
|||||||
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
|
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
|
||||||
get_application_version, DelayStartThread
|
get_application_version, DelayStartThread
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [u'OpenLP', u'main']
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
The :mod:`core` module provides all core application functions
|
|
||||||
|
|
||||||
All the core functions of the OpenLP application including the GUI, settings,
|
|
||||||
logging and a plugin framework are contained within the openlp.core module.
|
|
||||||
"""
|
|
||||||
|
|
||||||
application_stylesheet = u"""
|
application_stylesheet = u"""
|
||||||
QMainWindow::separator
|
QMainWindow::separator
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,13 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class MediaType(object):
|
||||||
|
"""
|
||||||
|
An enumeration class for types of media.
|
||||||
|
"""
|
||||||
|
Audio = 1
|
||||||
|
Video = 2
|
||||||
|
|
||||||
def translate(context, text, comment=None,
|
def translate(context, text, comment=None,
|
||||||
encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
|
encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
|
||||||
translate=QtCore.QCoreApplication.translate):
|
translate=QtCore.QCoreApplication.translate):
|
||||||
@ -241,9 +248,7 @@ from settingsmanager import SettingsManager
|
|||||||
from plugin import PluginStatus, StringContent, Plugin
|
from plugin import PluginStatus, StringContent, Plugin
|
||||||
from pluginmanager import PluginManager
|
from pluginmanager import PluginManager
|
||||||
from settingstab import SettingsTab
|
from settingstab import SettingsTab
|
||||||
from serviceitem import ServiceItem
|
from serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
|
||||||
from serviceitem import ServiceItemType
|
|
||||||
from serviceitem import ItemCapabilities
|
|
||||||
from htmlbuilder import build_html, build_lyrics_format_css, \
|
from htmlbuilder import build_html, build_lyrics_format_css, \
|
||||||
build_lyrics_outline_css
|
build_lyrics_outline_css
|
||||||
from toolbar import OpenLPToolbar
|
from toolbar import OpenLPToolbar
|
||||||
|
@ -82,7 +82,7 @@ def upgrade_db(url, upgrade):
|
|||||||
load_changes = True
|
load_changes = True
|
||||||
try:
|
try:
|
||||||
tables = upgrade.upgrade_setup(metadata)
|
tables = upgrade.upgrade_setup(metadata)
|
||||||
except SQLAlchemyError, DBAPIError:
|
except (SQLAlchemyError, DBAPIError):
|
||||||
load_changes = False
|
load_changes = False
|
||||||
metadata_table = Table(u'metadata', metadata,
|
metadata_table = Table(u'metadata', metadata,
|
||||||
Column(u'key', types.Unicode(64), primary_key=True),
|
Column(u'key', types.Unicode(64), primary_key=True),
|
||||||
@ -106,7 +106,7 @@ def upgrade_db(url, upgrade):
|
|||||||
getattr(upgrade, u'upgrade_%d' % version) \
|
getattr(upgrade, u'upgrade_%d' % version) \
|
||||||
(session, metadata, tables)
|
(session, metadata, tables)
|
||||||
version_meta.value = unicode(version)
|
version_meta.value = unicode(version)
|
||||||
except SQLAlchemyError, DBAPIError:
|
except (SQLAlchemyError, DBAPIError):
|
||||||
log.exception(u'Could not run database upgrade script '
|
log.exception(u'Could not run database upgrade script '
|
||||||
'"upgrade_%s", upgrade process has been halted.', version)
|
'"upgrade_%s", upgrade process has been halted.', version)
|
||||||
break
|
break
|
||||||
@ -221,7 +221,8 @@ class Manager(object):
|
|||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
self.session = init_schema(self.db_url)
|
self.session = init_schema(self.db_url)
|
||||||
except:
|
except (SQLAlchemyError, DBAPIError):
|
||||||
|
log.exception(u'Error loading database: %s', self.db_url)
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
translate('OpenLP.Manager', 'Database Error'),
|
translate('OpenLP.Manager', 'Database Error'),
|
||||||
unicode(translate('OpenLP.Manager', 'OpenLP cannot load your '
|
unicode(translate('OpenLP.Manager', 'OpenLP cannot load your '
|
||||||
|
@ -111,7 +111,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
self.requiredIcons()
|
self.requiredIcons()
|
||||||
self.setupUi()
|
self.setupUi()
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name),
|
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name),
|
||||||
self.serviceLoad)
|
self.serviceLoad)
|
||||||
@ -506,7 +506,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
if QtCore.QSettings().value(u'advanced/single click preview',
|
if QtCore.QSettings().value(u'advanced/single click preview',
|
||||||
QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \
|
QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \
|
||||||
and self.listView.selectedIndexes() \
|
and self.listView.selectedIndexes() \
|
||||||
and self.auto_select_id == -1:
|
and self.autoSelectId == -1:
|
||||||
self.onPreviewClick(True)
|
self.onPreviewClick(True)
|
||||||
|
|
||||||
def onPreviewClick(self, keepFocus=False):
|
def onPreviewClick(self, keepFocus=False):
|
||||||
@ -626,7 +626,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def check_search_result(self):
|
def checkSearchResult(self):
|
||||||
"""
|
"""
|
||||||
Checks if the listView is empty and adds a "No Search Results" item.
|
Checks if the listView is empty and adds a "No Search Results" item.
|
||||||
"""
|
"""
|
||||||
@ -662,15 +662,15 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
return item_id
|
return item_id
|
||||||
|
|
||||||
def save_auto_select_id(self):
|
def saveAutoSelectId(self):
|
||||||
"""
|
"""
|
||||||
Sorts out, what item to select after loading a list.
|
Sorts out, what item to select after loading a list.
|
||||||
"""
|
"""
|
||||||
# The item to select has not been set.
|
# The item to select has not been set.
|
||||||
if self.auto_select_id == -1:
|
if self.autoSelectId == -1:
|
||||||
item = self.listView.currentItem()
|
item = self.listView.currentItem()
|
||||||
if item:
|
if item:
|
||||||
self.auto_select_id = item.data(QtCore.Qt.UserRole).toInt()[0]
|
self.autoSelectId = item.data(QtCore.Qt.UserRole).toInt()[0]
|
||||||
|
|
||||||
def search(self, string):
|
def search(self, string):
|
||||||
"""
|
"""
|
||||||
|
@ -368,3 +368,4 @@ class Plugin(QtCore.QObject):
|
|||||||
after this has been set.
|
after this has been set.
|
||||||
"""
|
"""
|
||||||
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
||||||
|
|
||||||
|
@ -222,14 +222,14 @@ class Renderer(object):
|
|||||||
if item.is_capable(ItemCapabilities.NoLineBreaks):
|
if item.is_capable(ItemCapabilities.NoLineBreaks):
|
||||||
line_end = u' '
|
line_end = u' '
|
||||||
# Bibles
|
# Bibles
|
||||||
if item.is_capable(ItemCapabilities.AllowsWordSplit):
|
if item.is_capable(ItemCapabilities.CanWordSplit):
|
||||||
pages = self._paginate_slide_words(text.split(u'\n'), line_end)
|
pages = self._paginate_slide_words(text.split(u'\n'), line_end)
|
||||||
else:
|
else:
|
||||||
# Clean up line endings.
|
# Clean up line endings.
|
||||||
lines = self._lines_split(text)
|
lines = self._lines_split(text)
|
||||||
pages = self._paginate_slide(lines, line_end)
|
pages = self._paginate_slide(lines, line_end)
|
||||||
# Songs and Custom
|
# Songs and Custom
|
||||||
if item.is_capable(ItemCapabilities.AllowsVirtualSplit) and \
|
if item.is_capable(ItemCapabilities.CanSoftBreak) and \
|
||||||
len(pages) > 1 and u'[---]' in text:
|
len(pages) > 1 and u'[---]' in text:
|
||||||
pages = []
|
pages = []
|
||||||
while True:
|
while True:
|
||||||
|
@ -52,20 +52,21 @@ class ItemCapabilities(object):
|
|||||||
"""
|
"""
|
||||||
Provides an enumeration of a serviceitem's capabilities
|
Provides an enumeration of a serviceitem's capabilities
|
||||||
"""
|
"""
|
||||||
AllowsPreview = 1
|
CanPreview = 1
|
||||||
AllowsEdit = 2
|
CanEdit = 2
|
||||||
AllowsMaintain = 3
|
CanMaintain = 3
|
||||||
RequiresMedia = 4
|
RequiresMedia = 4
|
||||||
AllowsLoop = 5
|
CanLoop = 5
|
||||||
AllowsAdditions = 6
|
CanAppend = 6
|
||||||
NoLineBreaks = 7
|
NoLineBreaks = 7
|
||||||
OnLoadUpdate = 8
|
OnLoadUpdate = 8
|
||||||
AddIfNewItem = 9
|
AddIfNewItem = 9
|
||||||
ProvidesOwnDisplay = 10
|
ProvidesOwnDisplay = 10
|
||||||
AllowsDetailedTitleDisplay = 11
|
HasDetailedTitleDisplay = 11
|
||||||
AllowsVariableStartTime = 12
|
HasVariableStartTime = 12
|
||||||
AllowsVirtualSplit = 13
|
CanSoftBreak = 13
|
||||||
AllowsWordSplit = 14
|
CanWordSplit = 14
|
||||||
|
HasBackgroundAudio = 15
|
||||||
|
|
||||||
|
|
||||||
class ServiceItem(object):
|
class ServiceItem(object):
|
||||||
@ -116,6 +117,7 @@ class ServiceItem(object):
|
|||||||
self.media_length = 0
|
self.media_length = 0
|
||||||
self.from_service = False
|
self.from_service = False
|
||||||
self.image_border = u'#000000'
|
self.image_border = u'#000000'
|
||||||
|
self.background_audio = []
|
||||||
self._new_item()
|
self._new_item()
|
||||||
|
|
||||||
def _new_item(self):
|
def _new_item(self):
|
||||||
@ -159,7 +161,7 @@ class ServiceItem(object):
|
|||||||
"""
|
"""
|
||||||
The render method is what generates the frames for the screen and
|
The render method is what generates the frames for the screen and
|
||||||
obtains the display information from the renderemanager.
|
obtains the display information from the renderemanager.
|
||||||
At this point all the slides are build for the given
|
At this point all the slides are built for the given
|
||||||
display size.
|
display size.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Render called')
|
log.debug(u'Render called')
|
||||||
@ -272,7 +274,8 @@ class ServiceItem(object):
|
|||||||
u'xml_version': self.xml_version,
|
u'xml_version': self.xml_version,
|
||||||
u'start_time': self.start_time,
|
u'start_time': self.start_time,
|
||||||
u'end_time': self.end_time,
|
u'end_time': self.end_time,
|
||||||
u'media_length': self.media_length
|
u'media_length': self.media_length,
|
||||||
|
u'background_audio': self.background_audio
|
||||||
}
|
}
|
||||||
service_data = []
|
service_data = []
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
@ -320,6 +323,8 @@ class ServiceItem(object):
|
|||||||
self.end_time = header[u'end_time']
|
self.end_time = header[u'end_time']
|
||||||
if u'media_length' in header:
|
if u'media_length' in header:
|
||||||
self.media_length = header[u'media_length']
|
self.media_length = header[u'media_length']
|
||||||
|
if u'background_audio' in header:
|
||||||
|
self.background_audio = header[u'background_audio']
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
for slide in serviceitem[u'serviceitem'][u'data']:
|
for slide in serviceitem[u'serviceitem'][u'data']:
|
||||||
self._raw_frames.append(slide)
|
self._raw_frames.append(slide)
|
||||||
@ -341,7 +346,7 @@ class ServiceItem(object):
|
|||||||
if self.is_text():
|
if self.is_text():
|
||||||
return self.title
|
return self.title
|
||||||
else:
|
else:
|
||||||
if ItemCapabilities.AllowsDetailedTitleDisplay in self.capabilities:
|
if ItemCapabilities.HasDetailedTitleDisplay in self.capabilities:
|
||||||
return self._raw_frames[0][u'title']
|
return self._raw_frames[0][u'title']
|
||||||
elif len(self._raw_frames) > 1:
|
elif len(self._raw_frames) > 1:
|
||||||
return self.title
|
return self.title
|
||||||
@ -359,6 +364,8 @@ class ServiceItem(object):
|
|||||||
"""
|
"""
|
||||||
self._uuid = other._uuid
|
self._uuid = other._uuid
|
||||||
self.notes = other.notes
|
self.notes = other.notes
|
||||||
|
if self.is_capable(ItemCapabilities.HasBackgroundAudio):
|
||||||
|
log.debug(self.background_audio)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""
|
"""
|
||||||
|
@ -135,6 +135,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
"""
|
"""
|
||||||
Determine the next page in the Wizard to go to.
|
Determine the next page in the Wizard to go to.
|
||||||
"""
|
"""
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
if self.currentId() == FirstTimePage.Plugins:
|
if self.currentId() == FirstTimePage.Plugins:
|
||||||
if not self.webAccess:
|
if not self.webAccess:
|
||||||
return FirstTimePage.NoInternet
|
return FirstTimePage.NoInternet
|
||||||
@ -175,9 +176,12 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
elif pageId == FirstTimePage.Progress:
|
elif pageId == FirstTimePage.Progress:
|
||||||
Receiver.send_message(u'cursor_busy')
|
Receiver.send_message(u'cursor_busy')
|
||||||
self._preWizard()
|
self._preWizard()
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
self._performWizard()
|
self._performWizard()
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
self._postWizard()
|
self._postWizard()
|
||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
|
||||||
def updateScreenListCombo(self):
|
def updateScreenListCombo(self):
|
||||||
"""
|
"""
|
||||||
@ -219,6 +223,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
Prepare the UI for the process.
|
Prepare the UI for the process.
|
||||||
"""
|
"""
|
||||||
self.max_progress = 0
|
self.max_progress = 0
|
||||||
|
self.finishButton.setVisible(False)
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
# Loop through the songs list and increase for each selected item
|
# Loop through the songs list and increase for each selected item
|
||||||
for i in xrange(self.songsListWidget.count()):
|
for i in xrange(self.songsListWidget.count()):
|
||||||
item = self.songsListWidget.item(i)
|
item = self.songsListWidget.item(i)
|
||||||
@ -242,7 +248,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
|||||||
filename = item.data(QtCore.Qt.UserRole).toString()
|
filename = item.data(QtCore.Qt.UserRole).toString()
|
||||||
size = self._getFileSize(u'%s%s' % (self.web, filename))
|
size = self._getFileSize(u'%s%s' % (self.web, filename))
|
||||||
self.max_progress += size
|
self.max_progress += size
|
||||||
self.finishButton.setVisible(False)
|
|
||||||
if self.max_progress:
|
if self.max_progress:
|
||||||
# Add on 2 for plugins status setting plus a "finished" point.
|
# Add on 2 for plugins status setting plus a "finished" point.
|
||||||
self.max_progress = self.max_progress + 2
|
self.max_progress = self.max_progress + 2
|
||||||
|
@ -62,6 +62,10 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
self.override = {}
|
self.override = {}
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
self.mediaObject = None
|
self.mediaObject = None
|
||||||
|
if live:
|
||||||
|
self.audioPlayer = AudioPlayer(self)
|
||||||
|
else:
|
||||||
|
self.audioPlayer = None
|
||||||
self.firstTime = True
|
self.firstTime = True
|
||||||
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
|
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
|
||||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
|
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
|
||||||
@ -587,61 +591,76 @@ class AudioPlayer(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Initialisation started')
|
log.debug(u'AudioPlayer Initialisation started')
|
||||||
QtCore.QObject.__init__(self, parent)
|
QtCore.QObject.__init__(self, parent)
|
||||||
self.message = None
|
self.currentIndex = -1
|
||||||
|
self.playlist = []
|
||||||
self.mediaObject = Phonon.MediaObject()
|
self.mediaObject = Phonon.MediaObject()
|
||||||
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
|
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
|
||||||
Phonon.createPath(self.mediaObject, self.audioObject)
|
Phonon.createPath(self.mediaObject, self.audioObject)
|
||||||
|
QtCore.QObject.connect(self.mediaObject,
|
||||||
|
QtCore.SIGNAL(u'aboutToFinish()'), self.onAboutToFinish)
|
||||||
|
|
||||||
def setup(self):
|
def __del__(self):
|
||||||
"""
|
|
||||||
Sets up the Audio Player for use
|
|
||||||
"""
|
|
||||||
log.debug(u'AudioPlayer Setup')
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""
|
"""
|
||||||
Shutting down so clean up connections
|
Shutting down so clean up connections
|
||||||
"""
|
"""
|
||||||
self.onMediaStop()
|
self.stop()
|
||||||
for path in self.mediaObject.outputPaths():
|
for path in self.mediaObject.outputPaths():
|
||||||
path.disconnect()
|
path.disconnect()
|
||||||
|
QtCore.QObject.__del__(self)
|
||||||
|
|
||||||
def onMediaQueue(self, message):
|
def onAboutToFinish(self):
|
||||||
"""
|
"""
|
||||||
Set up a video to play from the serviceitem.
|
Just before the audio player finishes the current track, queue the next
|
||||||
|
item in the playlist, if there is one.
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Queue new media message %s' % message)
|
self.currentIndex += 1
|
||||||
mfile = os.path.join(message[0].get_frame_path(),
|
if len(self.playlist) > self.currentIndex:
|
||||||
message[0].get_frame_title())
|
self.mediaObject.enqueue(self.playlist[self.currentIndex])
|
||||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(mfile))
|
|
||||||
self.onMediaPlay()
|
|
||||||
|
|
||||||
def onMediaPlay(self):
|
def connectVolumeSlider(self, slider):
|
||||||
|
slider.setAudioOutput(self.audioObject)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
"""
|
"""
|
||||||
We want to play the play so start it
|
Reset the audio player, clearing the playlist and the queue.
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer _play called')
|
self.currentIndex = -1
|
||||||
|
self.playlist = []
|
||||||
|
self.stop()
|
||||||
|
self.mediaObject.clear()
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
"""
|
||||||
|
We want to play the file so start it
|
||||||
|
"""
|
||||||
|
log.debug(u'AudioPlayer.play() called')
|
||||||
|
if self.currentIndex == -1:
|
||||||
|
self.onAboutToFinish()
|
||||||
self.mediaObject.play()
|
self.mediaObject.play()
|
||||||
|
|
||||||
def onMediaPause(self):
|
def pause(self):
|
||||||
"""
|
"""
|
||||||
Pause the Audio
|
Pause the Audio
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Media paused by user')
|
log.debug(u'AudioPlayer.pause() called')
|
||||||
self.mediaObject.pause()
|
self.mediaObject.pause()
|
||||||
|
|
||||||
def onMediaStop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
Stop the Audio and clean up
|
Stop the Audio and clean up
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Media stopped by user')
|
log.debug(u'AudioPlayer.stop() called')
|
||||||
self.message = None
|
|
||||||
self.mediaObject.stop()
|
self.mediaObject.stop()
|
||||||
self.onMediaFinish()
|
|
||||||
|
|
||||||
def onMediaFinish(self):
|
def addToPlaylist(self, filenames):
|
||||||
"""
|
"""
|
||||||
Clean up the Object queue
|
Add another file to the playlist.
|
||||||
|
|
||||||
|
``filename``
|
||||||
|
The file to add to the playlist.
|
||||||
"""
|
"""
|
||||||
log.debug(u'AudioPlayer Reached end of media playlist')
|
if not isinstance(filenames, list):
|
||||||
self.mediaObject.clearQueue()
|
filenames = [filenames]
|
||||||
|
for filename in filenames:
|
||||||
|
self.playlist.append(Phonon.MediaSource(filename))
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import cgi
|
|||||||
import cPickle
|
import cPickle
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -471,23 +472,34 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if not self.fileName():
|
if not self.fileName():
|
||||||
return self.saveFileAs()
|
return self.saveFileAs()
|
||||||
path_file_name = unicode(self.fileName())
|
path_file_name = unicode(self.fileName())
|
||||||
(path, file_name) = os.path.split(path_file_name)
|
path, file_name = os.path.split(path_file_name)
|
||||||
(basename, extension) = os.path.splitext(file_name)
|
basename, extension = os.path.splitext(file_name)
|
||||||
service_file_name = basename + '.osd'
|
service_file_name = '%s.osd' % basename
|
||||||
log.debug(u'ServiceManager.saveFile - %s' % path_file_name)
|
log.debug(u'ServiceManager.saveFile - %s' % path_file_name)
|
||||||
SettingsManager.set_last_dir(
|
SettingsManager.set_last_dir(
|
||||||
self.mainwindow.servicemanagerSettingsSection,
|
self.mainwindow.servicemanagerSettingsSection,
|
||||||
path)
|
path)
|
||||||
service = []
|
service = []
|
||||||
write_list = []
|
write_list = []
|
||||||
|
audio_files = []
|
||||||
total_size = 0
|
total_size = 0
|
||||||
Receiver.send_message(u'cursor_busy')
|
Receiver.send_message(u'cursor_busy')
|
||||||
# Number of items + 1 to zip it
|
# Number of items + 1 to zip it
|
||||||
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
|
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
|
||||||
for item in self.serviceItems:
|
for item in self.serviceItems:
|
||||||
self.mainwindow.incrementProgressBar()
|
self.mainwindow.incrementProgressBar()
|
||||||
service.append({u'serviceitem':
|
service_item = item[u'service_item'].get_service_repr()
|
||||||
item[u'service_item'].get_service_repr()})
|
# Get all the audio files, and ready them for embedding in the
|
||||||
|
# service file.
|
||||||
|
if len(service_item[u'header'][u'background_audio']) > 0:
|
||||||
|
for i, filename in \
|
||||||
|
enumerate(service_item[u'header'][u'background_audio']):
|
||||||
|
new_file = os.path.join(u'audio', item[u'service_item']._uuid,
|
||||||
|
os.path.split(filename)[1])
|
||||||
|
audio_files.append((filename, new_file))
|
||||||
|
service_item[u'header'][u'background_audio'][i] = new_file
|
||||||
|
# Add the service item to the service.
|
||||||
|
service.append({u'serviceitem': service_item})
|
||||||
if not item[u'service_item'].uses_file():
|
if not item[u'service_item'].uses_file():
|
||||||
continue
|
continue
|
||||||
skipMissing = False
|
skipMissing = False
|
||||||
@ -541,6 +553,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
# Finally add all the listed media files.
|
# Finally add all the listed media files.
|
||||||
for path_from in write_list:
|
for path_from in write_list:
|
||||||
zip.write(path_from, path_from.encode(u'utf-8'))
|
zip.write(path_from, path_from.encode(u'utf-8'))
|
||||||
|
for path_from, path_to in audio_files:
|
||||||
|
zip.write(path_from, path_to.encode(u'utf-8'))
|
||||||
except IOError:
|
except IOError:
|
||||||
log.exception(u'Failed to save service to disk')
|
log.exception(u'Failed to save service to disk')
|
||||||
success = False
|
success = False
|
||||||
@ -595,11 +609,12 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
'The content encoding is not UTF-8.'))
|
'The content encoding is not UTF-8.'))
|
||||||
continue
|
continue
|
||||||
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile))
|
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile))
|
||||||
filename_only = os.path.split(osfile)[1]
|
if not osfile.startswith(u'audio'):
|
||||||
zipinfo.filename = filename_only
|
osfile = os.path.split(osfile)[1]
|
||||||
|
zipinfo.filename = osfile
|
||||||
zip.extract(zipinfo, self.servicePath)
|
zip.extract(zipinfo, self.servicePath)
|
||||||
if filename_only.endswith(u'osd'):
|
if osfile.endswith(u'osd'):
|
||||||
p_file = os.path.join(self.servicePath, filename_only)
|
p_file = os.path.join(self.servicePath, osfile)
|
||||||
if 'p_file' in locals():
|
if 'p_file' in locals():
|
||||||
Receiver.send_message(u'cursor_busy')
|
Receiver.send_message(u'cursor_busy')
|
||||||
fileTo = open(p_file, u'r')
|
fileTo = open(p_file, u'r')
|
||||||
@ -630,10 +645,10 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
'File is not a valid service.'))
|
'File is not a valid service.'))
|
||||||
log.exception(u'File contains no service data')
|
log.exception(u'File contains no service data')
|
||||||
except (IOError, NameError, zipfile.BadZipfile):
|
except (IOError, NameError, zipfile.BadZipfile):
|
||||||
|
log.exception(u'Problem loading service file %s' % fileName)
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
message=translate('OpenLP.ServiceManager',
|
message=translate('OpenLP.ServiceManager',
|
||||||
'File could not be opened because it is corrupt.'))
|
'File could not be opened because it is corrupt.'))
|
||||||
log.exception(u'Problem loading service file %s' % fileName)
|
|
||||||
except zipfile.BadZipfile:
|
except zipfile.BadZipfile:
|
||||||
if os.path.getsize(fileName) == 0:
|
if os.path.getsize(fileName) == 0:
|
||||||
log.exception(u'Service file is zero sized: %s' % fileName)
|
log.exception(u'Service file is zero sized: %s' % fileName)
|
||||||
@ -682,16 +697,16 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.maintainAction.setVisible(False)
|
self.maintainAction.setVisible(False)
|
||||||
self.notesAction.setVisible(False)
|
self.notesAction.setVisible(False)
|
||||||
self.timeAction.setVisible(False)
|
self.timeAction.setVisible(False)
|
||||||
if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\
|
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanEdit)\
|
||||||
and serviceItem[u'service_item'].edit_id:
|
and serviceItem[u'service_item'].edit_id:
|
||||||
self.editAction.setVisible(True)
|
self.editAction.setVisible(True)
|
||||||
if serviceItem[u'service_item']\
|
if serviceItem[u'service_item']\
|
||||||
.is_capable(ItemCapabilities.AllowsMaintain):
|
.is_capable(ItemCapabilities.CanMaintain):
|
||||||
self.maintainAction.setVisible(True)
|
self.maintainAction.setVisible(True)
|
||||||
if item.parent() is None:
|
if item.parent() is None:
|
||||||
self.notesAction.setVisible(True)
|
self.notesAction.setVisible(True)
|
||||||
if serviceItem[u'service_item']\
|
if serviceItem[u'service_item']\
|
||||||
.is_capable(ItemCapabilities.AllowsVariableStartTime):
|
.is_capable(ItemCapabilities.HasVariableStartTime):
|
||||||
self.timeAction.setVisible(True)
|
self.timeAction.setVisible(True)
|
||||||
self.themeMenu.menuAction().setVisible(False)
|
self.themeMenu.menuAction().setVisible(False)
|
||||||
# Set up the theme menu.
|
# Set up the theme menu.
|
||||||
@ -962,7 +977,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
(unicode(translate('OpenLP.ServiceManager', 'Notes')),
|
(unicode(translate('OpenLP.ServiceManager', 'Notes')),
|
||||||
cgi.escape(unicode(serviceitem.notes))))
|
cgi.escape(unicode(serviceitem.notes))))
|
||||||
if item[u'service_item'] \
|
if item[u'service_item'] \
|
||||||
.is_capable(ItemCapabilities.AllowsVariableStartTime):
|
.is_capable(ItemCapabilities.HasVariableStartTime):
|
||||||
tips.append(item[u'service_item'].get_media_time())
|
tips.append(item[u'service_item'].get_media_time())
|
||||||
treewidgetitem.setToolTip(0, u'<br>'.join(tips))
|
treewidgetitem.setToolTip(0, u'<br>'.join(tips))
|
||||||
treewidgetitem.setData(0, QtCore.Qt.UserRole,
|
treewidgetitem.setData(0, QtCore.Qt.UserRole,
|
||||||
@ -998,6 +1013,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
for file in os.listdir(self.servicePath):
|
for file in os.listdir(self.servicePath):
|
||||||
file_path = os.path.join(self.servicePath, file)
|
file_path = os.path.join(self.servicePath, file)
|
||||||
delete_file(file_path)
|
delete_file(file_path)
|
||||||
|
if os.path.exists(os.path.join(self.servicePath, u'audio')):
|
||||||
|
shutil.rmtree(os.path.join(self.servicePath, u'audio'), False)
|
||||||
|
|
||||||
def onThemeComboBoxSelected(self, currentIndex):
|
def onThemeComboBoxSelected(self, currentIndex):
|
||||||
"""
|
"""
|
||||||
@ -1196,7 +1213,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
item += 1
|
item += 1
|
||||||
if self.serviceItems and item < len(self.serviceItems) and \
|
if self.serviceItems and item < len(self.serviceItems) and \
|
||||||
self.serviceItems[item][u'service_item'].is_capable(
|
self.serviceItems[item][u'service_item'].is_capable(
|
||||||
ItemCapabilities.AllowsPreview):
|
ItemCapabilities.CanPreview):
|
||||||
self.mainwindow.previewController.addServiceManagerItem(
|
self.mainwindow.previewController.addServiceManagerItem(
|
||||||
self.serviceItems[item][u'service_item'], 0)
|
self.serviceItems[item][u'service_item'], 0)
|
||||||
self.mainwindow.liveController.previewListWidget.setFocus()
|
self.mainwindow.liveController.previewListWidget.setFocus()
|
||||||
@ -1214,7 +1231,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
item = self.findServiceItem()[0]
|
item = self.findServiceItem()[0]
|
||||||
if self.serviceItems[item][u'service_item']\
|
if self.serviceItems[item][u'service_item']\
|
||||||
.is_capable(ItemCapabilities.AllowsEdit):
|
.is_capable(ItemCapabilities.CanEdit):
|
||||||
Receiver.send_message(u'%s_edit' %
|
Receiver.send_message(u'%s_edit' %
|
||||||
self.serviceItems[item][u'service_item'].name.lower(),
|
self.serviceItems[item][u'service_item'].name.lower(),
|
||||||
u'L:%s' % self.serviceItems[item][u'service_item'].edit_id)
|
u'L:%s' % self.serviceItems[item][u'service_item'].edit_id)
|
||||||
@ -1297,7 +1314,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
serviceItem = self.serviceItems[pos]
|
serviceItem = self.serviceItems[pos]
|
||||||
if (plugin == serviceItem[u'service_item'].name and
|
if (plugin == serviceItem[u'service_item'].name and
|
||||||
serviceItem[u'service_item'].is_capable(
|
serviceItem[u'service_item'].is_capable(
|
||||||
ItemCapabilities.AllowsAdditions)):
|
ItemCapabilities.CanAppend)):
|
||||||
action = self.dndMenu.exec_(QtGui.QCursor.pos())
|
action = self.dndMenu.exec_(QtGui.QCursor.pos())
|
||||||
# New action required
|
# New action required
|
||||||
if action == self.newAction:
|
if action == self.newAction:
|
||||||
|
@ -256,6 +256,12 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.songMenu.setMenu(QtGui.QMenu(
|
self.songMenu.setMenu(QtGui.QMenu(
|
||||||
translate('OpenLP.SlideController', 'Go To'), self.toolbar))
|
translate('OpenLP.SlideController', 'Go To'), self.toolbar))
|
||||||
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
|
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
|
||||||
|
# Stuff for items with background audio.
|
||||||
|
self.audioPauseItem = self.toolbar.addToolbarButton(
|
||||||
|
u'Pause Audio', u':/slides/media_playback_pause.png',
|
||||||
|
translate('OpenLP.SlideController', 'Pause audio.'),
|
||||||
|
self.onAudioPauseClicked, True)
|
||||||
|
self.audioPauseItem.setVisible(False)
|
||||||
# Build the volumeSlider.
|
# Build the volumeSlider.
|
||||||
self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
|
self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
|
||||||
self.volumeSlider.setTickInterval(1)
|
self.volumeSlider.setTickInterval(1)
|
||||||
@ -518,7 +524,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.parent().songsSettingsSection + u'/display songbar',
|
self.parent().songsSettingsSection + u'/display songbar',
|
||||||
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
|
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
|
||||||
self.toolbar.makeWidgetsVisible([u'Song Menu'])
|
self.toolbar.makeWidgetsVisible([u'Song Menu'])
|
||||||
if item.is_capable(ItemCapabilities.AllowsLoop) and \
|
if item.is_capable(ItemCapabilities.CanLoop) and \
|
||||||
len(item.get_frames()) > 1:
|
len(item.get_frames()) > 1:
|
||||||
self.toolbar.makeWidgetsVisible(self.loopList)
|
self.toolbar.makeWidgetsVisible(self.loopList)
|
||||||
if item.is_media():
|
if item.is_media():
|
||||||
@ -538,7 +544,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.toolbar.hide()
|
self.toolbar.hide()
|
||||||
self.mediabar.setVisible(False)
|
self.mediabar.setVisible(False)
|
||||||
self.toolbar.makeWidgetsInvisible(self.songEditList)
|
self.toolbar.makeWidgetsInvisible(self.songEditList)
|
||||||
if item.is_capable(ItemCapabilities.AllowsEdit) and item.from_plugin:
|
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
|
||||||
self.toolbar.makeWidgetsVisible(self.songEditList)
|
self.toolbar.makeWidgetsVisible(self.songEditList)
|
||||||
elif item.is_media():
|
elif item.is_media():
|
||||||
self.toolbar.setVisible(False)
|
self.toolbar.setVisible(False)
|
||||||
@ -576,7 +582,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Replacement item following a remote edit
|
Replacement item following a remote edit
|
||||||
"""
|
"""
|
||||||
if item.__eq__(self.serviceItem):
|
if item == self.serviceItem:
|
||||||
self._processItem(item, self.previewListWidget.currentRow())
|
self._processItem(item, self.previewListWidget.currentRow())
|
||||||
|
|
||||||
def addServiceManagerItem(self, item, slideno):
|
def addServiceManagerItem(self, item, slideno):
|
||||||
@ -586,15 +592,17 @@ class SlideController(QtGui.QWidget):
|
|||||||
Called by ServiceManager
|
Called by ServiceManager
|
||||||
"""
|
"""
|
||||||
log.debug(u'addServiceManagerItem live = %s' % self.isLive)
|
log.debug(u'addServiceManagerItem live = %s' % self.isLive)
|
||||||
# If no valid slide number is specified we take the first one.
|
# If no valid slide number is specified we take the first one, but we
|
||||||
|
# remember the initial value to see if we should reload the song or not
|
||||||
|
slidenum = slideno
|
||||||
if slideno == -1:
|
if slideno == -1:
|
||||||
slideno = 0
|
slidenum = 0
|
||||||
# If service item is the same as the current on only change slide
|
# If service item is the same as the current one, only change slide
|
||||||
if item.__eq__(self.serviceItem):
|
if slideno >= 0 and item == self.serviceItem:
|
||||||
self.__checkUpdateSelectedSlide(slideno)
|
self.__checkUpdateSelectedSlide(slidenum)
|
||||||
self.slideSelected()
|
self.slideSelected()
|
||||||
return
|
else:
|
||||||
self._processItem(item, slideno)
|
self._processItem(item, slidenum)
|
||||||
|
|
||||||
def _processItem(self, serviceItem, slideno):
|
def _processItem(self, serviceItem, slideno):
|
||||||
"""
|
"""
|
||||||
@ -618,6 +626,15 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.previewListWidget.setColumnWidth(0, width)
|
self.previewListWidget.setColumnWidth(0, width)
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
self.songMenu.menu().clear()
|
self.songMenu.menu().clear()
|
||||||
|
self.display.audioPlayer.reset()
|
||||||
|
self.setAudioItemsVisibility(False)
|
||||||
|
self.audioPauseItem.setChecked(False)
|
||||||
|
if self.serviceItem.is_capable(ItemCapabilities.HasBackgroundAudio):
|
||||||
|
log.debug(u'Starting to play...')
|
||||||
|
self.display.audioPlayer.addToPlaylist(
|
||||||
|
self.serviceItem.background_audio)
|
||||||
|
self.display.audioPlayer.play()
|
||||||
|
self.setAudioItemsVisibility(True)
|
||||||
row = 0
|
row = 0
|
||||||
text = []
|
text = []
|
||||||
for framenumber, frame in enumerate(self.serviceItem.get_frames()):
|
for framenumber, frame in enumerate(self.serviceItem.get_frames()):
|
||||||
@ -1097,6 +1114,17 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.playSlidesLoop.setChecked(False)
|
self.playSlidesLoop.setChecked(False)
|
||||||
self.onToggleLoop()
|
self.onToggleLoop()
|
||||||
|
|
||||||
|
def setAudioItemsVisibility(self, visible):
|
||||||
|
self.audioPauseItem.setVisible(visible)
|
||||||
|
|
||||||
|
def onAudioPauseClicked(self, checked):
|
||||||
|
if not self.audioPauseItem.isVisible():
|
||||||
|
return
|
||||||
|
if checked:
|
||||||
|
self.display.audioPlayer.pause()
|
||||||
|
else:
|
||||||
|
self.display.audioPlayer.play()
|
||||||
|
|
||||||
def timerEvent(self, event):
|
def timerEvent(self, event):
|
||||||
"""
|
"""
|
||||||
If the timer event is for this window select next slide
|
If the timer event is for this window select next slide
|
||||||
|
@ -67,7 +67,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
self.search_results = {}
|
self.search_results = {}
|
||||||
self.second_search_results = {}
|
self.second_search_results = {}
|
||||||
self.check_search_result()
|
self.checkSearchResult()
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles)
|
QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles)
|
||||||
|
|
||||||
@ -651,7 +651,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
elif self.search_results:
|
elif self.search_results:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
self.advancedSearchButton.setEnabled(True)
|
self.advancedSearchButton.setEnabled(True)
|
||||||
self.check_search_result()
|
self.checkSearchResult()
|
||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
Receiver.send_message(u'openlp_process_events')
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
|
||||||
@ -715,7 +715,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
elif self.search_results:
|
elif self.search_results:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
self.quickSearchButton.setEnabled(True)
|
self.quickSearchButton.setEnabled(True)
|
||||||
self.check_search_result()
|
self.checkSearchResult()
|
||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
Receiver.send_message(u'openlp_process_events')
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
|
||||||
@ -863,9 +863,9 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
not second_bible:
|
not second_bible:
|
||||||
# Split the line but do not replace line breaks in renderer.
|
# Split the line but do not replace line breaks in renderer.
|
||||||
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsWordSplit)
|
service_item.add_capability(ItemCapabilities.CanWordSplit)
|
||||||
# Service Item: Title
|
# Service Item: Title
|
||||||
service_item.title = u', '.join(raw_title)
|
service_item.title = u', '.join(raw_title)
|
||||||
# Service Item: Theme
|
# Service Item: Theme
|
||||||
|
@ -135,7 +135,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
self.customSlide.credits = unicode(self.creditEdit.text())
|
self.customSlide.credits = unicode(self.creditEdit.text())
|
||||||
self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
|
self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
|
||||||
success = self.manager.save_object(self.customSlide)
|
success = self.manager.save_object(self.customSlide)
|
||||||
self.mediaitem.auto_select_id = self.customSlide.id
|
self.mediaitem.autoSelectId = self.customSlide.id
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def onUpButtonClicked(self):
|
def onUpButtonClicked(self):
|
||||||
|
@ -132,7 +132,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def loadList(self, custom_slides):
|
def loadList(self, custom_slides):
|
||||||
# Sort out what custom we want to select after loading the list.
|
# Sort out what custom we want to select after loading the list.
|
||||||
self.save_auto_select_id()
|
self.saveAutoSelectId()
|
||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
# Sort the customs by its title considering language specific
|
# Sort the customs by its title considering language specific
|
||||||
# characters. lower() is needed for windows!
|
# characters. lower() is needed for windows!
|
||||||
@ -144,9 +144,9 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id))
|
QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id))
|
||||||
self.listView.addItem(custom_name)
|
self.listView.addItem(custom_name)
|
||||||
# Auto-select the custom.
|
# Auto-select the custom.
|
||||||
if custom_slide.id == self.auto_select_id:
|
if custom_slide.id == self.autoSelectId:
|
||||||
self.listView.setCurrentItem(custom_name)
|
self.listView.setCurrentItem(custom_name)
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
# Called to redisplay the custom list screen edith from a search
|
# Called to redisplay the custom list screen edith from a search
|
||||||
# or from the exit of the Custom edit dialog. If remote editing is
|
# or from the exit of the Custom edit dialog. If remote editing is
|
||||||
# active trigger it and clean up so it will not update again.
|
# active trigger it and clean up so it will not update again.
|
||||||
@ -180,7 +180,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
self.remoteTriggered = remote_type
|
self.remoteTriggered = remote_type
|
||||||
self.edit_custom_form.loadCustom(custom_id, (remote_type == u'P'))
|
self.edit_custom_form.loadCustom(custom_id, (remote_type == u'P'))
|
||||||
self.edit_custom_form.exec_()
|
self.edit_custom_form.exec_()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
self.onSearchTextButtonClick()
|
self.onSearchTextButtonClick()
|
||||||
|
|
||||||
def onEditClick(self):
|
def onEditClick(self):
|
||||||
@ -192,7 +192,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
self.edit_custom_form.loadCustom(item_id, False)
|
self.edit_custom_form.loadCustom(item_id, False)
|
||||||
self.edit_custom_form.exec_()
|
self.edit_custom_form.exec_()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
self.onSearchTextButtonClick()
|
self.onSearchTextButtonClick()
|
||||||
|
|
||||||
def onDeleteClick(self):
|
def onDeleteClick(self):
|
||||||
@ -227,10 +227,10 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
slide = None
|
slide = None
|
||||||
theme = None
|
theme = None
|
||||||
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
|
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
||||||
customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
|
customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
|
||||||
title = customSlide.title
|
title = customSlide.title
|
||||||
credit = customSlide.credits
|
credit = customSlide.credits
|
||||||
@ -273,7 +273,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ',
|
CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ',
|
||||||
search_keywords) + u'%'), order_by_ref=CustomSlide.title)
|
search_keywords) + u'%'), order_by_ref=CustomSlide.title)
|
||||||
self.loadList(search_results)
|
self.loadList(search_results)
|
||||||
self.check_search_result()
|
self.checkSearchResult()
|
||||||
|
|
||||||
def onSearchTextEditChanged(self, text):
|
def onSearchTextEditChanged(self, text):
|
||||||
"""
|
"""
|
||||||
|
@ -149,10 +149,10 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
if not items:
|
if not items:
|
||||||
return False
|
return False
|
||||||
service_item.title = unicode(self.plugin.nameStrings[u'plural'])
|
service_item.title = unicode(self.plugin.nameStrings[u'plural'])
|
||||||
service_item.add_capability(ItemCapabilities.AllowsMaintain)
|
service_item.add_capability(ItemCapabilities.CanMaintain)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsAdditions)
|
service_item.add_capability(ItemCapabilities.CanAppend)
|
||||||
# force a nonexistent theme
|
# force a nonexistent theme
|
||||||
service_item.theme = -1
|
service_item.theme = -1
|
||||||
missing_items = []
|
missing_items = []
|
||||||
|
@ -31,11 +31,11 @@ import os
|
|||||||
import locale
|
import locale
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
||||||
SettingsManager, translate, check_item_selected, Receiver
|
SettingsManager, translate, check_item_selected, Receiver, MediaType
|
||||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||||
from PyQt4.phonon import Phonon
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -48,9 +48,9 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
log.info(u'%s MediaMediaItem loaded', __name__)
|
log.info(u'%s MediaMediaItem loaded', __name__)
|
||||||
|
|
||||||
def __init__(self, parent, plugin, icon):
|
def __init__(self, parent, plugin, icon):
|
||||||
self.IconPath = u'images/image'
|
self.iconPath = u'images/image'
|
||||||
self.background = False
|
self.background = False
|
||||||
self.PreviewFunction = CLAPPERBOARD
|
self.previewFunction = CLAPPERBOARD
|
||||||
MediaManagerItem.__init__(self, parent, plugin, icon)
|
MediaManagerItem.__init__(self, parent, plugin, icon)
|
||||||
self.singleServiceItem = False
|
self.singleServiceItem = False
|
||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
@ -139,8 +139,8 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
# 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.stop()
|
||||||
self.mediaObject.clearQueue()
|
self.mediaObject.clearQueue()
|
||||||
@ -156,13 +156,16 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
or self.mediaObject.currentSource().type() \
|
or self.mediaObject.currentSource().type() \
|
||||||
== Phonon.MediaSource.Invalid:
|
== Phonon.MediaSource.Invalid:
|
||||||
self.mediaObject.stop()
|
self.mediaObject.stop()
|
||||||
critical_error_message_box(UiStrings().UnsupportedFile,
|
critical_error_message_box(
|
||||||
UiStrings().UnsupportedFile)
|
translate('MediaPlugin.MediaItem', 'File Too Big'),
|
||||||
|
translate('MediaPlugin.MediaItem', 'The file you are '
|
||||||
|
'trying to load is too big. Please reduce it to less '
|
||||||
|
'than 50MiB.'))
|
||||||
return False
|
return False
|
||||||
self.mediaObject.stop()
|
self.mediaObject.stop()
|
||||||
service_item.media_length = self.mediaObject.totalTime() / 1000
|
service_item.media_length = self.mediaObject.totalTime() / 1000
|
||||||
service_item.add_capability(
|
service_item.add_capability(
|
||||||
ItemCapabilities.AllowsVariableStartTime)
|
ItemCapabilities.HasVariableStartTime)
|
||||||
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
|
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
|
||||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||||
# force a non-existent theme
|
# force a non-existent theme
|
||||||
@ -217,6 +220,19 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
item_name.setToolTip(track)
|
item_name.setToolTip(track)
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
|
|
||||||
|
def getList(self, type=MediaType.Audio):
|
||||||
|
media = SettingsManager.load_list(self.settingsSection, u'media')
|
||||||
|
media.sort(cmp=locale.strcoll,
|
||||||
|
key=lambda filename: os.path.split(unicode(filename))[1].lower())
|
||||||
|
ext = []
|
||||||
|
if type == MediaType.Audio:
|
||||||
|
ext = self.plugin.audio_extensions_list
|
||||||
|
else:
|
||||||
|
ext = self.plugin.video_extensions_list
|
||||||
|
ext = map(lambda x: x[1:], ext)
|
||||||
|
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
||||||
|
return media
|
||||||
|
|
||||||
def createPhonon(self):
|
def createPhonon(self):
|
||||||
log.debug(u'CreatePhonon')
|
log.debug(u'CreatePhonon')
|
||||||
if not self.mediaObject:
|
if not self.mediaObject:
|
||||||
|
@ -248,7 +248,7 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
service_item.title = unicode(self.displayTypeComboBox.currentText())
|
service_item.title = unicode(self.displayTypeComboBox.currentText())
|
||||||
service_item.shortname = unicode(self.displayTypeComboBox.currentText())
|
service_item.shortname = unicode(self.displayTypeComboBox.currentText())
|
||||||
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
|
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsDetailedTitleDisplay)
|
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
|
||||||
shortname = service_item.shortname
|
shortname = service_item.shortname
|
||||||
if shortname:
|
if shortname:
|
||||||
for bitem in items:
|
for bitem in items:
|
||||||
|
@ -52,6 +52,7 @@ them separate from the functionality, so that it is easier to recreate the GUI
|
|||||||
from the .ui files later if necessary.
|
from the .ui files later if necessary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from mediafilesform import MediaFilesForm
|
||||||
from authorsform import AuthorsForm
|
from authorsform import AuthorsForm
|
||||||
from topicsform import TopicsForm
|
from topicsform import TopicsForm
|
||||||
from songbookform import SongBookForm
|
from songbookform import SongBookForm
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import build_icon, translate
|
from openlp.core.lib import build_icon, translate
|
||||||
from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box
|
from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box, \
|
||||||
|
create_up_down_push_button_set
|
||||||
from openlp.plugins.songs.lib.ui import SongStrings
|
from openlp.plugins.songs.lib.ui import SongStrings
|
||||||
|
|
||||||
class Ui_EditSongDialog(object):
|
class Ui_EditSongDialog(object):
|
||||||
@ -36,9 +37,11 @@ class Ui_EditSongDialog(object):
|
|||||||
editSongDialog.setObjectName(u'editSongDialog')
|
editSongDialog.setObjectName(u'editSongDialog')
|
||||||
editSongDialog.resize(650, 400)
|
editSongDialog.resize(650, 400)
|
||||||
editSongDialog.setWindowIcon(
|
editSongDialog.setWindowIcon(
|
||||||
build_icon(u':/icon/openlp.org-icon-32.bmp'))
|
build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||||
editSongDialog.setModal(True)
|
editSongDialog.setModal(True)
|
||||||
self.dialogLayout = QtGui.QVBoxLayout(editSongDialog)
|
self.dialogLayout = QtGui.QVBoxLayout(editSongDialog)
|
||||||
|
self.dialogLayout.setSpacing(8)
|
||||||
|
self.dialogLayout.setContentsMargins(8, 8, 8, 8)
|
||||||
self.dialogLayout.setObjectName(u'dialogLayout')
|
self.dialogLayout.setObjectName(u'dialogLayout')
|
||||||
self.songTabWidget = QtGui.QTabWidget(editSongDialog)
|
self.songTabWidget = QtGui.QTabWidget(editSongDialog)
|
||||||
self.songTabWidget.setObjectName(u'songTabWidget')
|
self.songTabWidget.setObjectName(u'songTabWidget')
|
||||||
@ -246,6 +249,36 @@ class Ui_EditSongDialog(object):
|
|||||||
self.commentsLayout.addWidget(self.commentsEdit)
|
self.commentsLayout.addWidget(self.commentsEdit)
|
||||||
self.themeTabLayout.addWidget(self.commentsGroupBox)
|
self.themeTabLayout.addWidget(self.commentsGroupBox)
|
||||||
self.songTabWidget.addTab(self.themeTab, u'')
|
self.songTabWidget.addTab(self.themeTab, u'')
|
||||||
|
# audio tab
|
||||||
|
self.audioTab = QtGui.QWidget()
|
||||||
|
self.audioTab.setObjectName(u'audioTab')
|
||||||
|
self.audioLayout = QtGui.QHBoxLayout(self.audioTab)
|
||||||
|
self.audioLayout.setObjectName(u'audioLayout')
|
||||||
|
self.audioListWidget = QtGui.QListWidget(self.audioTab)
|
||||||
|
self.audioListWidget.setObjectName(u'audioListWidget')
|
||||||
|
self.audioLayout.addWidget(self.audioListWidget)
|
||||||
|
self.audioButtonsLayout = QtGui.QVBoxLayout()
|
||||||
|
self.audioButtonsLayout.setObjectName(u'audioButtonsLayout')
|
||||||
|
self.audioAddFromFileButton = QtGui.QPushButton(self.audioTab)
|
||||||
|
self.audioAddFromFileButton.setObjectName(u'audioAddFromFileButton')
|
||||||
|
self.audioButtonsLayout.addWidget(self.audioAddFromFileButton)
|
||||||
|
self.audioAddFromMediaButton = QtGui.QPushButton(self.audioTab)
|
||||||
|
self.audioAddFromMediaButton.setObjectName(u'audioAddFromMediaButton')
|
||||||
|
self.audioButtonsLayout.addWidget(self.audioAddFromMediaButton)
|
||||||
|
self.audioRemoveButton = QtGui.QPushButton(self.audioTab)
|
||||||
|
self.audioRemoveButton.setObjectName(u'audioRemoveButton')
|
||||||
|
self.audioButtonsLayout.addWidget(self.audioRemoveButton)
|
||||||
|
self.audioRemoveAllButton = QtGui.QPushButton(self.audioTab)
|
||||||
|
self.audioRemoveAllButton.setObjectName(u'audioRemoveAllButton')
|
||||||
|
self.audioButtonsLayout.addWidget(self.audioRemoveAllButton)
|
||||||
|
self.audioButtonsLayout.addStretch(1)
|
||||||
|
self.upButton, self.downButton = \
|
||||||
|
create_up_down_push_button_set(self)
|
||||||
|
self.audioButtonsLayout.addWidget(self.upButton)
|
||||||
|
self.audioButtonsLayout.addWidget(self.downButton)
|
||||||
|
self.audioLayout.addLayout(self.audioButtonsLayout)
|
||||||
|
self.songTabWidget.addTab(self.audioTab, u'')
|
||||||
|
# Last few bits
|
||||||
self.dialogLayout.addWidget(self.songTabWidget)
|
self.dialogLayout.addWidget(self.songTabWidget)
|
||||||
self.buttonBox = create_accept_reject_button_box(editSongDialog)
|
self.buttonBox = create_accept_reject_button_box(editSongDialog)
|
||||||
self.dialogLayout.addWidget(self.buttonBox)
|
self.dialogLayout.addWidget(self.buttonBox)
|
||||||
@ -305,6 +338,17 @@ class Ui_EditSongDialog(object):
|
|||||||
self.songTabWidget.indexOf(self.themeTab),
|
self.songTabWidget.indexOf(self.themeTab),
|
||||||
translate('SongsPlugin.EditSongForm',
|
translate('SongsPlugin.EditSongForm',
|
||||||
'Theme, Copyright Info && Comments'))
|
'Theme, Copyright Info && Comments'))
|
||||||
|
self.songTabWidget.setTabText(
|
||||||
|
self.songTabWidget.indexOf(self.audioTab),
|
||||||
|
translate('SongsPlugin.EditSongForm', 'Linked Audio'))
|
||||||
|
self.audioAddFromFileButton.setText(
|
||||||
|
translate('SongsPlugin.EditSongForm', 'Add &File(s)'))
|
||||||
|
self.audioAddFromMediaButton.setText(
|
||||||
|
translate('SongsPlugin.EditSongForm', 'Add &Media'))
|
||||||
|
self.audioRemoveButton.setText(
|
||||||
|
translate('SongsPlugin.EditSongForm', '&Remove'))
|
||||||
|
self.audioRemoveAllButton.setText(
|
||||||
|
translate('SongsPlugin.EditSongForm', 'Remove &All'))
|
||||||
|
|
||||||
def editSongDialogComboBox(parent, name):
|
def editSongDialogComboBox(parent, name):
|
||||||
"""
|
"""
|
||||||
|
@ -27,15 +27,18 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Receiver, translate
|
from openlp.core.lib import PluginStatus, Receiver, MediaType, translate
|
||||||
from openlp.core.lib.ui import UiStrings, add_widget_completer, \
|
from openlp.core.lib.ui import UiStrings, add_widget_completer, \
|
||||||
critical_error_message_box, find_and_set_in_combo_box
|
critical_error_message_box, find_and_set_in_combo_box
|
||||||
from openlp.plugins.songs.forms import EditVerseForm
|
from openlp.core.utils import AppLocation
|
||||||
|
from openlp.plugins.songs.forms import EditVerseForm, MediaFilesForm
|
||||||
from openlp.plugins.songs.lib import SongXML, VerseType, clean_song
|
from openlp.plugins.songs.lib import SongXML, VerseType, clean_song
|
||||||
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic
|
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile
|
||||||
from openlp.plugins.songs.lib.ui import SongStrings
|
from openlp.plugins.songs.lib.ui import SongStrings
|
||||||
from editsongdialog import Ui_EditSongDialog
|
from editsongdialog import Ui_EditSongDialog
|
||||||
|
|
||||||
@ -93,6 +96,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.mediaitem.plugin.renderer.themeManager.onAddTheme)
|
self.mediaitem.plugin.renderer.themeManager.onAddTheme)
|
||||||
QtCore.QObject.connect(self.maintenanceButton,
|
QtCore.QObject.connect(self.maintenanceButton,
|
||||||
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
|
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.audioAddFromFileButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'), self.onAudioAddFromFileButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.audioAddFromMediaButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'), self.onAudioAddFromMediaButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.audioRemoveButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'), self.onAudioRemoveButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.audioRemoveAllButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'), self.onAudioRemoveAllButtonClicked)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'theme_update_list'), self.loadThemes)
|
QtCore.SIGNAL(u'theme_update_list'), self.loadThemes)
|
||||||
self.previewButton = QtGui.QPushButton()
|
self.previewButton = QtGui.QPushButton()
|
||||||
@ -104,12 +115,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
QtCore.SIGNAL(u'clicked(QAbstractButton*)'), self.onPreview)
|
QtCore.SIGNAL(u'clicked(QAbstractButton*)'), self.onPreview)
|
||||||
# Create other objects and forms
|
# Create other objects and forms
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.verse_form = EditVerseForm(self)
|
self.verseForm = EditVerseForm(self)
|
||||||
|
self.mediaForm = MediaFilesForm(self)
|
||||||
self.initialise()
|
self.initialise()
|
||||||
self.authorsListView.setSortingEnabled(False)
|
self.authorsListView.setSortingEnabled(False)
|
||||||
self.authorsListView.setAlternatingRowColors(True)
|
self.authorsListView.setAlternatingRowColors(True)
|
||||||
self.topicsListView.setSortingEnabled(False)
|
self.topicsListView.setSortingEnabled(False)
|
||||||
self.topicsListView.setAlternatingRowColors(True)
|
self.topicsListView.setAlternatingRowColors(True)
|
||||||
|
self.audioListWidget.setAlternatingRowColors(True)
|
||||||
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
||||||
self.whitespace = re.compile(r'\W+', re.UNICODE)
|
self.whitespace = re.compile(r'\W+', re.UNICODE)
|
||||||
|
|
||||||
@ -161,6 +174,16 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.themes.append(theme)
|
self.themes.append(theme)
|
||||||
add_widget_completer(self.themes, self.themeComboBox)
|
add_widget_completer(self.themes, self.themeComboBox)
|
||||||
|
|
||||||
|
def loadMediaFiles(self):
|
||||||
|
self.audioAddFromMediaButton.setVisible(False)
|
||||||
|
for plugin in self.parent().pluginManager.plugins:
|
||||||
|
if plugin.name == u'media' and \
|
||||||
|
plugin.status == PluginStatus.Active:
|
||||||
|
self.audioAddFromMediaButton.setVisible(True)
|
||||||
|
self.mediaForm.populateFiles(
|
||||||
|
plugin.getMediaManagerItem().getList(MediaType.Audio))
|
||||||
|
break
|
||||||
|
|
||||||
def newSong(self):
|
def newSong(self):
|
||||||
log.debug(u'New Song')
|
log.debug(u'New Song')
|
||||||
self.song = None
|
self.song = None
|
||||||
@ -176,11 +199,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.verseListWidget.setRowCount(0)
|
self.verseListWidget.setRowCount(0)
|
||||||
self.authorsListView.clear()
|
self.authorsListView.clear()
|
||||||
self.topicsListView.clear()
|
self.topicsListView.clear()
|
||||||
|
self.audioListWidget.clear()
|
||||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
||||||
self.songBookNumberEdit.setText(u'')
|
self.songBookNumberEdit.setText(u'')
|
||||||
self.loadAuthors()
|
self.loadAuthors()
|
||||||
self.loadTopics()
|
self.loadTopics()
|
||||||
self.loadBooks()
|
self.loadBooks()
|
||||||
|
self.loadMediaFiles()
|
||||||
self.themeComboBox.setCurrentIndex(0)
|
self.themeComboBox.setCurrentIndex(0)
|
||||||
# it's a new song to preview is not possible
|
# it's a new song to preview is not possible
|
||||||
self.previewButton.setVisible(False)
|
self.previewButton.setVisible(False)
|
||||||
@ -201,6 +226,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.loadAuthors()
|
self.loadAuthors()
|
||||||
self.loadTopics()
|
self.loadTopics()
|
||||||
self.loadBooks()
|
self.loadBooks()
|
||||||
|
self.loadMediaFiles()
|
||||||
self.song = self.manager.get_object(Song, id)
|
self.song = self.manager.get_object(Song, id)
|
||||||
self.titleEdit.setText(self.song.title)
|
self.titleEdit.setText(self.song.title)
|
||||||
if self.song.alternate_title:
|
if self.song.alternate_title:
|
||||||
@ -303,6 +329,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
topic_name = QtGui.QListWidgetItem(unicode(topic.name))
|
topic_name = QtGui.QListWidgetItem(unicode(topic.name))
|
||||||
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
|
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
|
||||||
self.topicsListView.addItem(topic_name)
|
self.topicsListView.addItem(topic_name)
|
||||||
|
self.audioListWidget.clear()
|
||||||
|
for media in self.song.media_files:
|
||||||
|
media_file = QtGui.QListWidgetItem(os.path.split(media.file_name)[1])
|
||||||
|
media_file.setData(QtCore.Qt.UserRole, QtCore.QVariant(media.file_name))
|
||||||
|
self.audioListWidget.addItem(media_file)
|
||||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
||||||
# Hide or show the preview button.
|
# Hide or show the preview button.
|
||||||
self.previewButton.setVisible(preview)
|
self.previewButton.setVisible(preview)
|
||||||
@ -436,9 +467,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.verseDeleteButton.setEnabled(True)
|
self.verseDeleteButton.setEnabled(True)
|
||||||
|
|
||||||
def onVerseAddButtonClicked(self):
|
def onVerseAddButtonClicked(self):
|
||||||
self.verse_form.setVerse(u'', True)
|
self.verseForm.setVerse(u'', True)
|
||||||
if self.verse_form.exec_():
|
if self.verseForm.exec_():
|
||||||
after_text, verse_tag, verse_num = self.verse_form.getVerse()
|
after_text, verse_tag, verse_num = self.verseForm.getVerse()
|
||||||
verse_def = u'%s%s' % (verse_tag, verse_num)
|
verse_def = u'%s%s' % (verse_tag, verse_num)
|
||||||
item = QtGui.QTableWidgetItem(after_text)
|
item = QtGui.QTableWidgetItem(after_text)
|
||||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
||||||
@ -454,20 +485,21 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
if item:
|
if item:
|
||||||
tempText = item.text()
|
tempText = item.text()
|
||||||
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
|
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.verse_form.setVerse(tempText, True, verseId)
|
self.verseForm.setVerse(tempText, True, verseId)
|
||||||
if self.verse_form.exec_():
|
if self.verseForm.exec_():
|
||||||
after_text, verse_tag, verse_num = self.verse_form.getVerse()
|
after_text, verse_tag, verse_num = self.verseForm.getVerse()
|
||||||
verse_def = u'%s%s' % (verse_tag, verse_num)
|
verse_def = u'%s%s' % (verse_tag, verse_num)
|
||||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
||||||
item.setText(after_text)
|
item.setText(after_text)
|
||||||
# number of lines has change so repaint the list moving the data
|
# number of lines has changed, repaint the list moving the data
|
||||||
if len(tempText.split(u'\n')) != len(after_text.split(u'\n')):
|
if len(tempText.split(u'\n')) != len(after_text.split(u'\n')):
|
||||||
tempList = {}
|
tempList = {}
|
||||||
tempId = {}
|
tempId = {}
|
||||||
for row in range(0, self.verseListWidget.rowCount()):
|
for row in range(0, self.verseListWidget.rowCount()):
|
||||||
tempList[row] = self.verseListWidget.item(row, 0).text()
|
tempList[row] = self.verseListWidget.item(row, 0)\
|
||||||
tempId[row] = self.verseListWidget.item(row, 0).\
|
.text()
|
||||||
data(QtCore.Qt.UserRole)
|
tempId[row] = self.verseListWidget.item(row, 0)\
|
||||||
|
.data(QtCore.Qt.UserRole)
|
||||||
self.verseListWidget.clear()
|
self.verseListWidget.clear()
|
||||||
for row in range (0, len(tempList)):
|
for row in range (0, len(tempList)):
|
||||||
item = QtGui.QTableWidgetItem(tempList[row], 0)
|
item = QtGui.QTableWidgetItem(tempList[row], 0)
|
||||||
@ -486,12 +518,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
verse_list += u'---[%s:%s]---\n' % (verse_tag, verse_num)
|
verse_list += u'---[%s:%s]---\n' % (verse_tag, verse_num)
|
||||||
verse_list += item.text()
|
verse_list += item.text()
|
||||||
verse_list += u'\n'
|
verse_list += u'\n'
|
||||||
self.verse_form.setVerse(verse_list)
|
self.verseForm.setVerse(verse_list)
|
||||||
else:
|
else:
|
||||||
self.verse_form.setVerse(u'')
|
self.verseForm.setVerse(u'')
|
||||||
if not self.verse_form.exec_():
|
if not self.verseForm.exec_():
|
||||||
return
|
return
|
||||||
verse_list = self.verse_form.getVerseAll()
|
verse_list = self.verseForm.getVerseAll()
|
||||||
verse_list = unicode(verse_list.replace(u'\r\n', u'\n'))
|
verse_list = unicode(verse_list.replace(u'\r\n', u'\n'))
|
||||||
self.verseListWidget.clear()
|
self.verseListWidget.clear()
|
||||||
self.verseListWidget.setRowCount(0)
|
self.verseListWidget.setRowCount(0)
|
||||||
@ -670,6 +702,66 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.saveSong(True)
|
self.saveSong(True)
|
||||||
Receiver.send_message(u'songs_preview')
|
Receiver.send_message(u'songs_preview')
|
||||||
|
|
||||||
|
def onAudioAddFromFileButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Loads file(s) from the filesystem.
|
||||||
|
"""
|
||||||
|
filters = u'%s (*)' % UiStrings().AllFiles
|
||||||
|
filenames = QtGui.QFileDialog.getOpenFileNames(self,
|
||||||
|
translate('SongsPlugin.EditSongForm', 'Open File(s)'),
|
||||||
|
QtCore.QString(), filters)
|
||||||
|
for filename in filenames:
|
||||||
|
item = QtGui.QListWidgetItem(os.path.split(unicode(filename))[1])
|
||||||
|
item.setData(QtCore.Qt.UserRole, filename)
|
||||||
|
self.audioListWidget.addItem(item)
|
||||||
|
|
||||||
|
def onAudioAddFromMediaButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Loads file(s) from the media plugin.
|
||||||
|
"""
|
||||||
|
if self.mediaForm.exec_():
|
||||||
|
for filename in self.mediaForm.getSelectedFiles():
|
||||||
|
item = QtGui.QListWidgetItem(os.path.split(unicode(filename))[1])
|
||||||
|
item.setData(QtCore.Qt.UserRole, filename)
|
||||||
|
self.audioListWidget.addItem(item)
|
||||||
|
|
||||||
|
def onAudioRemoveButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Removes a file from the list.
|
||||||
|
"""
|
||||||
|
row = self.audioListWidget.currentRow()
|
||||||
|
if row == -1:
|
||||||
|
return
|
||||||
|
self.audioListWidget.takeItem(row)
|
||||||
|
|
||||||
|
def onAudioRemoveAllButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Removes all files from the list.
|
||||||
|
"""
|
||||||
|
self.audioListWidget.clear()
|
||||||
|
|
||||||
|
def onUpButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Moves a file up when the user clicks the up button on the audio tab.
|
||||||
|
"""
|
||||||
|
row = self.audioListWidget.currentRow()
|
||||||
|
if row <= 0:
|
||||||
|
return
|
||||||
|
item = self.audioListWidget.takeItem(row)
|
||||||
|
self.audioListWidget.insertItem(row - 1, item)
|
||||||
|
self.audioListWidget.setCurrentRow(row - 1)
|
||||||
|
|
||||||
|
def onDownButtonClicked(self):
|
||||||
|
"""
|
||||||
|
Moves a file down when the user clicks the up button on the audio tab.
|
||||||
|
"""
|
||||||
|
row = self.audioListWidget.currentRow()
|
||||||
|
if row == -1 or row > self.audioListWidget.count() - 1:
|
||||||
|
return
|
||||||
|
item = self.audioListWidget.takeItem(row)
|
||||||
|
self.audioListWidget.insertItem(row + 1, item)
|
||||||
|
self.audioListWidget.setCurrentRow(row + 1)
|
||||||
|
|
||||||
def clearCaches(self):
|
def clearCaches(self):
|
||||||
"""
|
"""
|
||||||
Free up autocompletion memory on dialog exit
|
Free up autocompletion memory on dialog exit
|
||||||
@ -744,18 +836,55 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.song.theme_name = None
|
self.song.theme_name = None
|
||||||
self._processLyrics()
|
self._processLyrics()
|
||||||
self.song.authors = []
|
self.song.authors = []
|
||||||
for row in range(self.authorsListView.count()):
|
for row in xrange(self.authorsListView.count()):
|
||||||
item = self.authorsListView.item(row)
|
item = self.authorsListView.item(row)
|
||||||
authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
self.song.authors.append(self.manager.get_object(Author, authorId))
|
self.song.authors.append(self.manager.get_object(Author, authorId))
|
||||||
self.song.topics = []
|
self.song.topics = []
|
||||||
for row in range(self.topicsListView.count()):
|
for row in xrange(self.topicsListView.count()):
|
||||||
item = self.topicsListView.item(row)
|
item = self.topicsListView.item(row)
|
||||||
topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
self.song.topics.append(self.manager.get_object(Topic, topicId))
|
self.song.topics.append(self.manager.get_object(Topic, topicId))
|
||||||
|
# Save the song here because we need a valid id for the audio files.
|
||||||
clean_song(self.manager, self.song)
|
clean_song(self.manager, self.song)
|
||||||
self.manager.save_object(self.song)
|
self.manager.save_object(self.song)
|
||||||
self.mediaitem.auto_select_id = self.song.id
|
audio_files = map(lambda a: a.file_name, self.song.media_files)
|
||||||
|
log.debug(audio_files)
|
||||||
|
save_path = os.path.join(
|
||||||
|
AppLocation.get_section_data_path(self.mediaitem.plugin.name),
|
||||||
|
'audio', str(self.song.id))
|
||||||
|
if not os.path.exists(save_path):
|
||||||
|
os.makedirs(save_path)
|
||||||
|
self.song.media_files = []
|
||||||
|
files = []
|
||||||
|
for row in xrange(self.audioListWidget.count()):
|
||||||
|
item = self.audioListWidget.item(row)
|
||||||
|
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
|
if not filename.startswith(save_path):
|
||||||
|
oldfile, filename = filename, os.path.join(save_path,
|
||||||
|
os.path.split(filename)[1])
|
||||||
|
shutil.copyfile(oldfile, filename)
|
||||||
|
files.append(filename)
|
||||||
|
media_file = MediaFile()
|
||||||
|
media_file.file_name = filename
|
||||||
|
media_file.type = u'audio'
|
||||||
|
media_file.weight = row
|
||||||
|
self.song.media_files.append(media_file)
|
||||||
|
for audio in audio_files:
|
||||||
|
if audio not in files:
|
||||||
|
try:
|
||||||
|
os.remove(audio)
|
||||||
|
except:
|
||||||
|
log.exception('Could not remove file: %s', audio)
|
||||||
|
pass
|
||||||
|
if not files:
|
||||||
|
try:
|
||||||
|
os.rmdir(save_path)
|
||||||
|
except OSError:
|
||||||
|
log.exception(u'Could not remove directory: %s', save_path)
|
||||||
|
clean_song(self.manager, self.song)
|
||||||
|
self.manager.save_object(self.song)
|
||||||
|
self.mediaitem.autoSelectId = self.song.id
|
||||||
|
|
||||||
def _processLyrics(self):
|
def _processLyrics(self):
|
||||||
"""
|
"""
|
||||||
@ -783,3 +912,4 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
except:
|
except:
|
||||||
log.exception(u'Problem processing song Lyrics \n%s',
|
log.exception(u'Problem processing song Lyrics \n%s',
|
||||||
sxml.dump_xml())
|
sxml.dump_xml())
|
||||||
|
|
||||||
|
75
openlp/plugins/songs/forms/mediafilesdialog.py
Normal file
75
openlp/plugins/songs/forms/mediafilesdialog.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2011 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
|
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
|
||||||
|
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
|
||||||
|
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||||
|
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
from openlp.core.lib import translate, build_icon
|
||||||
|
|
||||||
|
class Ui_MediaFilesDialog(object):
|
||||||
|
def setupUi(self, mediaFilesDialog):
|
||||||
|
mediaFilesDialog.setObjectName(u'mediaFilesDialog')
|
||||||
|
mediaFilesDialog.setWindowModality(QtCore.Qt.ApplicationModal)
|
||||||
|
mediaFilesDialog.resize(400, 300)
|
||||||
|
mediaFilesDialog.setModal(True)
|
||||||
|
mediaFilesDialog.setWindowIcon(
|
||||||
|
build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||||
|
self.filesVerticalLayout = QtGui.QVBoxLayout(mediaFilesDialog)
|
||||||
|
self.filesVerticalLayout.setSpacing(8)
|
||||||
|
self.filesVerticalLayout.setMargin(8)
|
||||||
|
self.filesVerticalLayout.setObjectName(u'filesVerticalLayout')
|
||||||
|
self.selectLabel = QtGui.QLabel(mediaFilesDialog)
|
||||||
|
self.selectLabel.setWordWrap(True)
|
||||||
|
self.selectLabel.setObjectName(u'selectLabel')
|
||||||
|
self.filesVerticalLayout.addWidget(self.selectLabel)
|
||||||
|
self.fileListWidget = QtGui.QListWidget(mediaFilesDialog)
|
||||||
|
self.fileListWidget.setAlternatingRowColors(True)
|
||||||
|
self.fileListWidget.setSelectionMode(
|
||||||
|
QtGui.QAbstractItemView.ExtendedSelection)
|
||||||
|
self.fileListWidget.setObjectName(u'fileListWidget')
|
||||||
|
self.filesVerticalLayout.addWidget(self.fileListWidget)
|
||||||
|
self.buttonBox = QtGui.QDialogButtonBox(mediaFilesDialog)
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.buttonBox.setStandardButtons(
|
||||||
|
QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
|
||||||
|
self.buttonBox.setObjectName(u'buttonBox')
|
||||||
|
self.filesVerticalLayout.addWidget(self.buttonBox)
|
||||||
|
|
||||||
|
self.retranslateUi(mediaFilesDialog)
|
||||||
|
QtCore.QObject.connect(self.buttonBox,
|
||||||
|
QtCore.SIGNAL(u'accepted()'), mediaFilesDialog.accept)
|
||||||
|
QtCore.QObject.connect(self.buttonBox,
|
||||||
|
QtCore.SIGNAL(u'rejected()'), mediaFilesDialog.reject)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(mediaFilesDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, mediaFilesDialog):
|
||||||
|
mediaFilesDialog.setWindowTitle(
|
||||||
|
translate('SongsPlugin.MediaFilesForm', 'Select Media File(s)'))
|
||||||
|
self.selectLabel.setText(
|
||||||
|
translate('SongsPlugin.MediaFilesForm', u'Select one or more '
|
||||||
|
'audio files from the list below, and click OK to import them '
|
||||||
|
'into this song.'))
|
||||||
|
|
57
openlp/plugins/songs/forms/mediafilesform.py
Normal file
57
openlp/plugins/songs/forms/mediafilesform.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2011 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
|
||||||
|
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
|
||||||
|
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
|
||||||
|
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||||
|
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
from mediafilesdialog import Ui_MediaFilesDialog
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class MediaFilesForm(QtGui.QDialog, Ui_MediaFilesDialog):
|
||||||
|
"""
|
||||||
|
Class to show a list of files from the
|
||||||
|
"""
|
||||||
|
log.info(u'%s MediaFilesForm loaded', __name__)
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
QtGui.QDialog.__init__(self)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
def populateFiles(self, files):
|
||||||
|
self.fileListWidget.clear()
|
||||||
|
for file in files:
|
||||||
|
item = QtGui.QListWidgetItem(os.path.split(file)[1])
|
||||||
|
item.setData(QtCore.Qt.UserRole, file)
|
||||||
|
self.fileListWidget.addItem(item)
|
||||||
|
|
||||||
|
def getSelectedFiles(self):
|
||||||
|
return map(lambda x: unicode(x.data(QtCore.Qt.UserRole).toString()),
|
||||||
|
self.fileListWidget.selectedItems())
|
||||||
|
|
@ -232,7 +232,8 @@ def init_schema(url):
|
|||||||
'authors': relation(Author, backref='songs',
|
'authors': relation(Author, backref='songs',
|
||||||
secondary=authors_songs_table, lazy=False),
|
secondary=authors_songs_table, lazy=False),
|
||||||
'book': relation(Book, backref='songs'),
|
'book': relation(Book, backref='songs'),
|
||||||
'media_files': relation(MediaFile, backref='songs'),
|
'media_files': relation(MediaFile, backref='songs',
|
||||||
|
order_by=media_files_table.c.weight),
|
||||||
'topics': relation(Topic, backref='songs',
|
'topics': relation(Topic, backref='songs',
|
||||||
secondary=songs_topics_table)
|
secondary=songs_topics_table)
|
||||||
})
|
})
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import locale
|
import locale
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from sqlalchemy.sql import or_
|
from sqlalchemy.sql import or_
|
||||||
@ -37,11 +39,12 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
|||||||
from openlp.core.lib.searchedit import SearchEdit
|
from openlp.core.lib.searchedit import SearchEdit
|
||||||
from openlp.core.lib.ui import UiStrings, context_menu_action, \
|
from openlp.core.lib.ui import UiStrings, context_menu_action, \
|
||||||
context_menu_separator
|
context_menu_separator
|
||||||
|
from openlp.core.utils import AppLocation
|
||||||
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
|
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
|
||||||
SongImportForm, SongExportForm
|
SongImportForm, SongExportForm
|
||||||
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
|
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
|
||||||
clean_string
|
clean_string
|
||||||
from openlp.plugins.songs.lib.db import Author, Song
|
from openlp.plugins.songs.lib.db import Author, Song, MediaFile
|
||||||
from openlp.plugins.songs.lib.ui import SongStrings
|
from openlp.plugins.songs.lib.ui import SongStrings
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -79,6 +82,22 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.quickPreviewAllowed = True
|
self.quickPreviewAllowed = True
|
||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
|
|
||||||
|
def _updateBackgroundAudio(self, song, item):
|
||||||
|
song.media_files = []
|
||||||
|
for i, bga in enumerate(item.background_audio):
|
||||||
|
dest_file = os.path.join(
|
||||||
|
AppLocation.get_section_data_path(self.plugin.name),
|
||||||
|
u'audio', str(song.id), os.path.split(bga)[1])
|
||||||
|
if not os.path.exists(os.path.split(dest_file)[0]):
|
||||||
|
os.makedirs(os.path.split(dest_file)[0])
|
||||||
|
shutil.copyfile(os.path.join(
|
||||||
|
AppLocation.get_section_data_path(
|
||||||
|
u'servicemanager'), bga),
|
||||||
|
dest_file)
|
||||||
|
song.media_files.append(MediaFile.populate(
|
||||||
|
weight=i, file_name=dest_file))
|
||||||
|
self.plugin.manager.save_object(song, True)
|
||||||
|
|
||||||
def addEndHeaderBar(self):
|
def addEndHeaderBar(self):
|
||||||
self.addToolbarSeparator()
|
self.addToolbarSeparator()
|
||||||
## Song Maintenance Button ##
|
## Song Maintenance Button ##
|
||||||
@ -210,7 +229,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
search_results = self.plugin.manager.get_all_objects(Song,
|
search_results = self.plugin.manager.get_all_objects(Song,
|
||||||
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
||||||
self.displayResultsSong(search_results)
|
self.displayResultsSong(search_results)
|
||||||
self.check_search_result()
|
self.checkSearchResult()
|
||||||
|
|
||||||
def searchEntire(self, search_keywords):
|
def searchEntire(self, search_keywords):
|
||||||
return self.plugin.manager.get_all_objects(Song,
|
return self.plugin.manager.get_all_objects(Song,
|
||||||
@ -244,7 +263,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def displayResultsSong(self, searchresults):
|
def displayResultsSong(self, searchresults):
|
||||||
log.debug(u'display results Song')
|
log.debug(u'display results Song')
|
||||||
self.save_auto_select_id()
|
self.saveAutoSelectId()
|
||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
# Sort the songs by its title considering language specific characters.
|
# Sort the songs by its title considering language specific characters.
|
||||||
# lower() is needed for windows!
|
# lower() is needed for windows!
|
||||||
@ -258,9 +277,9 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
||||||
self.listView.addItem(song_name)
|
self.listView.addItem(song_name)
|
||||||
# Auto-select the item if name has been set
|
# Auto-select the item if name has been set
|
||||||
if song.id == self.auto_select_id:
|
if song.id == self.autoSelectId:
|
||||||
self.listView.setCurrentItem(song_name)
|
self.listView.setCurrentItem(song_name)
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
|
|
||||||
def displayResultsAuthor(self, searchresults):
|
def displayResultsAuthor(self, searchresults):
|
||||||
log.debug(u'display results Author')
|
log.debug(u'display results Author')
|
||||||
@ -312,7 +331,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.edit_song_form.exec_()
|
self.edit_song_form.exec_()
|
||||||
self.onClearTextButtonClick()
|
self.onClearTextButtonClick()
|
||||||
self.onSelectionChange()
|
self.onSelectionChange()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
|
|
||||||
def onSongMaintenanceClick(self):
|
def onSongMaintenanceClick(self):
|
||||||
self.song_maintenance_form.exec_()
|
self.song_maintenance_form.exec_()
|
||||||
@ -335,9 +354,9 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
if valid:
|
if valid:
|
||||||
self.remoteSong = song_id
|
self.remoteSong = song_id
|
||||||
self.remoteTriggered = remote_type
|
self.remoteTriggered = remote_type
|
||||||
self.edit_song_form.loadSong(song_id, (remote_type == u'P'))
|
self.edit_song_form.loadSong(song_id, remote_type == u'P')
|
||||||
self.edit_song_form.exec_()
|
self.edit_song_form.exec_()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
self.onSongListLoad()
|
self.onSongListLoad()
|
||||||
|
|
||||||
def onEditClick(self):
|
def onEditClick(self):
|
||||||
@ -350,7 +369,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
|
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
self.edit_song_form.loadSong(item_id, False)
|
self.edit_song_form.loadSong(item_id, False)
|
||||||
self.edit_song_form.exec_()
|
self.edit_song_form.exec_()
|
||||||
self.auto_select_id = -1
|
self.autoSelectId = -1
|
||||||
self.onSongListLoad()
|
self.onSongListLoad()
|
||||||
self.editItem = None
|
self.editItem = None
|
||||||
|
|
||||||
@ -395,12 +414,12 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||||
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
||||||
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||||
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
||||||
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
||||||
song = self.plugin.manager.get_object(Song, item_id)
|
song = self.plugin.manager.get_object(Song, item_id)
|
||||||
service_item.theme = song.theme_name
|
service_item.theme = song.theme_name
|
||||||
service_item.edit_id = item_id
|
service_item.edit_id = item_id
|
||||||
@ -471,6 +490,10 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
service_item.data_string = {u'title': song.search_title,
|
service_item.data_string = {u'title': song.search_title,
|
||||||
u'authors': u', '.join(author_list)}
|
u'authors': u', '.join(author_list)}
|
||||||
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
||||||
|
# Add the audio file to the service item.
|
||||||
|
if len(song.media_files) > 0:
|
||||||
|
service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
|
||||||
|
service_item.background_audio = [m.file_name for m in song.media_files]
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def serviceLoad(self, item):
|
def serviceLoad(self, item):
|
||||||
@ -510,8 +533,15 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
add_song = False
|
add_song = False
|
||||||
editId = song.id
|
editId = song.id
|
||||||
break
|
break
|
||||||
|
# If there's any backing tracks, copy them over.
|
||||||
|
if len(item.background_audio) > 0:
|
||||||
|
self._updateBackgroundAudio(song, item)
|
||||||
if add_song and self.addSongFromService:
|
if add_song and self.addSongFromService:
|
||||||
editId = self.openLyrics.xml_to_song(item.xml_version)
|
song = self.openLyrics.xml_to_song(item.xml_version)
|
||||||
|
# If there's any backing tracks, copy them over.
|
||||||
|
if len(item.background_audio) > 0:
|
||||||
|
self._updateBackgroundAudio(song, item)
|
||||||
|
editId = song.id
|
||||||
self.onSearchTextButtonClick()
|
self.onSearchTextButtonClick()
|
||||||
else:
|
else:
|
||||||
# Make sure we temporary import formatting tags.
|
# Make sure we temporary import formatting tags.
|
||||||
|
@ -372,7 +372,7 @@ class OpenLyrics(object):
|
|||||||
self._process_topics(properties, song)
|
self._process_topics(properties, song)
|
||||||
clean_song(self.manager, song)
|
clean_song(self.manager, song)
|
||||||
self.manager.save_object(song)
|
self.manager.save_object(song)
|
||||||
return song.id
|
return song
|
||||||
|
|
||||||
def _add_text_to_element(self, tag, parent, text=None, label=None):
|
def _add_text_to_element(self, tag, parent, text=None, label=None):
|
||||||
if label:
|
if label:
|
||||||
|
95
resources/forms/mediafilesdialog.ui
Normal file
95
resources/forms/mediafilesdialog.ui
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MediaFilesDialog</class>
|
||||||
|
<widget class="QDialog" name="MediaFilesDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::ApplicationModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Select Media File(s)</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="filesVerticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="selectLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select one or more audio files from the list below, and click OK to import them into this song.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="fileListView">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../images/openlp-2.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>MediaFilesDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>MediaFilesDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2310
resources/i18n/hu.ts
2310
resources/i18n/hu.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1051
resources/i18n/ru.ts
1051
resources/i18n/ru.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user