HEAD r1552

This commit is contained in:
Armin Köhler 2011-05-18 20:00:40 +02:00
commit 236ca44105
18 changed files with 391 additions and 142 deletions

View File

@ -102,6 +102,7 @@ class MediaManagerItem(QtGui.QWidget):
self.remoteTriggered = None
self.singleServiceItem = True
self.quickPreviewAllowed = False
self.hasSearch = False
self.pageLayout = QtGui.QVBoxLayout(self)
self.pageLayout.setSpacing(0)
self.pageLayout.setMargin(0)
@ -474,11 +475,23 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem',
'You must select one or more items to send live.'))
else:
log.debug(u'%s Live requested', self.plugin.name)
serviceItem = self.buildServiceItem()
if serviceItem:
self.goLive()
def goLive(self, item_id=None):
log.debug(u'%s Live requested', self.plugin.name)
item = None
if item_id:
item = self.createItemFromId(item_id)
serviceItem = self.buildServiceItem(item)
if serviceItem:
if not item_id:
serviceItem.from_plugin = True
self.parent.liveController.addServiceItem(serviceItem)
self.parent.liveController.addServiceItem(serviceItem)
def createItemFromId(self, item_id):
item = QtGui.QListWidgetItem()
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(item_id))
return item
def onAddClick(self):
"""
@ -586,3 +599,10 @@ class MediaManagerItem(QtGui.QWidget):
else:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
return item_id
def search(self, string):
"""
Performs a plugin specific search for items containing ``string``
"""
raise NotImplementedError(
u'Plugin.search needs to be defined by the plugin')

View File

@ -211,3 +211,12 @@ class PluginManager(object):
if plugin.isActive():
plugin.finalise()
log.info(u'Finalisation Complete for %s ' % plugin.name)
def get_plugin_by_name(self, name):
"""
Return the plugin which has a name with value ``name``
"""
for plugin in self.plugins:
if plugin.name == name:
return plugin
return None

View File

@ -300,7 +300,7 @@ class Renderer(object):
# Adjust width and height to account for shadow. outline done in css
self.page_shell = u'<html><head><style>' \
u'*{margin: 0; padding: 0; border: 0;} '\
u'#main {position:absolute; top:0px; %s %s}</style><body>' \
u'#main {position:absolute; top:0px; %s %s}</style></head><body>' \
u'<div id="main">' % \
(build_lyrics_format_css(self.theme_data, self.page_width,
self.page_height), build_lyrics_outline_css(self.theme_data))

View File

@ -50,7 +50,6 @@ class SettingsTab(QtGui.QWidget):
self.setupUi()
self.retranslateUi()
self.initialise()
self.preLoad()
self.load()
def setupUi(self):
@ -86,12 +85,6 @@ class SettingsTab(QtGui.QWidget):
left_width = max(left_width, self.leftColumn.minimumSizeHint().width())
self.leftColumn.setFixedWidth(left_width)
def preLoad(self):
"""
Setup the tab's interface.
"""
pass
def retranslateUi(self):
"""
Setup the interface translation strings.
@ -118,9 +111,9 @@ class SettingsTab(QtGui.QWidget):
def cancel(self):
"""
Reset any settings
Reset any settings if cancel pressed
"""
pass
self.load()
def postSetUp(self, postUpdate=False):
"""

View File

@ -47,7 +47,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.preLoad()
self._loadDisplayTags()
QtCore.QObject.connect(self.tagTableWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected)
QtCore.QObject.connect(self.defaultPushButton,
@ -66,12 +66,12 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
Load Display and set field state.
"""
# Create initial copy from master
self.preLoad()
self._loadDisplayTags()
self._resetTable()
self.selected = -1
return QtGui.QDialog.exec_(self)
def preLoad(self):
def _loadDisplayTags(self):
"""
Load the Tags from store so can be used in the system or used to
update the display. If Cancel was selected this is needed to reset the

View File

@ -359,7 +359,7 @@ class BibleDB(QtCore.QObject, Manager):
else:
return None
def get_verses(self, reference_list):
def get_verses(self, reference_list, show_error=True):
"""
This is probably the most used function. It retrieves the list of
verses based on the user's query.
@ -396,11 +396,12 @@ class BibleDB(QtCore.QObject, Manager):
verse_list.extend(verses)
else:
log.debug(u'OpenLP failed to find book %s', book)
critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching book '
'could be found in this Bible. Check that you have '
'spelled the name of the book correctly.'))
if show_error:
critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching book '
'could be found in this Bible. Check that you '
'have spelled the name of the book correctly.'))
return verse_list
def verse_search(self, text):

View File

@ -439,7 +439,7 @@ class HTTPBible(BibleDB):
else:
return True
def get_verses(self, reference_list):
def get_verses(self, reference_list, show_error=True):
"""
A reimplementation of the ``BibleDB.get_verses`` method, this one is
specifically for web Bibles. It first checks to see if the particular
@ -465,11 +465,12 @@ class HTTPBible(BibleDB):
book_id = reference[0]
db_book = self.get_book_by_book_ref_id(book_id)
if not db_book:
critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching '
'book could be found in this Bible. Check that you '
'have spelled the name of the book correctly.'))
if show_error:
critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching '
'book could be found in this Bible. Check that you '
'have spelled the name of the book correctly.'))
return []
book = db_book.name
if BibleDB.get_verse_count(self, book_id, reference[1]) == 0:
@ -489,7 +490,7 @@ class HTTPBible(BibleDB):
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
return BibleDB.get_verses(self, reference_list)
return BibleDB.get_verses(self, reference_list, show_error)
def get_chapter(self, book, chapter):
"""

View File

@ -242,7 +242,7 @@ class BibleManager(object):
book_ref_id = db_book.book_reference_id
return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
def get_verses(self, bible, versetext, firstbible=False):
def get_verses(self, bible, versetext, firstbible=False, show_error=True):
"""
Parses a scripture reference, fetches the verses from the Bible
specified, and returns a list of ``Verse`` objects.
@ -263,13 +263,14 @@ class BibleManager(object):
"""
log.debug(u'BibleManager.get_verses("%s", "%s")', bible, versetext)
if not bible:
Receiver.send_message(u'openlp_information_message', {
u'title': translate('BiblesPlugin.BibleManager',
'No Bibles Available'),
u'message': translate('BiblesPlugin.BibleManager',
'There are no Bibles currently installed. Please use the '
'Import Wizard to install one or more Bibles.')
})
if show_error:
Receiver.send_message(u'openlp_information_message', {
u'title': translate('BiblesPlugin.BibleManager',
'No Bibles Available'),
u'message': translate('BiblesPlugin.BibleManager',
'There are no Bibles currently installed. Please use the '
'Import Wizard to install one or more Bibles.')
})
return None
reflist = parse_reference(versetext)
if reflist:
@ -295,22 +296,23 @@ class BibleManager(object):
'could be found in this Bible. Check that you have '
'spelled the name of the book correctly.'))
reflist = new_reflist
return self.db_cache[bible].get_verses(reflist)
return self.db_cache[bible].get_verses(reflist, show_error)
else:
Receiver.send_message(u'openlp_information_message', {
u'title': translate('BiblesPlugin.BibleManager',
'Scripture Reference Error'),
u'message': translate('BiblesPlugin.BibleManager',
'Your scripture reference is either not supported by OpenLP '
'or is invalid. Please make sure your reference conforms to '
'one of the following patterns:\n\n'
'Book Chapter\n'
'Book Chapter-Chapter\n'
'Book Chapter:Verse-Verse\n'
'Book Chapter:Verse-Verse,Verse-Verse\n'
'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n'
'Book Chapter:Verse-Chapter:Verse')
})
if show_error:
Receiver.send_message(u'openlp_information_message', {
u'title': translate('BiblesPlugin.BibleManager',
'Scripture Reference Error'),
u'message': translate('BiblesPlugin.BibleManager',
'Your scripture reference is either not supported by '
'OpenLP or is invalid. Please make sure your reference '
'conforms to one of the following patterns:\n\n'
'Book Chapter\n'
'Book Chapter-Chapter\n'
'Book Chapter:Verse-Verse\n'
'Book Chapter:Verse-Verse,Verse-Verse\n'
'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n'
'Book Chapter:Verse-Chapter:Verse')
})
return None
def verse_search(self, bible, second_bible, text):
@ -318,7 +320,7 @@ class BibleManager(object):
Does a verse search for the given bible and text.
``bible``
The bible to seach in (unicode).
The bible to search in (unicode).
``second_bible``
The second bible (unicode). We do not search in this bible.
@ -327,6 +329,15 @@ class BibleManager(object):
The text to search for (unicode).
"""
log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text)
if not bible:
Receiver.send_message(u'openlp_information_message', {
u'title': translate('BiblesPlugin.BibleManager',
'No Bibles Available'),
u'message': translate('BiblesPlugin.BibleManager',
'There are no Bibles currently installed. Please use the '
'Import Wizard to install one or more Bibles.')
})
return None
# Check if the bible or second_bible is a web bible.
webbible = self.db_cache[bible].get_object(BibleMeta,
u'download source')

View File

@ -61,6 +61,7 @@ class BibleMediaItem(MediaManagerItem):
# Place to store the search results for both bibles.
self.settings = self.parent.settings_tab
self.quickPreviewAllowed = True
self.hasSearch = True
self.search_results = {}
self.second_search_results = {}
self.check_search_result()
@ -646,6 +647,19 @@ class BibleMediaItem(MediaManagerItem):
Receiver.send_message(u'openlp_process_events')
def displayResults(self, bible, second_bible=u''):
"""
Displays the search results in the media manager. All data needed for
further action is saved for/in each row.
"""
items = self.buildDisplayResults(bible, second_bible,
self.search_results)
for bible_verse in items:
self.listView.addItem(bible_verse)
self.listView.selectAll()
self.search_results = {}
self.second_search_results = {}
def buildDisplayResults(self, bible, second_bible, search_results):
"""
Displays the search results in the media manager. All data needed for
further action is saved for/in each row.
@ -665,7 +679,8 @@ class BibleMediaItem(MediaManagerItem):
second_bible, u'Copyright').value
second_permissions = self.parent.manager.get_meta_data(
second_bible, u'Permissions').value
for count, verse in enumerate(self.search_results):
items = []
for count, verse in enumerate(search_results):
data = {
'book': QtCore.QVariant(verse.book.name),
'chapter': QtCore.QVariant(verse.chapter),
@ -697,10 +712,8 @@ class BibleMediaItem(MediaManagerItem):
verse.chapter, verse_separator, verse.verse, version)
bible_verse = QtGui.QListWidgetItem(bible_text)
bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
self.listView.addItem(bible_verse)
self.listView.selectAll()
self.search_results = {}
self.second_search_results = {}
items.append(bible_verse)
return items
def generateSlideData(self, service_item, item=None, xmlVersion=False):
"""
@ -708,7 +721,10 @@ class BibleMediaItem(MediaManagerItem):
service item's title.
"""
log.debug(u'generating slide data')
items = self.listView.selectedIndexes()
if item:
items = item
else:
items = self.listView.selectedItems()
if len(items) == 0:
return False
bible_text = u''
@ -717,8 +733,7 @@ class BibleMediaItem(MediaManagerItem):
raw_slides = []
raw_title = []
verses = VerseReferenceList()
for item in items:
bitem = self.listView.item(item.row())
for bitem in items:
book = self._decodeQtObject(bitem, 'book')
chapter = int(self._decodeQtObject(bitem, 'chapter'))
verse = int(self._decodeQtObject(bitem, 'verse'))
@ -752,11 +767,11 @@ class BibleMediaItem(MediaManagerItem):
else:
bible_text = u'%s %s&nbsp;%s\n' % (bible_text, verse_text, text)
if not old_item:
start_item = item
elif self.checkTitle(item, old_item):
start_item = bitem
elif self.checkTitle(bitem, old_item):
raw_title.append(self.formatTitle(start_item, old_item))
start_item = item
old_item = item
start_item = bitem
old_item = bitem
old_chapter = chapter
# Add footer
service_item.raw_footer.append(verses.format_verses())
@ -764,7 +779,7 @@ class BibleMediaItem(MediaManagerItem):
verses.add_version(second_version, second_copyright,
second_permissions)
service_item.raw_footer.append(verses.format_versions())
raw_title.append(self.formatTitle(start_item, item))
raw_title.append(self.formatTitle(start_item, bitem))
# If there are no more items we check whether we have to add bible_text.
if bible_text:
raw_slides.append(bible_text.lstrip())
@ -787,9 +802,9 @@ class BibleMediaItem(MediaManagerItem):
[service_item.add_from_text(slide[:30], slide) for slide in raw_slides]
return True
def formatTitle(self, start_item, old_item):
def formatTitle(self, start_bitem, old_bitem):
"""
This methode is called, when we have to change the title, because
This method is called, when we have to change the title, because
we are at the end of a verse range. E. g. if we want to add
Genesis 1:1-6 as well as Daniel 2:14.
@ -801,10 +816,8 @@ class BibleMediaItem(MediaManagerItem):
"""
verse_separator = get_reference_match(u'sep_v_display')
range_separator = get_reference_match(u'sep_r_display')
old_bitem = self.listView.item(old_item.row())
old_chapter = self._decodeQtObject(old_bitem, 'chapter')
old_verse = self._decodeQtObject(old_bitem, 'verse')
start_bitem = self.listView.item(start_item.row())
start_book = self._decodeQtObject(start_bitem, 'book')
start_chapter = self._decodeQtObject(start_bitem, 'chapter')
start_verse = self._decodeQtObject(start_bitem, 'verse')
@ -825,9 +838,9 @@ class BibleMediaItem(MediaManagerItem):
range_separator + old_chapter + verse_separator + old_verse
return u'%s %s (%s)' % (start_book, verse_range, bibles)
def checkTitle(self, item, old_item):
def checkTitle(self, bitem, old_bitem):
"""
This methode checks if we are at the end of an verse range. If that is
This method checks if we are at the end of an verse range. If that is
the case, we return True, otherwise False. E. g. if we added
Genesis 1:1-6, but the next verse is Daniel 2:14, we return True.
@ -838,13 +851,11 @@ class BibleMediaItem(MediaManagerItem):
The item we were previously dealing with.
"""
# Get all the necessary meta data.
bitem = self.listView.item(item.row())
book = self._decodeQtObject(bitem, 'book')
chapter = int(self._decodeQtObject(bitem, 'chapter'))
verse = int(self._decodeQtObject(bitem, 'verse'))
bible = self._decodeQtObject(bitem, 'bible')
second_bible = self._decodeQtObject(bitem, 'second_bible')
old_bitem = self.listView.item(old_item.row())
old_book = self._decodeQtObject(old_bitem, 'book')
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
old_verse = int(self._decodeQtObject(old_bitem, 'verse'))
@ -896,3 +907,22 @@ class BibleMediaItem(MediaManagerItem):
if self.settings.display_style == DisplayStyle.Square:
return u'{su}[%s]{/su}' % verse_text
return u'{su}%s{/su}' % verse_text
def search(self, string):
"""
Search for some Bible verses (by reference).
"""
bible = unicode(self.quickVersionComboBox.currentText())
search_results = self.parent.manager.get_verses(bible, string, False)
results = []
if search_results:
versetext = u' '.join([verse.text for verse in search_results])
return [[string, versetext]]
return []
def createItemFromId(self, item_id):
item = QtGui.QListWidgetItem()
bible = unicode(self.quickVersionComboBox.currentText())
search_results = self.parent.manager.get_verses(bible, item_id, False)
items = self.buildDisplayResults(bible, u'', search_results)
return items

View File

@ -27,6 +27,7 @@
import logging
from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_, func
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
check_item_selected
@ -47,6 +48,7 @@ class CustomMediaItem(MediaManagerItem):
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
self.quickPreviewAllowed = True
self.hasSearch = True
# Holds information about whether the edit is remotly triggered and
# which Custom is required.
self.remoteCustom = -1
@ -161,4 +163,16 @@ class CustomMediaItem(MediaManagerItem):
else:
raw_footer.append(u'')
service_item.raw_footer = raw_footer
return True
return True
def search(self, string):
search_results = self.manager.get_all_objects(CustomSlide,
or_(func.lower(CustomSlide.title).like(u'%' +
string.lower() + u'%'),
func.lower(CustomSlide.text).like(u'%' +
string.lower() + u'%')),
order_by_ref=CustomSlide.title)
results = []
for custom in search_results:
results.append([custom.id, custom.title])
return results

View File

@ -47,6 +47,7 @@ class ImageMediaItem(MediaManagerItem):
self.IconPath = u'images/image'
MediaManagerItem.__init__(self, parent, self, icon)
self.quickPreviewAllowed = True
self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged)
@ -130,51 +131,51 @@ class ImageMediaItem(MediaManagerItem):
self.parent.formparent.finishedProgressBar()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
items = self.listView.selectedIndexes()
if items:
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)
# force a nonexistent theme
service_item.theme = -1
missing_items = []
missing_items_filenames = []
for item in items:
bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if not os.path.exists(filename):
missing_items.append(item)
missing_items_filenames.append(filename)
for item in missing_items:
items.remove(item)
# We cannot continue, as all images do not exist.
if not items:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem',
'The following image(s) no longer exist: %s')) %
u'\n'.join(missing_items_filenames))
return False
# We have missing as well as existing images. We ask what to do.
elif missing_items and QtGui.QMessageBox.question(self,
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem', 'The following '
'image(s) no longer exist: %s\nDo you want to add the other '
'images anyway?')) % u'\n'.join(missing_items_filenames),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
return False
# Continue with the existing images.
for item in items:
bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
(path, name) = os.path.split(filename)
service_item.add_from_image(filename, name)
return True
if item:
items = [item]
else:
items = self.listView.selectedItems()
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)
# force a nonexistent theme
service_item.theme = -1
missing_items = []
missing_items_filenames = []
for bitem in items:
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if not os.path.exists(filename):
missing_items.append(item)
missing_items_filenames.append(filename)
for item in missing_items:
items.remove(item)
# We cannot continue, as all images do not exist.
if not items:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem',
'The following image(s) no longer exist: %s')) %
u'\n'.join(missing_items_filenames))
return False
# We have missing as well as existing images. We ask what to do.
elif missing_items and QtGui.QMessageBox.question(self,
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem', 'The following '
'image(s) no longer exist: %s\nDo you want to add the other '
'images anyway?')) % u'\n'.join(missing_items_filenames),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
return False
# Continue with the existing images.
for bitem in items:
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
(path, name) = os.path.split(filename)
service_item.add_from_image(filename, name)
return True
def onResetClick(self):
"""
@ -208,3 +209,14 @@ class ImageMediaItem(MediaManagerItem):
unicode(translate('ImagePlugin.MediaItem',
'There was a problem replacing your background, '
'the image file "%s" no longer exists.')) % filename)
def search(self, string):
list = SettingsManager.load_list(self.settingsSection,
self.settingsSection)
results = []
string = string.lower()
for file in list:
filename = os.path.split(unicode(file))[1]
if filename.lower().find(string) > -1:
results.append([file, filename])
return results

View File

@ -50,6 +50,7 @@ class MediaMediaItem(MediaManagerItem):
u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
self.hasSearch = True
self.mediaObject = None
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'),
@ -212,3 +213,14 @@ class MediaMediaItem(MediaManagerItem):
log.debug(u'CreatePhonon')
if not self.mediaObject:
self.mediaObject = Phonon.MediaObject(self)
def search(self, string):
list = SettingsManager.load_list(self.settingsSection,
self.settingsSection)
results = []
string = string.lower()
for file in list:
filename = os.path.split(unicode(file))[1]
if filename.lower().find(string) > -1:
results.append([file, filename])
return results

View File

@ -53,6 +53,7 @@ class PresentationMediaItem(MediaManagerItem):
self.Automatic = u''
MediaManagerItem.__init__(self, parent, self, icon)
self.message_listener = MessageListener(self)
self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
@ -231,17 +232,19 @@ class PresentationMediaItem(MediaManagerItem):
in the slidecontroller. In the case of powerpoints, an image
for each slide
"""
items = self.listView.selectedIndexes()
if len(items) > 1:
return False
if item:
items = [item]
else:
items = self.listView.selectedItems()
if len(items) > 1:
return False
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)
shortname = service_item.shortname
if shortname:
for item in items:
bitem = self.listView.item(item.row())
for bitem in items:
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename):
if shortname == self.Automatic:
@ -303,3 +306,12 @@ class PresentationMediaItem(MediaManagerItem):
if filetype in self.controllers[controller].alsosupports:
return controller
return None
def search(self, string):
list = SettingsManager.load_list(self.settingsSection, u'presentations')
results = []
string = string.lower()
for file in list:
if file.lower().find(string) > -1:
results.append([file, file])
return results

View File

@ -43,6 +43,7 @@
<a href="#service-manager" data-role="button" data-icon="arrow-r" data-iconpos="right">Service Manager</a>
<a href="#slide-controller" data-role="button" data-icon="arrow-r" data-iconpos="right">Slide Controller</a>
<a href="#alerts" data-role="button" data-icon="arrow-r" data-iconpos="right">Alerts</a>
<a href="#search" data-role="button" data-icon="arrow-r" data-iconpos="right">Search</a>
</div>
</div>
</div>
@ -50,6 +51,7 @@
<div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a>
<h1>Service Manager</h1>
<a href="#" id="service-refresh" data-role="button" data-icon="refresh">Refresh</a>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
@ -57,9 +59,8 @@
</div>
<div data-role="footer" data-theme="b" class="ui-bar">
<a href="#" id="service-blank" data-role="button" data-icon="blank">Blank</a>
<a href="#" id="service-unblank" data-role="button" data-icon="unblank">Unblank</a>
<a href="#" id="service-refresh" data-role="button" data-icon="refresh">Refresh</a>
<a href="#" id="service-previous" data-role="button" data-icon="arrow-l">Previous</a>
<a href="#" id="service-unblank" data-role="button" data-icon="unblank">Show</a>
<a href="#" id="service-previous" data-role="button" data-icon="arrow-l">Prev</a>
<a href="#" id="service-next" data-role="button" data-icon="arrow-r" data-iconpos="right">Next</a>
</div>
</div>
@ -67,6 +68,7 @@
<div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a>
<h1>Slide Controller</h1>
<a href="#" id="controller-refresh" data-role="button" data-icon="refresh">Refresh</a>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
@ -74,9 +76,8 @@
</div>
<div data-role="footer" data-theme="b" class="ui-bar">
<a href="#" id="controller-blank" data-role="button" data-icon="blank">Blank</a>
<a href="#" id="controller-unblank" data-role="button" data-icon="unblank">Unblank</a>
<a href="#" id="controller-refresh" data-role="button" data-icon="refresh">Refresh</a>
<a href="#" id="controller-previous" data-role="button" data-icon="arrow-l">Previous</a>
<a href="#" id="controller-unblank" data-role="button" data-icon="unblank">Show</a>
<a href="#" id="controller-previous" data-role="button" data-icon="arrow-l">Prev</a>
<a href="#" id="controller-next" data-role="button" data-icon="arrow-r" data-iconpos="right">Next</a>
</div>
</div>
@ -93,5 +94,23 @@
<a href="#" id="alert-submit" data-role="button">Show Alert</a>
</div>
</div>
<div data-role="page" id="search">
<div data-role="header">
<a href="#" data-rel="back" data-icon="arrow-l">Back</a>
<h1>Search</h1>
</div>
<div data-role="content">
<div data-role="fieldcontain">
<label for="search-plugin">Search:</label>
<select name="search-plugin" id="search-plugin" data-native-menu="false"></select>
</div>
<div data-role="fieldcontain">
<label for="search-text">Text:</label>
<input type="search" name="search-text" id="search-text" value="" />
</div>
<a href="#" id="search-submit" data-role="button">Search</a>
<ul data-role="listview" data-inset="true">
</div>
</div>
</body>
</html>

View File

@ -39,6 +39,19 @@ window.OpenLP = {
}
return $(targ);
},
getSearchablePlugins: function (event) {
$.getJSON(
"/api/plugin/search",
function (data, status) {
var select = $("#search-plugin");
select.html("");
$.each(data.results.items, function (idx, value) {
select.append("<option value='" + value + "'>" + value + "</option>");
});
select.selectmenu("refresh");
}
);
},
loadService: function (event) {
$.getJSON(
"/api/service/list",
@ -63,7 +76,9 @@ window.OpenLP = {
var ul = $("#slide-controller > div[data-role=content] > ul[data-role=listview]");
ul.html("");
for (idx in data.results.slides) {
var text = data.results.slides[idx]["text"];
var text = data.results.slides[idx]["tag"];
if (text != "") text = text + ": ";
text = text + data.results.slides[idx]["text"];
text = text.replace(/\n/g, '<br />');
var li = $("<li data-icon=\"false\">").append(
$("<a href=\"#\">").attr("value", parseInt(idx, 10)).html(text));
@ -189,7 +204,43 @@ window.OpenLP = {
}
);
return false;
},
search: function (event) {
var text = JSON.stringify({"request": {"text": $("#search-text").val()}});
$.getJSON(
"/api/" + $("#search-plugin").val() + "/search",
{"data": text},
function (data, status) {
var ul = $("#search > div[data-role=content] > ul[data-role=listview]");
ul.html("");
if (data.results.items.length == 0) {
var li = $("<li data-icon=\"false\">").text('No results');
ul.append(li);
}
else {
$.each(data.results.items, function (idx, value) {
var li = $("<li data-icon=\"false\">").append(
$("<a href=\"#\">").attr("value", value[0]).text(value[1]));
li.children("a").click(OpenLP.goLive);
ul.append(li);
});
}
ul.listview("refresh");
}
);
return false;
},
goLive: function (event) {
var slide = OpenLP.getElement(event);
var id = slide.attr("value");
var text = JSON.stringify({"request": {"id": id}});
$.getJSON(
"/api/" + $("#search-plugin").val() + "/live",
{"data": text})
$.mobile.changePage("slide-controller");
return false;
}
}
// Service Manager
$("#service-manager").live("pagebeforeshow", OpenLP.loadService);
@ -207,7 +258,10 @@ $("#controller-blank").live("click", OpenLP.blankDisplay);
$("#controller-unblank").live("click", OpenLP.unblankDisplay);
// Alerts
$("#alert-submit").live("click", OpenLP.showAlert);
// Search
$("#search-submit").live("click", OpenLP.search);
// Poll the server twice a second to get any updates.
OpenLP.getSearchablePlugins();
$.ajaxSetup({ cache: false });
setInterval("OpenLP.pollServer();", 500);
OpenLP.pollServer();

View File

@ -123,7 +123,7 @@ except ImportError:
from PyQt4 import QtCore, QtNetwork
from openlp.core.lib import Receiver
from openlp.core.lib import Receiver, PluginStatus
from openlp.core.ui import HideMode
from openlp.core.utils import AppLocation
@ -250,7 +250,10 @@ class HttpConnection(object):
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
(r'^/api/service/(.*)$', self.service),
(r'^/api/display/(hide|show)$', self.display),
(r'^/api/alert$', self.alert)
(r'^/api/alert$', self.alert),
(r'^/api/plugin/(search)$', self.pluginInfo),
(r'^/api/(.*)/search$', self.search),
(r'^/api/(.*)/live$', self.go_live)
]
QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'readyRead()'),
self.ready_read)
@ -409,8 +412,8 @@ class HttpConnection(object):
item[u'html'] = unicode(frame[u'html'])
else:
item[u'tag'] = unicode(index + 1)
item[u'text'] = u''
item[u'html'] = u''
item[u'text'] = unicode(frame[u'title'])
item[u'html'] = unicode(frame[u'title'])
item[u'selected'] = (self.parent.current_slide == index)
data.append(item)
json_data = {u'results': {u'slides': data}}
@ -443,6 +446,50 @@ class HttpConnection(object):
return HttpResponse(json.dumps({u'results': {u'success': True}}),
{u'Content-Type': u'application/json'})
def pluginInfo(self, action):
"""
Return plugin related information, based on the action
``action`` - The action to perform
if 'search' return a list of plugin names which support search
"""
if action == u'search':
searches = []
for plugin in self.parent.parent.pluginManager.plugins:
if plugin.status == PluginStatus.Active and \
plugin.mediaItem and plugin.mediaItem.hasSearch:
searches.append(plugin.name)
return HttpResponse(
json.dumps({u'results': {u'items': searches}}),
{u'Content-Type': u'application/json'})
def search(self, type):
"""
Return a list of items that match the search text
``type``
The plugin name to search in.
"""
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and \
plugin.mediaItem and plugin.mediaItem.hasSearch:
results =plugin.mediaItem.search(text)
else:
results = []
return HttpResponse(
json.dumps({u'results': {u'items': results}}),
{u'Content-Type': u'application/json'})
def go_live(self, type):
"""
Go live on an item of type ``type``.
"""
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
plugin = self.parent.parent.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
plugin.mediaItem.goLive(id)
def send_response(self, response):
http = u'HTTP/1.1 %s\r\n' % response.code
for header, value in response.headers.iteritems():

View File

@ -74,6 +74,7 @@ class SongMediaItem(MediaManagerItem):
self.editItem = None
self.whitespace = re.compile(r'\W+', re.UNICODE)
self.quickPreviewAllowed = True
self.hasSearch = True
def addEndHeaderBar(self):
self.addToolbarSeparator()
@ -171,11 +172,7 @@ class SongMediaItem(MediaManagerItem):
search_type = self.searchTextEdit.currentSearchType()
if search_type == SongSearch.Entire:
log.debug(u'Entire Song Search')
search_results = self.parent.manager.get_all_objects(Song,
or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ',
search_keywords.lower()) + u'%'),
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'),
Song.comments.like(u'%' + search_keywords.lower() + u'%')))
search_results = self.searchEntire(search_keywords)
self.displayResultsSong(search_results)
elif search_type == SongSearch.Titles:
log.debug(u'Titles Search')
@ -201,6 +198,13 @@ class SongMediaItem(MediaManagerItem):
self.displayResultsSong(search_results)
self.check_search_result()
def searchEntire(self, search_keywords):
return self.parent.manager.get_all_objects(Song,
or_(Song.search_title.like(u'%' + self.whitespace.sub(u' ',
search_keywords.lower()) + u'%'),
Song.search_lyrics.like(u'%' + search_keywords.lower() + u'%'),
Song.comments.like(u'%' + search_keywords.lower() + u'%')))
def onSongListLoad(self):
"""
Handle the exit from the edit dialog and trigger remote updates
@ -217,7 +221,8 @@ class SongMediaItem(MediaManagerItem):
# Push edits to the service manager to update items
if self.editItem and self.updateServiceOnEdit and \
not self.remoteTriggered:
item = self.buildServiceItem(self.editItem)
item_id = _getIdOfItemToGenerate(self.editItem)
item = self.buildServiceItem(item_id)
self.parent.serviceManager.replaceServiceItem(item)
self.onRemoteEditClear()
self.onSearchTextButtonClick()
@ -475,3 +480,13 @@ class SongMediaItem(MediaManagerItem):
"""
return locale.strcoll(unicode(song_1.title.lower()),
unicode(song_2.title.lower()))
def search(self, string):
"""
Search for some songs
"""
search_results = self.searchEntire(string)
results = []
for song in search_results:
results.append([song.id, song.title])
return results

View File

@ -268,4 +268,3 @@ class SongsPlugin(Plugin):
action_list.remove_action(self.songExportItem, UiStrings().Export)
action_list.remove_action(self.toolsReindexItem, UiStrings().Tools)
Plugin.finalise(self)