diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 9c1a84c99..2e514935f 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -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') diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 0fddc75c4..682352aa5 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -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 diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 5a4e62254..20d5c3d62 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -300,7 +300,7 @@ class Renderer(object): # Adjust width and height to account for shadow. outline done in css self.page_shell = u'' \ + u'#main {position:absolute; top:0px; %s %s}' \ u'
' % \ (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index e1396d984..53fd37ed9 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -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): """ diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py index b8169b9be..c439fc116 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/displaytagform.py @@ -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 diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 6452a2fca..0bbaaaf1b 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -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): diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index e0261570e..a0d8ba325 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -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): """ diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 7d8ca77db..ee5491878 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -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') diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 0adcff985..02c9dd49d 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -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 %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 diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 4bd3a8d4b..e05b56314 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -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 \ No newline at end of file + 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 diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 21b81128d..1377feef8 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -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 diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index aa574d029..9f1d72f73 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -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 diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 65b85454d..7660c9099 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -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 diff --git a/openlp/plugins/remotes/html/index.html b/openlp/plugins/remotes/html/index.html index 3708db654..fd7fb3715 100644 --- a/openlp/plugins/remotes/html/index.html +++ b/openlp/plugins/remotes/html/index.html @@ -43,6 +43,7 @@ Service Manager Slide Controller Alerts + Search
@@ -50,6 +51,7 @@
Back

Service Manager

+ Refresh
Blank - Unblank - Refresh - Previous + Show + Prev Next
@@ -67,6 +68,7 @@
Back

Slide Controller

+ Refresh
Blank - Unblank - Refresh - Previous + Show + Prev Next
@@ -93,5 +94,23 @@ Show Alert + diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 74463ffbc..4eee047a4 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -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(""); + }); + 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, '
'); var li = $("
  • ").append( $("").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 = $("
  • ").text('No results'); + ul.append(li); + } + else { + $.each(data.results.items, function (idx, value) { + var li = $("
  • ").append( + $("").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(); diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 20005840c..351e7f905 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -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(): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 8ac69392e..59ee05b7a 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -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 diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index f3c5705da..0091406d1 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -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) -