From 047287950cb748267c4ef9d863c15cd6fb8ba709 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Sat, 14 May 2011 10:48:58 +0100 Subject: [PATCH] Remote song search and go live beginnings --- openlp/core/lib/mediamanageritem.py | 30 ++++++++++++--- openlp/core/lib/pluginmanager.py | 11 +++++- openlp/plugins/remotes/html/index.html | 19 +++++++++- openlp/plugins/remotes/html/openlp.js | 38 +++++++++++++++++++ openlp/plugins/remotes/lib/httpserver.py | 48 +++++++++++++++++++++++- openlp/plugins/songs/lib/mediaitem.py | 32 +++++++++++++--- openlp/plugins/songs/songsplugin.py | 1 - 7 files changed, 163 insertions(+), 16 deletions(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 99a42e3cf..fab50b4dc 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -475,11 +475,18 @@ 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: - serviceItem.from_plugin = True - self.parent.liveController.addServiceItem(serviceItem) + self.goLive() + + def goLive(self, item_id=None): + log.debug(u'%s Live requested', self.plugin.name) + item = None + if item_id: + item = QtGui.QListWidgetItem() + item.setData(QtCore.Qt.UserRole, QtCore.QVariant(item_id)) + serviceItem = self.buildServiceItem(item) + if serviceItem: + serviceItem.from_plugin = True + self.parent.liveController.addServiceItem(serviceItem) def onAddClick(self): """ @@ -573,3 +580,16 @@ class MediaManagerItem(QtGui.QWidget): else: item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] return item_id + + def hasSearch(self): + """ + Returns whether this plugin supports the search method + """ + return False + + def search(self, string): + """ + Performs a plugin specific search for items containing ``string`` + """ + raise NotImplementedError( + u'Plugin.about needs to be defined by the plugin') diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 0fddc75c4..3e1620378 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -45,7 +45,7 @@ class PluginManager(object): """ The constructor for the plugin manager. Passes the controllers on to the plugins for them to interact with via their ServiceItems. - +pluginmanager.py ``plugin_dir`` The directory to search for plugins. """ @@ -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/plugins/remotes/html/index.html b/openlp/plugins/remotes/html/index.html index 3708db654..bbb0644c3 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 @@ -55,7 +56,7 @@ -
+
Blank Unblank Refresh @@ -72,7 +73,7 @@
-
+
Blank Unblank Refresh @@ -93,5 +94,19 @@ Show Alert
+ diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index 74463ffbc..4945e366f 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -189,7 +189,43 @@ window.OpenLP = { } ); return false; + }, + search: function (event) { + var text = JSON.stringify({"request": {"text": $("#search-text").val()}}); + $.getJSON( + "/api/Songs/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/Songs/live", + {"data": text}) + window.location.replace('/#slide-controller'); + return false; } + } // Service Manager $("#service-manager").live("pagebeforeshow", OpenLP.loadService); @@ -207,6 +243,8 @@ $("#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. $.ajaxSetup({ cache: false }); setInterval("OpenLP.pollServer();", 500); diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 20005840c..cc56c18f8 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -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.plugin), + (r'^/api/(.*)/search$', self.search), + (r'^/api/(.*)/live$', self.go_live) ] QtCore.QObject.connect(self.socket, QtCore.SIGNAL(u'readyRead()'), self.ready_read) @@ -443,6 +446,49 @@ class HttpConnection(object): return HttpResponse(json.dumps({u'results': {u'success': True}}), {u'Content-Type': u'application/json'}) + def plugin(self, action): + """ + Return plugin related actions + + ``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: + media_item = plugin.mediaItem + if media_item and media_item.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) + media_item = plugin.mediaItem + if media_item and media_item.hasSearch(): + results = media_item.search(text) + 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) + media_item = plugin.mediaItem + if media_item: + media_item.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 3b014d4b0..ccd68705a 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -171,11 +171,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 +197,13 @@ class SongMediaItem(MediaManagerItem): self.displayResultsSong(search_results) check_search_result(self.listView, search_results) + 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 +220,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 +479,19 @@ class SongMediaItem(MediaManagerItem): """ return locale.strcoll(unicode(song_1.title.lower()), unicode(song_2.title.lower())) + + def hasSearch(self): + """ + Returns whether this plugin supports the search method + """ + return True + + 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) -