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
|
||||
"""
|
||||
|
||||
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
|
||||
@ -221,7 +221,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):
|
||||
"""
|
||||
|
@ -135,6 +135,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||
"""
|
||||
Determine the next page in the Wizard to go to.
|
||||
"""
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
if self.currentId() == FirstTimePage.Plugins:
|
||||
if not self.webAccess:
|
||||
return FirstTimePage.NoInternet
|
||||
@ -175,9 +176,12 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||
elif pageId == FirstTimePage.Progress:
|
||||
Receiver.send_message(u'cursor_busy')
|
||||
self._preWizard()
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
self._performWizard()
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
self._postWizard()
|
||||
Receiver.send_message(u'cursor_normal')
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
|
||||
def updateScreenListCombo(self):
|
||||
"""
|
||||
@ -219,6 +223,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||
Prepare the UI for the process.
|
||||
"""
|
||||
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
|
||||
for i in xrange(self.songsListWidget.count()):
|
||||
item = self.songsListWidget.item(i)
|
||||
@ -242,7 +248,6 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
|
||||
filename = item.data(QtCore.Qt.UserRole).toString()
|
||||
size = self._getFileSize(u'%s%s' % (self.web, filename))
|
||||
self.max_progress += size
|
||||
self.finishButton.setVisible(False)
|
||||
if self.max_progress:
|
||||
# Add on 2 for plugins status setting plus a "finished" point.
|
||||
self.max_progress = self.max_progress + 2
|
||||
|
@ -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)
|
||||
@ -518,7 +524,7 @@ class SlideController(QtGui.QWidget):
|
||||
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()
|
||||
else:
|
||||
# Make sure we temporary import formatting tags.
|
||||
|
@ -372,7 +372,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>
|
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