forked from openlp/openlp
Songs can now have attached audio files, which are stored in services, and imported if the song needs to be imported.
bzr-revno: 1738 Fixes: https://launchpad.net/bugs/739770
This commit is contained in:
commit
3a87f3dff1
@ -27,3 +27,9 @@
|
||||
"""
|
||||
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 #
|
||||
###############################################################################
|
||||
|
||||
__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 sys
|
||||
@ -46,16 +51,11 @@ from openlp.core.ui import SplashScreen, ScreenList
|
||||
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
|
||||
get_application_version, DelayStartThread
|
||||
|
||||
|
||||
__all__ = [u'OpenLP', u'main']
|
||||
|
||||
|
||||
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"""
|
||||
QMainWindow::separator
|
||||
{
|
||||
|
@ -36,6 +36,13 @@ from PyQt4 import QtCore, QtGui
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MediaType(object):
|
||||
"""
|
||||
An enumeration class for types of media.
|
||||
"""
|
||||
Audio = 1
|
||||
Video = 2
|
||||
|
||||
def translate(context, text, comment=None,
|
||||
encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
|
||||
translate=QtCore.QCoreApplication.translate):
|
||||
@ -241,9 +248,7 @@ from settingsmanager import SettingsManager
|
||||
from plugin import PluginStatus, StringContent, Plugin
|
||||
from pluginmanager import PluginManager
|
||||
from settingstab import SettingsTab
|
||||
from serviceitem import ServiceItem
|
||||
from serviceitem import ServiceItemType
|
||||
from serviceitem import ItemCapabilities
|
||||
from serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
|
||||
from htmlbuilder import build_html, build_lyrics_format_css, \
|
||||
build_lyrics_outline_css
|
||||
from toolbar import OpenLPToolbar
|
||||
|
@ -82,7 +82,7 @@ def upgrade_db(url, upgrade):
|
||||
load_changes = True
|
||||
try:
|
||||
tables = upgrade.upgrade_setup(metadata)
|
||||
except SQLAlchemyError, DBAPIError:
|
||||
except (SQLAlchemyError, DBAPIError):
|
||||
load_changes = False
|
||||
metadata_table = Table(u'metadata', metadata,
|
||||
Column(u'key', types.Unicode(64), primary_key=True),
|
||||
@ -106,7 +106,7 @@ def upgrade_db(url, upgrade):
|
||||
getattr(upgrade, u'upgrade_%d' % version) \
|
||||
(session, metadata, tables)
|
||||
version_meta.value = unicode(version)
|
||||
except SQLAlchemyError, DBAPIError:
|
||||
except (SQLAlchemyError, DBAPIError):
|
||||
log.exception(u'Could not run database upgrade script '
|
||||
'"upgrade_%s", upgrade process has been halted.', version)
|
||||
break
|
||||
@ -213,7 +213,8 @@ class Manager(object):
|
||||
return
|
||||
try:
|
||||
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(
|
||||
translate('OpenLP.Manager', 'Database Error'),
|
||||
unicode(translate('OpenLP.Manager', 'OpenLP cannot load your '
|
||||
|
@ -111,7 +111,7 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
self.requiredIcons()
|
||||
self.setupUi()
|
||||
self.retranslateUi()
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name),
|
||||
self.serviceLoad)
|
||||
@ -506,7 +506,7 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
if QtCore.QSettings().value(u'advanced/single click preview',
|
||||
QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \
|
||||
and self.listView.selectedIndexes() \
|
||||
and self.auto_select_id == -1:
|
||||
and self.autoSelectId == -1:
|
||||
self.onPreviewClick(True)
|
||||
|
||||
def onPreviewClick(self, keepFocus=False):
|
||||
@ -626,7 +626,7 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
"""
|
||||
pass
|
||||
|
||||
def check_search_result(self):
|
||||
def checkSearchResult(self):
|
||||
"""
|
||||
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]
|
||||
return item_id
|
||||
|
||||
def save_auto_select_id(self):
|
||||
def saveAutoSelectId(self):
|
||||
"""
|
||||
Sorts out, what item to select after loading a list.
|
||||
"""
|
||||
# The item to select has not been set.
|
||||
if self.auto_select_id == -1:
|
||||
if self.autoSelectId == -1:
|
||||
item = self.listView.currentItem()
|
||||
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):
|
||||
"""
|
||||
|
@ -368,3 +368,4 @@ class Plugin(QtCore.QObject):
|
||||
after this has been set.
|
||||
"""
|
||||
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
||||
|
||||
|
@ -222,14 +222,14 @@ class Renderer(object):
|
||||
if item.is_capable(ItemCapabilities.NoLineBreaks):
|
||||
line_end = u' '
|
||||
# Bibles
|
||||
if item.is_capable(ItemCapabilities.AllowsWordSplit):
|
||||
if item.is_capable(ItemCapabilities.CanWordSplit):
|
||||
pages = self._paginate_slide_words(text.split(u'\n'), line_end)
|
||||
else:
|
||||
# Clean up line endings.
|
||||
lines = self._lines_split(text)
|
||||
pages = self._paginate_slide(lines, line_end)
|
||||
# Songs and Custom
|
||||
if item.is_capable(ItemCapabilities.AllowsVirtualSplit) and \
|
||||
if item.is_capable(ItemCapabilities.CanSoftBreak) and \
|
||||
len(pages) > 1 and u'[---]' in text:
|
||||
pages = []
|
||||
while True:
|
||||
|
@ -52,20 +52,21 @@ class ItemCapabilities(object):
|
||||
"""
|
||||
Provides an enumeration of a serviceitem's capabilities
|
||||
"""
|
||||
AllowsPreview = 1
|
||||
AllowsEdit = 2
|
||||
AllowsMaintain = 3
|
||||
CanPreview = 1
|
||||
CanEdit = 2
|
||||
CanMaintain = 3
|
||||
RequiresMedia = 4
|
||||
AllowsLoop = 5
|
||||
AllowsAdditions = 6
|
||||
CanLoop = 5
|
||||
CanAppend = 6
|
||||
NoLineBreaks = 7
|
||||
OnLoadUpdate = 8
|
||||
AddIfNewItem = 9
|
||||
ProvidesOwnDisplay = 10
|
||||
AllowsDetailedTitleDisplay = 11
|
||||
AllowsVariableStartTime = 12
|
||||
AllowsVirtualSplit = 13
|
||||
AllowsWordSplit = 14
|
||||
HasDetailedTitleDisplay = 11
|
||||
HasVariableStartTime = 12
|
||||
CanSoftBreak = 13
|
||||
CanWordSplit = 14
|
||||
HasBackgroundAudio = 15
|
||||
|
||||
|
||||
class ServiceItem(object):
|
||||
@ -116,6 +117,7 @@ class ServiceItem(object):
|
||||
self.media_length = 0
|
||||
self.from_service = False
|
||||
self.image_border = u'#000000'
|
||||
self.background_audio = []
|
||||
self._new_item()
|
||||
|
||||
def _new_item(self):
|
||||
@ -159,7 +161,7 @@ class ServiceItem(object):
|
||||
"""
|
||||
The render method is what generates the frames for the screen and
|
||||
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.
|
||||
"""
|
||||
log.debug(u'Render called')
|
||||
@ -272,7 +274,8 @@ class ServiceItem(object):
|
||||
u'xml_version': self.xml_version,
|
||||
u'start_time': self.start_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 = []
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
@ -320,6 +323,8 @@ class ServiceItem(object):
|
||||
self.end_time = header[u'end_time']
|
||||
if u'media_length' in header:
|
||||
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:
|
||||
for slide in serviceitem[u'serviceitem'][u'data']:
|
||||
self._raw_frames.append(slide)
|
||||
@ -341,7 +346,7 @@ class ServiceItem(object):
|
||||
if self.is_text():
|
||||
return self.title
|
||||
else:
|
||||
if ItemCapabilities.AllowsDetailedTitleDisplay in self.capabilities:
|
||||
if ItemCapabilities.HasDetailedTitleDisplay in self.capabilities:
|
||||
return self._raw_frames[0][u'title']
|
||||
elif len(self._raw_frames) > 1:
|
||||
return self.title
|
||||
@ -359,6 +364,8 @@ class ServiceItem(object):
|
||||
"""
|
||||
self._uuid = other._uuid
|
||||
self.notes = other.notes
|
||||
if self.is_capable(ItemCapabilities.HasBackgroundAudio):
|
||||
log.debug(self.background_audio)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
|
@ -62,6 +62,10 @@ class MainDisplay(QtGui.QGraphicsView):
|
||||
self.override = {}
|
||||
self.retranslateUi()
|
||||
self.mediaObject = None
|
||||
if live:
|
||||
self.audioPlayer = AudioPlayer(self)
|
||||
else:
|
||||
self.audioPlayer = None
|
||||
self.firstTime = True
|
||||
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
|
||||
@ -587,61 +591,76 @@ class AudioPlayer(QtCore.QObject):
|
||||
"""
|
||||
log.debug(u'AudioPlayer Initialisation started')
|
||||
QtCore.QObject.__init__(self, parent)
|
||||
self.message = None
|
||||
self.currentIndex = -1
|
||||
self.playlist = []
|
||||
self.mediaObject = Phonon.MediaObject()
|
||||
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
|
||||
Phonon.createPath(self.mediaObject, self.audioObject)
|
||||
QtCore.QObject.connect(self.mediaObject,
|
||||
QtCore.SIGNAL(u'aboutToFinish()'), self.onAboutToFinish)
|
||||
|
||||
def setup(self):
|
||||
"""
|
||||
Sets up the Audio Player for use
|
||||
"""
|
||||
log.debug(u'AudioPlayer Setup')
|
||||
|
||||
def close(self):
|
||||
def __del__(self):
|
||||
"""
|
||||
Shutting down so clean up connections
|
||||
"""
|
||||
self.onMediaStop()
|
||||
self.stop()
|
||||
for path in self.mediaObject.outputPaths():
|
||||
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)
|
||||
mfile = os.path.join(message[0].get_frame_path(),
|
||||
message[0].get_frame_title())
|
||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(mfile))
|
||||
self.onMediaPlay()
|
||||
self.currentIndex += 1
|
||||
if len(self.playlist) > self.currentIndex:
|
||||
self.mediaObject.enqueue(self.playlist[self.currentIndex])
|
||||
|
||||
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()
|
||||
|
||||
def onMediaPause(self):
|
||||
def pause(self):
|
||||
"""
|
||||
Pause the Audio
|
||||
"""
|
||||
log.debug(u'AudioPlayer Media paused by user')
|
||||
log.debug(u'AudioPlayer.pause() called')
|
||||
self.mediaObject.pause()
|
||||
|
||||
def onMediaStop(self):
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the Audio and clean up
|
||||
"""
|
||||
log.debug(u'AudioPlayer Media stopped by user')
|
||||
self.message = None
|
||||
log.debug(u'AudioPlayer.stop() called')
|
||||
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')
|
||||
self.mediaObject.clearQueue()
|
||||
if not isinstance(filenames, list):
|
||||
filenames = [filenames]
|
||||
for filename in filenames:
|
||||
self.playlist.append(Phonon.MediaSource(filename))
|
||||
|
||||
|
@ -28,6 +28,7 @@ import cgi
|
||||
import cPickle
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import zipfile
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -471,23 +472,34 @@ class ServiceManager(QtGui.QWidget):
|
||||
if not self.fileName():
|
||||
return self.saveFileAs()
|
||||
path_file_name = unicode(self.fileName())
|
||||
(path, file_name) = os.path.split(path_file_name)
|
||||
(basename, extension) = os.path.splitext(file_name)
|
||||
service_file_name = basename + '.osd'
|
||||
path, file_name = os.path.split(path_file_name)
|
||||
basename, extension = os.path.splitext(file_name)
|
||||
service_file_name = '%s.osd' % basename
|
||||
log.debug(u'ServiceManager.saveFile - %s' % path_file_name)
|
||||
SettingsManager.set_last_dir(
|
||||
self.mainwindow.servicemanagerSettingsSection,
|
||||
path)
|
||||
service = []
|
||||
write_list = []
|
||||
audio_files = []
|
||||
total_size = 0
|
||||
Receiver.send_message(u'cursor_busy')
|
||||
# Number of items + 1 to zip it
|
||||
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
|
||||
for item in self.serviceItems:
|
||||
self.mainwindow.incrementProgressBar()
|
||||
service.append({u'serviceitem':
|
||||
item[u'service_item'].get_service_repr()})
|
||||
service_item = 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():
|
||||
continue
|
||||
skipMissing = False
|
||||
@ -541,6 +553,8 @@ class ServiceManager(QtGui.QWidget):
|
||||
# Finally add all the listed media files.
|
||||
for path_from in write_list:
|
||||
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:
|
||||
log.exception(u'Failed to save service to disk')
|
||||
success = False
|
||||
@ -595,11 +609,12 @@ class ServiceManager(QtGui.QWidget):
|
||||
'The content encoding is not UTF-8.'))
|
||||
continue
|
||||
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile))
|
||||
filename_only = os.path.split(osfile)[1]
|
||||
zipinfo.filename = filename_only
|
||||
if not osfile.startswith(u'audio'):
|
||||
osfile = os.path.split(osfile)[1]
|
||||
zipinfo.filename = osfile
|
||||
zip.extract(zipinfo, self.servicePath)
|
||||
if filename_only.endswith(u'osd'):
|
||||
p_file = os.path.join(self.servicePath, filename_only)
|
||||
if osfile.endswith(u'osd'):
|
||||
p_file = os.path.join(self.servicePath, osfile)
|
||||
if 'p_file' in locals():
|
||||
Receiver.send_message(u'cursor_busy')
|
||||
fileTo = open(p_file, u'r')
|
||||
@ -630,10 +645,10 @@ class ServiceManager(QtGui.QWidget):
|
||||
'File is not a valid service.'))
|
||||
log.exception(u'File contains no service data')
|
||||
except (IOError, NameError, zipfile.BadZipfile):
|
||||
log.exception(u'Problem loading service file %s' % fileName)
|
||||
critical_error_message_box(
|
||||
message=translate('OpenLP.ServiceManager',
|
||||
'File could not be opened because it is corrupt.'))
|
||||
log.exception(u'Problem loading service file %s' % fileName)
|
||||
except zipfile.BadZipfile:
|
||||
if os.path.getsize(fileName) == 0:
|
||||
log.exception(u'Service file is zero sized: %s' % fileName)
|
||||
@ -682,16 +697,16 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.maintainAction.setVisible(False)
|
||||
self.notesAction.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:
|
||||
self.editAction.setVisible(True)
|
||||
if serviceItem[u'service_item']\
|
||||
.is_capable(ItemCapabilities.AllowsMaintain):
|
||||
.is_capable(ItemCapabilities.CanMaintain):
|
||||
self.maintainAction.setVisible(True)
|
||||
if item.parent() is None:
|
||||
self.notesAction.setVisible(True)
|
||||
if serviceItem[u'service_item']\
|
||||
.is_capable(ItemCapabilities.AllowsVariableStartTime):
|
||||
.is_capable(ItemCapabilities.HasVariableStartTime):
|
||||
self.timeAction.setVisible(True)
|
||||
self.themeMenu.menuAction().setVisible(False)
|
||||
# Set up the theme menu.
|
||||
@ -962,7 +977,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
(unicode(translate('OpenLP.ServiceManager', 'Notes')),
|
||||
cgi.escape(unicode(serviceitem.notes))))
|
||||
if item[u'service_item'] \
|
||||
.is_capable(ItemCapabilities.AllowsVariableStartTime):
|
||||
.is_capable(ItemCapabilities.HasVariableStartTime):
|
||||
tips.append(item[u'service_item'].get_media_time())
|
||||
treewidgetitem.setToolTip(0, u'<br>'.join(tips))
|
||||
treewidgetitem.setData(0, QtCore.Qt.UserRole,
|
||||
@ -998,6 +1013,8 @@ class ServiceManager(QtGui.QWidget):
|
||||
for file in os.listdir(self.servicePath):
|
||||
file_path = os.path.join(self.servicePath, file)
|
||||
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):
|
||||
"""
|
||||
@ -1196,7 +1213,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
item += 1
|
||||
if self.serviceItems and item < len(self.serviceItems) and \
|
||||
self.serviceItems[item][u'service_item'].is_capable(
|
||||
ItemCapabilities.AllowsPreview):
|
||||
ItemCapabilities.CanPreview):
|
||||
self.mainwindow.previewController.addServiceManagerItem(
|
||||
self.serviceItems[item][u'service_item'], 0)
|
||||
self.mainwindow.liveController.previewListWidget.setFocus()
|
||||
@ -1214,7 +1231,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
"""
|
||||
item = self.findServiceItem()[0]
|
||||
if self.serviceItems[item][u'service_item']\
|
||||
.is_capable(ItemCapabilities.AllowsEdit):
|
||||
.is_capable(ItemCapabilities.CanEdit):
|
||||
Receiver.send_message(u'%s_edit' %
|
||||
self.serviceItems[item][u'service_item'].name.lower(),
|
||||
u'L:%s' % self.serviceItems[item][u'service_item'].edit_id)
|
||||
@ -1297,7 +1314,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
serviceItem = self.serviceItems[pos]
|
||||
if (plugin == serviceItem[u'service_item'].name and
|
||||
serviceItem[u'service_item'].is_capable(
|
||||
ItemCapabilities.AllowsAdditions)):
|
||||
ItemCapabilities.CanAppend)):
|
||||
action = self.dndMenu.exec_(QtGui.QCursor.pos())
|
||||
# New action required
|
||||
if action == self.newAction:
|
||||
|
@ -256,6 +256,12 @@ class SlideController(QtGui.QWidget):
|
||||
self.songMenu.setMenu(QtGui.QMenu(
|
||||
translate('OpenLP.SlideController', 'Go To'), self.toolbar))
|
||||
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.
|
||||
self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
|
||||
self.volumeSlider.setTickInterval(1)
|
||||
@ -512,13 +518,13 @@ class SlideController(QtGui.QWidget):
|
||||
self.playSlidesOnce.setChecked(False)
|
||||
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png'))
|
||||
self.playSlidesLoop.setChecked(False)
|
||||
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
|
||||
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
|
||||
if item.is_text():
|
||||
if QtCore.QSettings().value(
|
||||
self.parent().songsSettingsSection + u'/display songbar',
|
||||
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
|
||||
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:
|
||||
self.toolbar.makeWidgetsVisible(self.loopList)
|
||||
if item.is_media():
|
||||
@ -538,7 +544,7 @@ class SlideController(QtGui.QWidget):
|
||||
self.toolbar.hide()
|
||||
self.mediabar.setVisible(False)
|
||||
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)
|
||||
elif item.is_media():
|
||||
self.toolbar.setVisible(False)
|
||||
@ -576,7 +582,7 @@ class SlideController(QtGui.QWidget):
|
||||
"""
|
||||
Replacement item following a remote edit
|
||||
"""
|
||||
if item.__eq__(self.serviceItem):
|
||||
if item == self.serviceItem:
|
||||
self._processItem(item, self.previewListWidget.currentRow())
|
||||
|
||||
def addServiceManagerItem(self, item, slideno):
|
||||
@ -586,15 +592,17 @@ class SlideController(QtGui.QWidget):
|
||||
Called by ServiceManager
|
||||
"""
|
||||
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:
|
||||
slideno = 0
|
||||
# If service item is the same as the current on only change slide
|
||||
if item.__eq__(self.serviceItem):
|
||||
self.__checkUpdateSelectedSlide(slideno)
|
||||
slidenum = 0
|
||||
# If service item is the same as the current one, only change slide
|
||||
if slideno >= 0 and item == self.serviceItem:
|
||||
self.__checkUpdateSelectedSlide(slidenum)
|
||||
self.slideSelected()
|
||||
return
|
||||
self._processItem(item, slideno)
|
||||
else:
|
||||
self._processItem(item, slidenum)
|
||||
|
||||
def _processItem(self, serviceItem, slideno):
|
||||
"""
|
||||
@ -618,6 +626,15 @@ class SlideController(QtGui.QWidget):
|
||||
self.previewListWidget.setColumnWidth(0, width)
|
||||
if self.isLive:
|
||||
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
|
||||
text = []
|
||||
for framenumber, frame in enumerate(self.serviceItem.get_frames()):
|
||||
@ -1097,6 +1114,17 @@ class SlideController(QtGui.QWidget):
|
||||
self.playSlidesLoop.setChecked(False)
|
||||
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):
|
||||
"""
|
||||
If the timer event is for this window select next slide
|
||||
|
@ -67,7 +67,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.hasSearch = True
|
||||
self.search_results = {}
|
||||
self.second_search_results = {}
|
||||
self.check_search_result()
|
||||
self.checkSearchResult()
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles)
|
||||
|
||||
@ -651,7 +651,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
elif self.search_results:
|
||||
self.displayResults(bible, second_bible)
|
||||
self.advancedSearchButton.setEnabled(True)
|
||||
self.check_search_result()
|
||||
self.checkSearchResult()
|
||||
Receiver.send_message(u'cursor_normal')
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
|
||||
@ -715,7 +715,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
elif self.search_results:
|
||||
self.displayResults(bible, second_bible)
|
||||
self.quickSearchButton.setEnabled(True)
|
||||
self.check_search_result()
|
||||
self.checkSearchResult()
|
||||
Receiver.send_message(u'cursor_normal')
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
|
||||
@ -863,9 +863,9 @@ class BibleMediaItem(MediaManagerItem):
|
||||
not second_bible:
|
||||
# Split the line but do not replace line breaks in renderer.
|
||||
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||
service_item.add_capability(ItemCapabilities.AllowsWordSplit)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanWordSplit)
|
||||
# Service Item: Title
|
||||
service_item.title = u', '.join(raw_title)
|
||||
# Service Item: Theme
|
||||
|
@ -135,7 +135,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
self.customSlide.credits = unicode(self.creditEdit.text())
|
||||
self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
|
||||
success = self.manager.save_object(self.customSlide)
|
||||
self.mediaitem.auto_select_id = self.customSlide.id
|
||||
self.mediaitem.autoSelectId = self.customSlide.id
|
||||
return success
|
||||
|
||||
def onUpButtonClicked(self):
|
||||
|
@ -132,7 +132,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
|
||||
def loadList(self, custom_slides):
|
||||
# Sort out what custom we want to select after loading the list.
|
||||
self.save_auto_select_id()
|
||||
self.saveAutoSelectId()
|
||||
self.listView.clear()
|
||||
# Sort the customs by its title considering language specific
|
||||
# characters. lower() is needed for windows!
|
||||
@ -144,9 +144,9 @@ class CustomMediaItem(MediaManagerItem):
|
||||
QtCore.Qt.UserRole, QtCore.QVariant(custom_slide.id))
|
||||
self.listView.addItem(custom_name)
|
||||
# Auto-select the custom.
|
||||
if custom_slide.id == self.auto_select_id:
|
||||
if custom_slide.id == self.autoSelectId:
|
||||
self.listView.setCurrentItem(custom_name)
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
# Called to redisplay the custom list screen edith from a search
|
||||
# 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.
|
||||
@ -180,7 +180,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
self.remoteTriggered = remote_type
|
||||
self.edit_custom_form.loadCustom(custom_id, (remote_type == u'P'))
|
||||
self.edit_custom_form.exec_()
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
self.onSearchTextButtonClick()
|
||||
|
||||
def onEditClick(self):
|
||||
@ -192,7 +192,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
self.edit_custom_form.loadCustom(item_id, False)
|
||||
self.edit_custom_form.exec_()
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
self.onSearchTextButtonClick()
|
||||
|
||||
def onDeleteClick(self):
|
||||
@ -227,10 +227,10 @@ class CustomMediaItem(MediaManagerItem):
|
||||
slide = None
|
||||
theme = None
|
||||
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
|
||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
||||
customSlide = self.plugin.manager.get_object(CustomSlide, item_id)
|
||||
title = customSlide.title
|
||||
credit = customSlide.credits
|
||||
@ -273,7 +273,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
CustomSlide.theme_name.like(u'%' + self.whitespace.sub(u' ',
|
||||
search_keywords) + u'%'), order_by_ref=CustomSlide.title)
|
||||
self.loadList(search_results)
|
||||
self.check_search_result()
|
||||
self.checkSearchResult()
|
||||
|
||||
def onSearchTextEditChanged(self, text):
|
||||
"""
|
||||
|
@ -149,10 +149,10 @@ class ImageMediaItem(MediaManagerItem):
|
||||
if not items:
|
||||
return False
|
||||
service_item.title = unicode(self.plugin.nameStrings[u'plural'])
|
||||
service_item.add_capability(ItemCapabilities.AllowsMaintain)
|
||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||
service_item.add_capability(ItemCapabilities.AllowsAdditions)
|
||||
service_item.add_capability(ItemCapabilities.CanMaintain)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanAppend)
|
||||
# force a nonexistent theme
|
||||
service_item.theme = -1
|
||||
missing_items = []
|
||||
|
@ -31,11 +31,11 @@ import os
|
||||
import locale
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
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 PyQt4.phonon import Phonon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -48,9 +48,9 @@ class MediaMediaItem(MediaManagerItem):
|
||||
log.info(u'%s MediaMediaItem loaded', __name__)
|
||||
|
||||
def __init__(self, parent, plugin, icon):
|
||||
self.IconPath = u'images/image'
|
||||
self.iconPath = u'images/image'
|
||||
self.background = False
|
||||
self.PreviewFunction = CLAPPERBOARD
|
||||
self.previewFunction = CLAPPERBOARD
|
||||
MediaManagerItem.__init__(self, parent, plugin, icon)
|
||||
self.singleServiceItem = False
|
||||
self.hasSearch = True
|
||||
@ -139,8 +139,8 @@ class MediaMediaItem(MediaManagerItem):
|
||||
# File is no longer present
|
||||
critical_error_message_box(
|
||||
translate('MediaPlugin.MediaItem', 'Missing Media File'),
|
||||
unicode(translate('MediaPlugin.MediaItem',
|
||||
'The file %s no longer exists.')) % filename)
|
||||
unicode(translate('MediaPlugin.MediaItem',
|
||||
'The file %s no longer exists.')) % filename)
|
||||
return False
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
@ -156,13 +156,16 @@ class MediaMediaItem(MediaManagerItem):
|
||||
or self.mediaObject.currentSource().type() \
|
||||
== Phonon.MediaSource.Invalid:
|
||||
self.mediaObject.stop()
|
||||
critical_error_message_box(UiStrings().UnsupportedFile,
|
||||
UiStrings().UnsupportedFile)
|
||||
critical_error_message_box(
|
||||
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
|
||||
self.mediaObject.stop()
|
||||
service_item.media_length = self.mediaObject.totalTime() / 1000
|
||||
service_item.add_capability(
|
||||
ItemCapabilities.AllowsVariableStartTime)
|
||||
ItemCapabilities.HasVariableStartTime)
|
||||
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
|
||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||
# force a non-existent theme
|
||||
@ -217,6 +220,19 @@ class MediaMediaItem(MediaManagerItem):
|
||||
item_name.setToolTip(track)
|
||||
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):
|
||||
log.debug(u'CreatePhonon')
|
||||
if not self.mediaObject:
|
||||
|
@ -248,7 +248,7 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
service_item.title = unicode(self.displayTypeComboBox.currentText())
|
||||
service_item.shortname = unicode(self.displayTypeComboBox.currentText())
|
||||
service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay)
|
||||
service_item.add_capability(ItemCapabilities.AllowsDetailedTitleDisplay)
|
||||
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
|
||||
shortname = service_item.shortname
|
||||
if shortname:
|
||||
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 mediafilesform import MediaFilesForm
|
||||
from authorsform import AuthorsForm
|
||||
from topicsform import TopicsForm
|
||||
from songbookform import SongBookForm
|
||||
|
@ -28,7 +28,8 @@
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
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
|
||||
|
||||
class Ui_EditSongDialog(object):
|
||||
@ -36,9 +37,11 @@ class Ui_EditSongDialog(object):
|
||||
editSongDialog.setObjectName(u'editSongDialog')
|
||||
editSongDialog.resize(650, 400)
|
||||
editSongDialog.setWindowIcon(
|
||||
build_icon(u':/icon/openlp.org-icon-32.bmp'))
|
||||
build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||
editSongDialog.setModal(True)
|
||||
self.dialogLayout = QtGui.QVBoxLayout(editSongDialog)
|
||||
self.dialogLayout.setSpacing(8)
|
||||
self.dialogLayout.setContentsMargins(8, 8, 8, 8)
|
||||
self.dialogLayout.setObjectName(u'dialogLayout')
|
||||
self.songTabWidget = QtGui.QTabWidget(editSongDialog)
|
||||
self.songTabWidget.setObjectName(u'songTabWidget')
|
||||
@ -246,6 +249,36 @@ class Ui_EditSongDialog(object):
|
||||
self.commentsLayout.addWidget(self.commentsEdit)
|
||||
self.themeTabLayout.addWidget(self.commentsGroupBox)
|
||||
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.buttonBox = create_accept_reject_button_box(editSongDialog)
|
||||
self.dialogLayout.addWidget(self.buttonBox)
|
||||
@ -305,6 +338,17 @@ class Ui_EditSongDialog(object):
|
||||
self.songTabWidget.indexOf(self.themeTab),
|
||||
translate('SongsPlugin.EditSongForm',
|
||||
'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):
|
||||
"""
|
||||
|
@ -27,15 +27,18 @@
|
||||
|
||||
import logging
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
|
||||
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, \
|
||||
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.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 editsongdialog import Ui_EditSongDialog
|
||||
|
||||
@ -93,6 +96,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.mediaitem.plugin.renderer.themeManager.onAddTheme)
|
||||
QtCore.QObject.connect(self.maintenanceButton,
|
||||
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.SIGNAL(u'theme_update_list'), self.loadThemes)
|
||||
self.previewButton = QtGui.QPushButton()
|
||||
@ -104,12 +115,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
QtCore.SIGNAL(u'clicked(QAbstractButton*)'), self.onPreview)
|
||||
# Create other objects and forms
|
||||
self.manager = manager
|
||||
self.verse_form = EditVerseForm(self)
|
||||
self.verseForm = EditVerseForm(self)
|
||||
self.mediaForm = MediaFilesForm(self)
|
||||
self.initialise()
|
||||
self.authorsListView.setSortingEnabled(False)
|
||||
self.authorsListView.setAlternatingRowColors(True)
|
||||
self.topicsListView.setSortingEnabled(False)
|
||||
self.topicsListView.setAlternatingRowColors(True)
|
||||
self.audioListWidget.setAlternatingRowColors(True)
|
||||
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
||||
self.whitespace = re.compile(r'\W+', re.UNICODE)
|
||||
|
||||
@ -161,6 +174,16 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.themes.append(theme)
|
||||
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):
|
||||
log.debug(u'New Song')
|
||||
self.song = None
|
||||
@ -176,11 +199,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.verseListWidget.setRowCount(0)
|
||||
self.authorsListView.clear()
|
||||
self.topicsListView.clear()
|
||||
self.audioListWidget.clear()
|
||||
self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason)
|
||||
self.songBookNumberEdit.setText(u'')
|
||||
self.loadAuthors()
|
||||
self.loadTopics()
|
||||
self.loadBooks()
|
||||
self.loadMediaFiles()
|
||||
self.themeComboBox.setCurrentIndex(0)
|
||||
# it's a new song to preview is not possible
|
||||
self.previewButton.setVisible(False)
|
||||
@ -201,6 +226,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.loadAuthors()
|
||||
self.loadTopics()
|
||||
self.loadBooks()
|
||||
self.loadMediaFiles()
|
||||
self.song = self.manager.get_object(Song, id)
|
||||
self.titleEdit.setText(self.song.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.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
|
||||
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)
|
||||
# Hide or show the preview button.
|
||||
self.previewButton.setVisible(preview)
|
||||
@ -436,9 +467,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.verseDeleteButton.setEnabled(True)
|
||||
|
||||
def onVerseAddButtonClicked(self):
|
||||
self.verse_form.setVerse(u'', True)
|
||||
if self.verse_form.exec_():
|
||||
after_text, verse_tag, verse_num = self.verse_form.getVerse()
|
||||
self.verseForm.setVerse(u'', True)
|
||||
if self.verseForm.exec_():
|
||||
after_text, verse_tag, verse_num = self.verseForm.getVerse()
|
||||
verse_def = u'%s%s' % (verse_tag, verse_num)
|
||||
item = QtGui.QTableWidgetItem(after_text)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
||||
@ -454,20 +485,21 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
if item:
|
||||
tempText = item.text()
|
||||
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||
self.verse_form.setVerse(tempText, True, verseId)
|
||||
if self.verse_form.exec_():
|
||||
after_text, verse_tag, verse_num = self.verse_form.getVerse()
|
||||
self.verseForm.setVerse(tempText, True, verseId)
|
||||
if self.verseForm.exec_():
|
||||
after_text, verse_tag, verse_num = self.verseForm.getVerse()
|
||||
verse_def = u'%s%s' % (verse_tag, verse_num)
|
||||
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
|
||||
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')):
|
||||
tempList = {}
|
||||
tempId = {}
|
||||
for row in range(0, self.verseListWidget.rowCount()):
|
||||
tempList[row] = self.verseListWidget.item(row, 0).text()
|
||||
tempId[row] = self.verseListWidget.item(row, 0).\
|
||||
data(QtCore.Qt.UserRole)
|
||||
tempList[row] = self.verseListWidget.item(row, 0)\
|
||||
.text()
|
||||
tempId[row] = self.verseListWidget.item(row, 0)\
|
||||
.data(QtCore.Qt.UserRole)
|
||||
self.verseListWidget.clear()
|
||||
for row in range (0, len(tempList)):
|
||||
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 += item.text()
|
||||
verse_list += u'\n'
|
||||
self.verse_form.setVerse(verse_list)
|
||||
self.verseForm.setVerse(verse_list)
|
||||
else:
|
||||
self.verse_form.setVerse(u'')
|
||||
if not self.verse_form.exec_():
|
||||
self.verseForm.setVerse(u'')
|
||||
if not self.verseForm.exec_():
|
||||
return
|
||||
verse_list = self.verse_form.getVerseAll()
|
||||
verse_list = self.verseForm.getVerseAll()
|
||||
verse_list = unicode(verse_list.replace(u'\r\n', u'\n'))
|
||||
self.verseListWidget.clear()
|
||||
self.verseListWidget.setRowCount(0)
|
||||
@ -670,6 +702,66 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.saveSong(True)
|
||||
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):
|
||||
"""
|
||||
Free up autocompletion memory on dialog exit
|
||||
@ -744,18 +836,55 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
self.song.theme_name = None
|
||||
self._processLyrics()
|
||||
self.song.authors = []
|
||||
for row in range(self.authorsListView.count()):
|
||||
for row in xrange(self.authorsListView.count()):
|
||||
item = self.authorsListView.item(row)
|
||||
authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
self.song.authors.append(self.manager.get_object(Author, authorId))
|
||||
self.song.topics = []
|
||||
for row in range(self.topicsListView.count()):
|
||||
for row in xrange(self.topicsListView.count()):
|
||||
item = self.topicsListView.item(row)
|
||||
topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
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)
|
||||
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):
|
||||
"""
|
||||
@ -783,3 +912,4 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
except:
|
||||
log.exception(u'Problem processing song Lyrics \n%s',
|
||||
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',
|
||||
secondary=authors_songs_table, lazy=False),
|
||||
'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',
|
||||
secondary=songs_topics_table)
|
||||
})
|
||||
|
@ -28,6 +28,8 @@
|
||||
import logging
|
||||
import locale
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
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.ui import UiStrings, context_menu_action, \
|
||||
context_menu_separator
|
||||
from openlp.core.utils import AppLocation
|
||||
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
|
||||
SongImportForm, SongExportForm
|
||||
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
|
||||
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
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -79,6 +82,22 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.quickPreviewAllowed = 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):
|
||||
self.addToolbarSeparator()
|
||||
## Song Maintenance Button ##
|
||||
@ -210,7 +229,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
search_results = self.plugin.manager.get_all_objects(Song,
|
||||
Song.theme_name.like(u'%' + search_keywords + u'%'))
|
||||
self.displayResultsSong(search_results)
|
||||
self.check_search_result()
|
||||
self.checkSearchResult()
|
||||
|
||||
def searchEntire(self, search_keywords):
|
||||
return self.plugin.manager.get_all_objects(Song,
|
||||
@ -244,7 +263,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
|
||||
def displayResultsSong(self, searchresults):
|
||||
log.debug(u'display results Song')
|
||||
self.save_auto_select_id()
|
||||
self.saveAutoSelectId()
|
||||
self.listView.clear()
|
||||
# Sort the songs by its title considering language specific characters.
|
||||
# lower() is needed for windows!
|
||||
@ -258,9 +277,9 @@ class SongMediaItem(MediaManagerItem):
|
||||
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
||||
self.listView.addItem(song_name)
|
||||
# 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.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
|
||||
def displayResultsAuthor(self, searchresults):
|
||||
log.debug(u'display results Author')
|
||||
@ -312,7 +331,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
self.edit_song_form.exec_()
|
||||
self.onClearTextButtonClick()
|
||||
self.onSelectionChange()
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
|
||||
def onSongMaintenanceClick(self):
|
||||
self.song_maintenance_form.exec_()
|
||||
@ -335,9 +354,9 @@ class SongMediaItem(MediaManagerItem):
|
||||
if valid:
|
||||
self.remoteSong = song_id
|
||||
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.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
self.onSongListLoad()
|
||||
|
||||
def onEditClick(self):
|
||||
@ -350,7 +369,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||
self.edit_song_form.loadSong(item_id, False)
|
||||
self.edit_song_form.exec_()
|
||||
self.auto_select_id = -1
|
||||
self.autoSelectId = -1
|
||||
self.onSongListLoad()
|
||||
self.editItem = None
|
||||
|
||||
@ -395,12 +414,12 @@ class SongMediaItem(MediaManagerItem):
|
||||
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
||||
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanEdit)
|
||||
service_item.add_capability(ItemCapabilities.CanPreview)
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
||||
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)
|
||||
service_item.theme = song.theme_name
|
||||
service_item.edit_id = item_id
|
||||
@ -471,6 +490,10 @@ class SongMediaItem(MediaManagerItem):
|
||||
service_item.data_string = {u'title': song.search_title,
|
||||
u'authors': u', '.join(author_list)}
|
||||
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
|
||||
|
||||
def serviceLoad(self, item):
|
||||
@ -510,8 +533,15 @@ class SongMediaItem(MediaManagerItem):
|
||||
add_song = False
|
||||
editId = song.id
|
||||
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:
|
||||
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()
|
||||
# Update service with correct song id.
|
||||
if editId:
|
||||
|
@ -343,7 +343,7 @@ class OpenLyrics(object):
|
||||
self._process_topics(properties, song)
|
||||
clean_song(self.manager, song)
|
||||
self.manager.save_object(song)
|
||||
return song.id
|
||||
return song
|
||||
|
||||
def _add_text_to_element(self, tag, parent, text=None, label=None):
|
||||
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>
|
Loading…
Reference in New Issue
Block a user