Merge with lp:~raoul-snyman/openlp/bug-845692 to forestall merge conflicts.

This commit is contained in:
M2j 2012-03-05 11:09:07 +01:00
commit 9aaafdf108
13 changed files with 234 additions and 87 deletions

View File

@ -199,6 +199,10 @@ class Manager(object):
urlquote(unicode(settings.value(u'db password').toString())), urlquote(unicode(settings.value(u'db password').toString())),
urlquote(unicode(settings.value(u'db hostname').toString())), urlquote(unicode(settings.value(u'db hostname').toString())),
urlquote(unicode(settings.value(u'db database').toString()))) urlquote(unicode(settings.value(u'db database').toString())))
if db_type == u'mysql':
db_encoding = unicode(
settings.value(u'db encoding', u'utf8').toString())
self.db_url += u'?charset=%s' % urlquote(db_encoding)
settings.endGroup() settings.endGroup()
if upgrade_mod: if upgrade_mod:
db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod)

View File

@ -93,6 +93,7 @@ class UiStrings(object):
self.New = translate('OpenLP.Ui', 'New') self.New = translate('OpenLP.Ui', 'New')
self.NewService = translate('OpenLP.Ui', 'New Service') self.NewService = translate('OpenLP.Ui', 'New Service')
self.NewTheme = translate('OpenLP.Ui', 'New Theme') self.NewTheme = translate('OpenLP.Ui', 'New Theme')
self.NextTrack = translate('OpenLP.Ui', 'Next Track')
self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular') self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular')
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural') self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular') self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
@ -322,8 +323,7 @@ def create_action(parent, name, **kwargs):
A QList<QKeySequence> (or a list of strings) which are set as shortcuts. A QList<QKeySequence> (or a list of strings) which are set as shortcuts.
``context`` ``context``
A context for the shortcut execution (only will be set together with A context for the shortcut execution.
``shortcuts``).
``category`` ``category``
A category the action should be listed in the shortcut dialog. A category the action should be listed in the shortcut dialog.
@ -354,8 +354,8 @@ def create_action(parent, name, **kwargs):
action.setData(QtCore.QVariant(kwargs.pop(u'data'))) action.setData(QtCore.QVariant(kwargs.pop(u'data')))
if kwargs.get(u'shortcuts'): if kwargs.get(u'shortcuts'):
action.setShortcuts(kwargs.pop(u'shortcuts')) action.setShortcuts(kwargs.pop(u'shortcuts'))
if kwargs.get(u'context') is not None: if u'context' in kwargs:
action.setShortcutContext(kwargs.pop(u'context')) action.setShortcutContext(kwargs.pop(u'context'))
if kwargs.get(u'category'): if kwargs.get(u'category'):
action_list = ActionList.get_instance() action_list = ActionList.get_instance()
action_list.add_action(action, unicode(kwargs.pop(u'category'))) action_list.add_action(action, unicode(kwargs.pop(u'category')))
@ -364,7 +364,7 @@ def create_action(parent, name, **kwargs):
kwargs.pop(u'triggers')) kwargs.pop(u'triggers'))
for key in kwargs.keys(): for key in kwargs.keys():
if key not in [u'text', u'icon', u'tooltip', u'statustip', u'checked', if key not in [u'text', u'icon', u'tooltip', u'statustip', u'checked',
u'shortcuts', u'context', u'category', u'triggers']: u'shortcuts', u'category', u'triggers']:
log.warn(u'Parameter %s was not consumed in create_action().', key) log.warn(u'Parameter %s was not consumed in create_action().', key)
return action return action

View File

@ -175,6 +175,9 @@ class GeneralTab(SettingsTab):
self.startPausedCheckBox = QtGui.QCheckBox(self.audioGroupBox) self.startPausedCheckBox = QtGui.QCheckBox(self.audioGroupBox)
self.startPausedCheckBox.setObjectName(u'startPausedCheckBox') self.startPausedCheckBox.setObjectName(u'startPausedCheckBox')
self.audioLayout.addWidget(self.startPausedCheckBox) self.audioLayout.addWidget(self.startPausedCheckBox)
self.repeatListCheckBox = QtGui.QCheckBox(self.audioGroupBox)
self.repeatListCheckBox.setObjectName(u'repeatListCheckBox')
self.audioLayout.addWidget(self.repeatListCheckBox)
self.rightLayout.addWidget(self.audioGroupBox) self.rightLayout.addWidget(self.audioGroupBox)
self.rightLayout.addStretch() self.rightLayout.addStretch()
# Signals and slots # Signals and slots
@ -251,6 +254,8 @@ class GeneralTab(SettingsTab):
translate('OpenLP.GeneralTab', 'Background Audio')) translate('OpenLP.GeneralTab', 'Background Audio'))
self.startPausedCheckBox.setText( self.startPausedCheckBox.setText(
translate('OpenLP.GeneralTab', 'Start background audio paused')) translate('OpenLP.GeneralTab', 'Start background audio paused'))
self.repeatListCheckBox.setText(
translate('OpenLP.GeneralTab', 'Repeat track list'))
def load(self): def load(self):
""" """
@ -298,6 +303,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.screens.current[u'size'].width())).toInt()[0]) QtCore.QVariant(self.screens.current[u'size'].width())).toInt()[0])
self.startPausedCheckBox.setChecked(settings.value( self.startPausedCheckBox.setChecked(settings.value(
u'audio start paused', QtCore.QVariant(True)).toBool()) u'audio start paused', QtCore.QVariant(True)).toBool())
self.repeatListCheckBox.setChecked(settings.value(
u'audio repeat list', QtCore.QVariant(False)).toBool())
settings.endGroup() settings.endGroup()
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked()) self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked()) self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
@ -350,7 +357,9 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.overrideCheckBox.isChecked())) QtCore.QVariant(self.overrideCheckBox.isChecked()))
settings.setValue(u'audio start paused', settings.setValue(u'audio start paused',
QtCore.QVariant(self.startPausedCheckBox.isChecked())) QtCore.QVariant(self.startPausedCheckBox.isChecked()))
settings.endGroup() settings.setValue(u'audio repeat list',
QtCore.QVariant(self.repeatListCheckBox.isChecked()))
settings.endGroup()
# On save update the screens as well # On save update the screens as well
self.postSetUp(True) self.postSetUp(True)

View File

@ -30,7 +30,6 @@ and play multimedia within OpenLP.
""" """
import cgi import cgi
import logging import logging
import os
import sys import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
@ -136,12 +135,12 @@ class MainDisplay(Display):
QtCore.Qt.WindowStaysOnTopHint QtCore.Qt.WindowStaysOnTopHint
if QtCore.QSettings().value(u'advanced/x11 bypass wm', if QtCore.QSettings().value(u'advanced/x11 bypass wm',
QtCore.QVariant(True)).toBool(): QtCore.QVariant(True)).toBool():
windowFlags = windowFlags | QtCore.Qt.X11BypassWindowManagerHint windowFlags |= QtCore.Qt.X11BypassWindowManagerHint
# FIXME: QtCore.Qt.SplashScreen is workaround to make display screen # FIXME: QtCore.Qt.SplashScreen is workaround to make display screen
# stay always on top on Mac OS X. For details see bug 906926. # stay always on top on Mac OS X. For details see bug 906926.
# It needs more investigation to fix it properly. # It needs more investigation to fix it properly.
if sys.platform == 'darwin': if sys.platform == 'darwin':
windowFlags = windowFlags | QtCore.Qt.SplashScreen windowFlags |= QtCore.Qt.SplashScreen
self.setWindowFlags(windowFlags) self.setWindowFlags(windowFlags)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setTransparency(True) self.setTransparency(True)
@ -493,11 +492,15 @@ class AudioPlayer(QtCore.QObject):
QtCore.QObject.__init__(self, parent) QtCore.QObject.__init__(self, parent)
self.currentIndex = -1 self.currentIndex = -1
self.playlist = [] self.playlist = []
self.repeat = False
self.mediaObject = Phonon.MediaObject() self.mediaObject = Phonon.MediaObject()
self.mediaObject.setTickInterval(100)
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory) self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self.audioObject) Phonon.createPath(self.mediaObject, self.audioObject)
QtCore.QObject.connect(self.mediaObject, QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'aboutToFinish()'), self.onAboutToFinish) QtCore.SIGNAL(u'aboutToFinish()'), self.onAboutToFinish)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'finished()'), self.onFinished)
def __del__(self): def __del__(self):
""" """
@ -516,6 +519,14 @@ class AudioPlayer(QtCore.QObject):
if len(self.playlist) > self.currentIndex: if len(self.playlist) > self.currentIndex:
self.mediaObject.enqueue(self.playlist[self.currentIndex]) self.mediaObject.enqueue(self.playlist[self.currentIndex])
def onFinished(self):
if self.repeat:
log.debug(u'Repeat is enabled... here we go again!')
self.mediaObject.clearQueue()
self.mediaObject.clear()
self.currentIndex = -1
self.play()
def connectVolumeSlider(self, slider): def connectVolumeSlider(self, slider):
slider.setAudioOutput(self.audioObject) slider.setAudioOutput(self.audioObject)
@ -563,3 +574,27 @@ class AudioPlayer(QtCore.QObject):
for filename in filenames: for filename in filenames:
self.playlist.append(Phonon.MediaSource(filename)) self.playlist.append(Phonon.MediaSource(filename))
def next(self):
if not self.repeat and self.currentIndex + 1 == len(self.playlist):
return
isPlaying = self.mediaObject.state() == Phonon.PlayingState
self.currentIndex += 1
if self.repeat and self.currentIndex == len(self.playlist):
self.currentIndex = 0
self.mediaObject.clearQueue()
self.mediaObject.clear()
self.mediaObject.enqueue(self.playlist[self.currentIndex])
if isPlaying:
self.mediaObject.play()
def goTo(self, index):
isPlaying = self.mediaObject.state() == Phonon.PlayingState
self.mediaObject.clearQueue()
self.mediaObject.clear()
self.currentIndex = index
self.mediaObject.enqueue(self.playlist[self.currentIndex])
if isPlaying:
self.mediaObject.play()
def connectSlot(self, signal, slot):
QtCore.QObject.connect(self.mediaObject, signal, slot)

View File

@ -100,8 +100,7 @@ class MediaController(object):
Register each media Player controller (Webkit, Phonon, etc) and store Register each media Player controller (Webkit, Phonon, etc) and store
for later use for later use
""" """
if controller.check_available(): self.mediaPlayers[controller.name] = controller
self.mediaPlayers[controller.name] = controller
def check_available_media_players(self): def check_available_media_players(self):
""" """
@ -134,7 +133,8 @@ class MediaController(object):
QtCore.QVariant(u'webkit')).toString()) QtCore.QVariant(u'webkit')).toString())
savedPlayers = playerSettings.split(u',') savedPlayers = playerSettings.split(u',')
invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \ invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \
if not mediaPlayer in self.mediaPlayers] if not mediaPlayer in self.mediaPlayers or \
not self.mediaPlayers[mediaPlayer].check_available()]
if len(invalidMediaPlayers) > 0: if len(invalidMediaPlayers) > 0:
for invalidPlayer in invalidMediaPlayers: for invalidPlayer in invalidMediaPlayers:
savedPlayers.remove(invalidPlayer) savedPlayers.remove(invalidPlayer)

View File

@ -33,7 +33,7 @@ from collections import deque
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \ from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
translate, build_icon, ServiceItem, build_html, PluginManager, ServiceItem translate, build_icon, build_html, PluginManager, ServiceItem
from openlp.core.lib.ui import UiStrings, create_action from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.lib import SlideLimits, ServiceItemAction from openlp.core.lib import SlideLimits, ServiceItemAction
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList
@ -46,9 +46,10 @@ class SlideList(QtGui.QTableWidget):
Customised version of QTableWidget which can respond to keyboard Customised version of QTableWidget which can respond to keyboard
events. events.
""" """
def __init__(self, parent=None, name=None): def __init__(self, parent=None):
QtGui.QTableWidget.__init__(self, parent.controller) QtGui.QTableWidget.__init__(self, parent.controller)
class Controller(QtGui.QWidget): class Controller(QtGui.QWidget):
""" """
Controller is a general controller widget. Controller is a general controller widget.
@ -95,8 +96,10 @@ class SlideController(Controller):
u'loopSeparator', u'loopSeparator',
u'delaySpinBox' u'delaySpinBox'
] ]
self.songEditList = [ self.audioList = [
u'editSong', u'songMenu',
u'audioPauseItem',
u'audioTimeLabel'
] ]
self.timer_id = 0 self.timer_id = 0
self.songEdit = False self.songEdit = False
@ -273,14 +276,44 @@ class SlideController(Controller):
self.songMenu.setPopupMode(QtGui.QToolButton.InstantPopup) self.songMenu.setPopupMode(QtGui.QToolButton.InstantPopup)
self.songMenu.setMenu(QtGui.QMenu( self.songMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Go To'), self.toolbar)) translate('OpenLP.SlideController', 'Go To'), self.toolbar))
self.songMenu.hide()
self.toolbar.addToolbarWidget(self.songMenu) self.toolbar.addToolbarWidget(self.songMenu)
# Stuff for items with background audio. # Stuff for items with background audio.
self.audioPauseItem = self.toolbar.addToolbarAction(u'audioPause', self.audioPauseItem = self.toolbar.addToolbarAction(
text=u'Pause Audio', icon=u':/slides/media_playback_pause.png', u'audioPauseItem', icon=u':/slides/media_playback_pause.png',
text=translate('OpenLP.SlideController', 'Pause Audio'),
tooltip=translate('OpenLP.SlideController', 'Pause audio.'), tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
checked=False, visible=False, checked=False, visible=False, category=self.category,
triggers=self.onAudioPauseClicked) triggers=self.onAudioPauseClicked)
self.audioMenu = QtGui.QMenu(
translate('OpenLP.SlideController', 'Background Audio'), self)
self.audioPauseItem.setMenu(self.audioMenu)
self.audioPauseItem.setParent(self)
self.toolbar.widgetForAction(self.audioPauseItem).setPopupMode(
QtGui.QToolButton.MenuButtonPopup)
self.nextTrackItem = create_action(self, u'nextTrackItem',
text=translate('OpenLP.SlideController', 'Next Track'),
icon=u':/slides/media_playback_next.png', tooltip=translate(
'OpenLP.SlideController', 'Go to next audio track.'),
category=self.category, context=QtCore.Qt.WindowShortcut,
triggers=self.onNextTrackClicked)
self.audioMenu.addAction(self.nextTrackItem)
self.trackMenu = self.audioMenu.addMenu(
translate('OpenLP.SlideController', 'Tracks'))
self.audioTimeLabel = QtGui.QLabel(u' 00:00 ', self.toolbar)
self.audioTimeLabel.setAlignment(
QtCore.Qt.AlignCenter|QtCore.Qt.AlignHCenter)
self.audioTimeLabel.setStyleSheet(
u'background-color: palette(background); '
u'border-top-color: palette(shadow); '
u'border-left-color: palette(shadow); '
u'border-bottom-color: palette(light); '
u'border-right-color: palette(light); '
u'border-radius: 3px; border-style: inset; '
u'border-width: 1; font-family: monospace; margin: 2px;'
)
self.audioTimeLabel.setObjectName(u'audioTimeLabel')
self.toolbar.addToolbarWidget(self.audioTimeLabel)
self.toolbar.setWidgetVisible(self.audioList, False)
# Screen preview area # Screen preview area
self.previewFrame = QtGui.QFrame(self.splitter) self.previewFrame = QtGui.QFrame(self.splitter)
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio)) self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
@ -365,7 +398,7 @@ class SlideController(Controller):
QtCore.QObject.connect(self.previewListWidget, QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onGoLiveClick) self.onGoLiveClick)
self.toolbar.setWidgetVisible(self.songEditList, False) self.toolbar.setWidgetVisible([u'editSong'], False)
if self.isLive: if self.isLive:
self.setLiveHotkeys(self) self.setLiveHotkeys(self)
self.__addActionsToWidget(self.previewListWidget) self.__addActionsToWidget(self.previewListWidget)
@ -527,7 +560,7 @@ class SlideController(Controller):
self.keypress_loop = True self.keypress_loop = True
keypressCommand = self.keypress_queue.popleft() keypressCommand = self.keypress_queue.popleft()
if keypressCommand == ServiceItemAction.Previous: if keypressCommand == ServiceItemAction.Previous:
Receiver.send_message('servicemanager_previous_item', None) Receiver.send_message('servicemanager_previous_item')
elif keypressCommand == ServiceItemAction.PreviousLastSlide: elif keypressCommand == ServiceItemAction.PreviousLastSlide:
# Go to the last slide of the previous item # Go to the last slide of the previous item
Receiver.send_message('servicemanager_previous_item', u'last slide') Receiver.send_message('servicemanager_previous_item', u'last slide')
@ -548,6 +581,8 @@ class SlideController(Controller):
self.display.setup() self.display.setup()
if self.isLive: if self.isLive:
self.__addActionsToWidget(self.display) self.__addActionsToWidget(self.display)
self.display.audioPlayer.connectSlot(
QtCore.SIGNAL(u'tick(qint64)'), self.onAudioTimeRemaining)
# The SlidePreview's ratio. # The SlidePreview's ratio.
try: try:
self.ratio = float(self.screens.current[u'size'].width()) / \ self.ratio = float(self.screens.current[u'size'].width()) / \
@ -559,7 +594,7 @@ class SlideController(Controller):
self.previewDisplay.setup() self.previewDisplay.setup()
serviceItem = ServiceItem() serviceItem = ServiceItem()
self.previewDisplay.webView.setHtml(build_html(serviceItem, self.previewDisplay.webView.setHtml(build_html(serviceItem,
self.previewDisplay.screen, None, self.isLive, None, self.previewDisplay.screen, None, self.isLive,
plugins=PluginManager.get_instance().plugins)) plugins=PluginManager.get_instance().plugins))
self.mediaController.setup_display(self.previewDisplay) self.mediaController.setup_display(self.previewDisplay)
if self.serviceItem: if self.serviceItem:
@ -621,7 +656,7 @@ class SlideController(Controller):
Adjusts the value of the ``delaySpinBox`` to the given one. Adjusts the value of the ``delaySpinBox`` to the given one.
""" """
self.delaySpinBox.setValue(int(value)) self.delaySpinBox.setValue(int(value))
def updateSlideLimits(self): def updateSlideLimits(self):
""" """
Updates the Slide Limits variable from the settings. Updates the Slide Limits variable from the settings.
@ -679,9 +714,9 @@ class SlideController(Controller):
# See bug #791050 # See bug #791050
self.toolbar.hide() self.toolbar.hide()
self.mediabar.hide() self.mediabar.hide()
self.toolbar.setWidgetVisible(self.songEditList, False) self.toolbar.setWidgetVisible([u'editSong'], False)
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin: if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
self.toolbar.setWidgetVisible(self.songEditList) self.toolbar.setWidgetVisible([u'editSong'])
elif item.is_media(): elif item.is_media():
self.mediabar.show() self.mediabar.show()
self.previousItem.setVisible(not item.is_media()) self.previousItem.setVisible(not item.is_media())
@ -764,10 +799,23 @@ class SlideController(Controller):
self.display.audioPlayer.reset() self.display.audioPlayer.reset()
self.setAudioItemsVisibility(False) self.setAudioItemsVisibility(False)
self.audioPauseItem.setChecked(False) self.audioPauseItem.setChecked(False)
# If the current item has background audio
if self.serviceItem.is_capable(ItemCapabilities.HasBackgroundAudio): if self.serviceItem.is_capable(ItemCapabilities.HasBackgroundAudio):
log.debug(u'Starting to play...') log.debug(u'Starting to play...')
self.display.audioPlayer.addToPlaylist( self.display.audioPlayer.addToPlaylist(
self.serviceItem.background_audio) self.serviceItem.background_audio)
self.trackMenu.clear()
for counter in range(len(self.serviceItem.background_audio)):
action = self.trackMenu.addAction(os.path.basename(
self.serviceItem.background_audio[counter]))
action.setData(counter)
QtCore.QObject.connect(action,
QtCore.SIGNAL(u'triggered(bool)'),
self.onTrackTriggered)
self.display.audioPlayer.repeat = QtCore.QSettings().value(
self.parent().generalSettingsSection + \
u'/audio repeat list',
QtCore.QVariant(False)).toBool()
if QtCore.QSettings().value( if QtCore.QSettings().value(
self.parent().generalSettingsSection + \ self.parent().generalSettingsSection + \
u'/audio start paused', u'/audio start paused',
@ -1021,7 +1069,7 @@ class SlideController(Controller):
else: else:
Receiver.send_message(u'live_display_show') Receiver.send_message(u'live_display_show')
def onSlideSelected(self, start=False): def onSlideSelected(self):
""" """
Slide selected in controller Slide selected in controller
""" """
@ -1217,7 +1265,7 @@ class SlideController(Controller):
self.onToggleLoop() self.onToggleLoop()
def setAudioItemsVisibility(self, visible): def setAudioItemsVisibility(self, visible):
self.audioPauseItem.setVisible(visible) self.toolbar.setWidgetVisible(self.audioList, visible)
def onAudioPauseClicked(self, checked): def onAudioPauseClicked(self, checked):
if not self.audioPauseItem.isVisible(): if not self.audioPauseItem.isVisible():
@ -1328,3 +1376,17 @@ class SlideController(Controller):
return HideMode.Screen return HideMode.Screen
else: else:
return None return None
def onNextTrackClicked(self):
self.display.audioPlayer.next()
def onAudioTimeRemaining(self, time):
seconds = self.display.audioPlayer.mediaObject.remainingTime() // 1000
minutes = seconds // 60
seconds %= 60
self.audioTimeLabel.setText(u' %02d:%02d ' % (minutes, seconds))
def onTrackTriggered(self):
action = self.sender()
index = action.data().toInt()[0]
self.display.audioPlayer.goTo(index)

View File

@ -27,6 +27,7 @@
--> -->
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1" />
<title>${app_title}</title> <title>${app_title}</title>
<link rel="stylesheet" href="/files/jquery.mobile.css" /> <link rel="stylesheet" href="/files/jquery.mobile.css" />
<link rel="stylesheet" href="/files/openlp.css" /> <link rel="stylesheet" href="/files/openlp.css" />

View File

@ -42,7 +42,7 @@ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \ from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
clean_string clean_string
from openlp.plugins.songs.lib.db import Author, Song, MediaFile from openlp.plugins.songs.lib.db import Author, Song, Book, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.ui import SongStrings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -55,7 +55,8 @@ class SongSearch(object):
Titles = 2 Titles = 2
Lyrics = 3 Lyrics = 3
Authors = 4 Authors = 4
Themes = 5 Books = 5
Themes = 6
class SongMediaItem(MediaManagerItem): class SongMediaItem(MediaManagerItem):
@ -157,6 +158,8 @@ class SongMediaItem(MediaManagerItem):
translate('SongsPlugin.MediaItem', 'Lyrics')), translate('SongsPlugin.MediaItem', 'Lyrics')),
(SongSearch.Authors, u':/songs/song_search_author.png', (SongSearch.Authors, u':/songs/song_search_author.png',
SongStrings.Authors), SongStrings.Authors),
(SongSearch.Books, u':/songs/song_book_edit.png',
SongStrings.SongBooks),
(SongSearch.Themes, u':/slides/slide_theme.png', UiStrings().Themes) (SongSearch.Themes, u':/slides/slide_theme.png', UiStrings().Themes)
]) ])
self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value( self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value(
@ -195,6 +198,19 @@ class SongMediaItem(MediaManagerItem):
Author.display_name.like(u'%' + search_keywords + u'%'), Author.display_name.like(u'%' + search_keywords + u'%'),
Author.display_name.asc()) Author.display_name.asc())
self.displayResultsAuthor(search_results) self.displayResultsAuthor(search_results)
elif search_type == SongSearch.Books:
log.debug(u'Books Search')
search_results = self.plugin.manager.get_all_objects(Book,
Book.name.like(u'%' + search_keywords + u'%'),
Book.name.asc())
song_number = False
if not search_results:
search_keywords = search_keywords.rpartition(' ')
search_results = self.plugin.manager.get_all_objects(Book,
Book.name.like(u'%' + search_keywords[0] + u'%'),
Book.name.asc())
song_number = re.sub(r'[^0-9]', u'', search_keywords[2])
self.displayResultsBook(search_results, song_number)
elif search_type == SongSearch.Themes: elif search_type == SongSearch.Themes:
log.debug(u'Theme Search') log.debug(u'Theme Search')
search_results = self.plugin.manager.get_all_objects(Song, search_results = self.plugin.manager.get_all_objects(Song,
@ -269,6 +285,25 @@ class SongMediaItem(MediaManagerItem):
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id)) song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
self.listView.addItem(song_name) self.listView.addItem(song_name)
def displayResultsBook(self, searchresults, song_number=False):
log.debug(u'display results Book')
self.listView.clear()
for book in searchresults:
songs = sorted(book.songs, key=lambda song: int(
re.sub(r'[^0-9]', u' ', song.song_number).partition(' ')[0])
if len(re.sub(r'[^\w]', ' ', song.song_number)) else 0)
for song in songs:
# Do not display temporary songs
if song.temporary:
continue
if song_number and not song_number in song.song_number:
continue
song_detail = u'%s - %s (%s)' % (book.name, song.song_number,
song.title)
song_name = QtGui.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
self.listView.addItem(song_name)
def onClearTextButtonClick(self): def onClearTextButtonClick(self):
""" """
Clear the search text. Clear the search text.

View File

@ -33,56 +33,56 @@ class SongsTab(SettingsTab):
""" """
SongsTab is the Songs settings tab in the settings dialog. SongsTab is the Songs settings tab in the settings dialog.
""" """
def __init__(self, parent, title, visible_title, icon_path):
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
def setupUi(self): def setupUi(self):
"""
Set up the configuration tab UI.
"""
self.setObjectName(u'SongsTab') self.setObjectName(u'SongsTab')
SettingsTab.setupUi(self) SettingsTab.setupUi(self)
self.SongsModeGroupBox = QtGui.QGroupBox(self.leftColumn) self.modeGroupBox = QtGui.QGroupBox(self.leftColumn)
self.SongsModeGroupBox.setObjectName(u'SongsModeGroupBox') self.modeGroupBox.setObjectName(u'modeGroupBox')
self.SongsModeLayout = QtGui.QVBoxLayout(self.SongsModeGroupBox) self.modeLayout = QtGui.QVBoxLayout(self.modeGroupBox)
self.SongsModeLayout.setObjectName(u'SongsModeLayout') self.modeLayout.setObjectName(u'modeLayout')
self.SearchAsTypeCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) self.searchAsTypeCheckBox = QtGui.QCheckBox(self.modeGroupBox)
self.SearchAsTypeCheckBox.setObjectName(u'SearchAsTypeCheckBox') self.searchAsTypeCheckBox.setObjectName(u'SearchAsTypeCheckBox')
self.SongsModeLayout.addWidget(self.SearchAsTypeCheckBox) self.modeLayout.addWidget(self.searchAsTypeCheckBox)
self.SongBarActiveCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) self.toolBarActiveCheckBox = QtGui.QCheckBox(self.modeGroupBox)
self.SongBarActiveCheckBox.setObjectName(u'SongBarActiveCheckBox') self.toolBarActiveCheckBox.setObjectName(u'toolBarActiveCheckBox')
self.SongsModeLayout.addWidget(self.SongBarActiveCheckBox) self.modeLayout.addWidget(self.toolBarActiveCheckBox)
self.SongUpdateOnEditCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) self.updateOnEditCheckBox = QtGui.QCheckBox(self.modeGroupBox)
self.SongUpdateOnEditCheckBox.setObjectName(u'SongUpdateOnEditCheckBox') self.updateOnEditCheckBox.setObjectName(u'updateOnEditCheckBox')
self.SongsModeLayout.addWidget(self.SongUpdateOnEditCheckBox) self.modeLayout.addWidget(self.updateOnEditCheckBox)
self.SongAddFromServiceCheckBox = QtGui.QCheckBox( self.addFromServiceCheckBox = QtGui.QCheckBox(
self.SongsModeGroupBox) self.modeGroupBox)
self.SongAddFromServiceCheckBox.setObjectName( self.addFromServiceCheckBox.setObjectName(
u'SongAddFromServiceCheckBox') u'addFromServiceCheckBox')
self.SongsModeLayout.addWidget(self.SongAddFromServiceCheckBox) self.modeLayout.addWidget(self.addFromServiceCheckBox)
self.leftLayout.addWidget(self.SongsModeGroupBox) self.leftLayout.addWidget(self.modeGroupBox)
self.leftLayout.addStretch() self.leftLayout.addStretch()
self.rightLayout.addStretch() self.rightLayout.addStretch()
QtCore.QObject.connect(self.SearchAsTypeCheckBox, QtCore.QObject.connect(self.searchAsTypeCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), QtCore.SIGNAL(u'stateChanged(int)'),
self.onSearchAsTypeCheckBoxChanged) self.onSearchAsTypeCheckBoxChanged)
QtCore.QObject.connect(self.SongBarActiveCheckBox, QtCore.QObject.connect(self.toolBarActiveCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), QtCore.SIGNAL(u'stateChanged(int)'),
self.onSongBarActiveCheckBoxChanged) self.onToolBarActiveCheckBoxChanged)
QtCore.QObject.connect(self.SongUpdateOnEditCheckBox, QtCore.QObject.connect(self.updateOnEditCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), QtCore.SIGNAL(u'stateChanged(int)'),
self.onSongUpdateOnEditCheckBoxChanged) self.onUpdateOnEditCheckBoxChanged)
QtCore.QObject.connect(self.SongAddFromServiceCheckBox, QtCore.QObject.connect(self.addFromServiceCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), QtCore.SIGNAL(u'stateChanged(int)'),
self.onSongAddFromServiceCheckBoxChanged) self.onAddFromServiceCheckBoxChanged)
def retranslateUi(self): def retranslateUi(self):
self.SongsModeGroupBox.setTitle( self.modeGroupBox.setTitle(
translate('SongsPlugin.SongsTab', 'Songs Mode')) translate('SongsPlugin.SongsTab', 'Songs Mode'))
self.SearchAsTypeCheckBox.setText( self.searchAsTypeCheckBox.setText(
translate('SongsPlugin.SongsTab', 'Enable search as you type')) translate('SongsPlugin.SongsTab', 'Enable search as you type'))
self.SongBarActiveCheckBox.setText(translate('SongsPlugin.SongsTab', self.toolBarActiveCheckBox.setText(translate('SongsPlugin.SongsTab',
'Display verses on live tool bar')) 'Display verses on live tool bar'))
self.SongUpdateOnEditCheckBox.setText( self.updateOnEditCheckBox.setText(
translate('SongsPlugin.SongsTab', 'Update service from song edit')) translate('SongsPlugin.SongsTab', 'Update service from song edit'))
self.SongAddFromServiceCheckBox.setText( self.addFromServiceCheckBox.setText(
translate('SongsPlugin.SongsTab', translate('SongsPlugin.SongsTab',
'Add missing songs when opening service')) 'Add missing songs when opening service'))
@ -92,19 +92,19 @@ class SongsTab(SettingsTab):
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.song_search = True self.song_search = True
def onSongBarActiveCheckBoxChanged(self, check_state): def onToolBarActiveCheckBoxChanged(self, check_state):
self.song_bar = False self.tool_bar = False
# we have a set value convert to True/False # we have a set value convert to True/False
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.song_bar = True self.tool_bar = True
def onSongUpdateOnEditCheckBoxChanged(self, check_state): def onUpdateOnEditCheckBoxChanged(self, check_state):
self.update_edit = False self.update_edit = False
# we have a set value convert to True/False # we have a set value convert to True/False
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.update_edit = True self.update_edit = True
def onSongAddFromServiceCheckBoxChanged(self, check_state): def onAddFromServiceCheckBoxChanged(self, check_state):
self.update_load = False self.update_load = False
# we have a set value convert to True/False # we have a set value convert to True/False
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
@ -115,23 +115,23 @@ class SongsTab(SettingsTab):
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.song_search = settings.value( self.song_search = settings.value(
u'search as type', QtCore.QVariant(False)).toBool() u'search as type', QtCore.QVariant(False)).toBool()
self.song_bar = settings.value( self.tool_bar = settings.value(
u'display songbar', QtCore.QVariant(True)).toBool() u'display songbar', QtCore.QVariant(True)).toBool()
self.update_edit = settings.value( self.update_edit = settings.value(
u'update service on edit', QtCore.QVariant(False)).toBool() u'update service on edit', QtCore.QVariant(False)).toBool()
self.update_load = settings.value( self.update_load = settings.value(
u'add song from service', QtCore.QVariant(True)).toBool() u'add song from service', QtCore.QVariant(True)).toBool()
self.SearchAsTypeCheckBox.setChecked(self.song_search) self.searchAsTypeCheckBox.setChecked(self.song_search)
self.SongBarActiveCheckBox.setChecked(self.song_bar) self.toolBarActiveCheckBox.setChecked(self.tool_bar)
self.SongUpdateOnEditCheckBox.setChecked(self.update_edit) self.updateOnEditCheckBox.setChecked(self.update_edit)
self.SongAddFromServiceCheckBox.setChecked(self.update_load) self.addFromServiceCheckBox.setChecked(self.update_load)
settings.endGroup() settings.endGroup()
def save(self): def save(self):
settings = QtCore.QSettings() settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
settings.setValue(u'search as type', QtCore.QVariant(self.song_search)) settings.setValue(u'search as type', QtCore.QVariant(self.song_search))
settings.setValue(u'display songbar', QtCore.QVariant(self.song_bar)) settings.setValue(u'display songbar', QtCore.QVariant(self.tool_bar))
settings.setValue(u'update service on edit', settings.setValue(u'update service on edit',
QtCore.QVariant(self.update_edit)) QtCore.QVariant(self.update_edit))
settings.setValue(u'add song from service', settings.setValue(u'add song from service',

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

View File

@ -68,6 +68,7 @@
<file>media_playback_start.png</file> <file>media_playback_start.png</file>
<file>media_playback_stop.png</file> <file>media_playback_stop.png</file>
<file>media_playback_pause.png</file> <file>media_playback_pause.png</file>
<file>media_playback_next.png</file>
</qresource> </qresource>
<qresource prefix="icon"> <qresource prefix="icon">
<file>openlp-logo-16x16.png</file> <file>openlp-logo-16x16.png</file>

View File

@ -12,12 +12,12 @@
+############################################################################### +###############################################################################
+# OpenLP - Open Source Lyrics Projection # +# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- # +# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman # +# Copyright (c) 2008-2012 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
+# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Woldsund # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- # +# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it # +# 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 # +# under the terms of the GNU General Public License as published by the Free #

View File

@ -5,12 +5,12 @@
############################################################################### ###############################################################################
# OpenLP - Open Source Lyrics Projection # # OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman # # Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael # # Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, # # Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # # Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode # # Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Woldsund # # Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
# --------------------------------------------------------------------------- # # --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it # # 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 # # under the terms of the GNU General Public License as published by the Free #