diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index bee195b0f..f193ccd16 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -111,10 +111,6 @@ class EventReceiver(QtCore.QObject): ``servicemanager_set_item`` Go live on a specific item, by index - ``servicemanager_list_request`` - Request the service list. Responds with servicemanager_list_response - containing a array of dictionaries - ``maindisplay_blank`` Blank the maindisplay window diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index d39c4ec6f..b5e8bbc54 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -274,8 +274,6 @@ class ServiceManager(QtGui.QWidget): QtCore.SIGNAL(u'servicemanager_previous_item'), self.previousItem) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_set_item'), self.onSetItem) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated) QtCore.QObject.connect(Receiver.get_receiver(), @@ -1307,23 +1305,6 @@ class ServiceManager(QtGui.QWidget): else: return parentitem.data(0, QtCore.Qt.UserRole).toInt()[0] - def listRequest(self, message=None): - data = [] - item = self.findServiceItem()[0] - if item >= 0 and item < len(self.serviceItems): - curitem = self.serviceItems[item] - else: - curitem = None - for item in self.serviceItems: - service_item = item[u'service_item'] - data_item = {} - data_item[u'title'] = unicode(service_item.get_display_title()) - data_item[u'plugin'] = unicode(service_item.name) - data_item[u'notes'] = unicode(service_item.notes) - data_item[u'selected'] = (item == curitem) - data.append(data_item) - Receiver.send_message(u'servicemanager_list_response', data) - def printServiceOrder(self): """ Print a Service Order Sheet. diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js index e6efbb2c5..811ce0cac 100644 --- a/openlp/plugins/remotes/html/openlp.js +++ b/openlp/plugins/remotes/html/openlp.js @@ -48,6 +48,7 @@ window.OpenLP = { $.each(data.results.items, function (idx, value) { var li = $("
  • ").append( $("").attr("value", parseInt(idx, 10)).text(value["title"])); + li.attr("uuid", value["id"]) li.children("a").click(OpenLP.setItem); ul.append(li); }); @@ -119,10 +120,10 @@ window.OpenLP = { $("#service-manager div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c"); $("#service-manager div[data-role=content] ul[data-role=listview] li a").each(function () { var item = $(this); - if (item.text() == OpenLP.currentItem) { - while (item[0].tagName != "LI") { - item = item.parent(); - } + while (item[0].tagName != "LI") { + item = item.parent(); + } + if (item.attr("uuid") == OpenLP.currentItem) { item.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e"); return false; } diff --git a/openlp/plugins/remotes/html/stage.css b/openlp/plugins/remotes/html/stage.css new file mode 100644 index 000000000..a773c2393 --- /dev/null +++ b/openlp/plugins/remotes/html/stage.css @@ -0,0 +1,66 @@ +/***************************************************************************** + * OpenLP - Open Source Lyrics Projection * + * ------------------------------------------------------------------------- * + * Copyright (c) 2008-2010 Raoul Snyman * + * Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael * + * Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, * + * Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, * + * Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund * + * ------------------------------------------------------------------------- * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; version 2 of the License. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * + * Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *****************************************************************************/ + +body { + background-color: black; + font-family: sans-serif; + overflow: hidden; +} + +#currentslide { + font-size: 40pt; + color: white; +} + +#nextslide { + font-size: 30pt; + color: grey; + padding-top: 25px; +} + +#right { + float: right; +} + +#clock { + font-size: 40pt; + color: yellow; + text-align: right; +} + +#notes { + font-size: 36pt; + color: salmon; + text-align: right; +} + +#verseorder { + font-size: 30pt; + color: green; + text-align: left; +} + +.currenttag { + color: lightgreen; + font-weight: bold; +} diff --git a/openlp/plugins/remotes/html/stage.html b/openlp/plugins/remotes/html/stage.html new file mode 100644 index 000000000..99090b6f9 --- /dev/null +++ b/openlp/plugins/remotes/html/stage.html @@ -0,0 +1,43 @@ + + + + + + OpenLP 2.0 Remote + + + + + + +
    +
    +
    + + diff --git a/openlp/plugins/remotes/html/stage.js b/openlp/plugins/remotes/html/stage.js new file mode 100644 index 000000000..8b8a83f6a --- /dev/null +++ b/openlp/plugins/remotes/html/stage.js @@ -0,0 +1,104 @@ +/***************************************************************************** + * OpenLP - Open Source Lyrics Projection * + * ------------------------------------------------------------------------- * + * Copyright (c) 2008-2010 Raoul Snyman * + * Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael * + * Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, * + * Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, * + * Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund * + * ------------------------------------------------------------------------- * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; version 2 of the License. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * + * Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + *****************************************************************************/ +window.OpenLP = { + loadService: function (event) { + $.getJSON( + "/api/service/list", + function (data, status) { + OpenLP.nextSong = ""; + $("#notes").html(""); + for (idx in data.results.items) { + idx = parseInt(idx, 10); + if ((data.results.items[idx]["selected"]) && + (data.results.items.length > idx + 1)) { + $("#notes").html(data.results.items[idx]["notes"]); + OpenLP.nextSong = data.results.items[idx + 1]["title"]; + break; + } + } + OpenLP.updateSlide(); + } + ); + }, + loadSlides: function (event) { + $.getJSON( + "/api/controller/live/text", + function (data, status) { + OpenLP.currentSlides = data.results.slides; + OpenLP.currentSlide = 0; + var div = $("#verseorder"); + div.html(""); + for (idx in data.results.slides) { + idx = parseInt(idx, 10); + div.append(" "); + var tag = data.results.slides[idx]["tag"]; + if (tag == 'None') + tag = idx; + $("#verseorder span").last().attr("id", "tag" + idx).text(tag); + if (data.results.slides[idx]["selected"]) + OpenLP.currentSlide = idx; + } + OpenLP.loadService(); + } + ); + }, + updateSlide: function() { + $("#verseorder span").removeClass("currenttag"); + $("#tag" + OpenLP.currentSlide).addClass("currenttag"); + $("#currentslide").html(OpenLP.currentSlides[OpenLP.currentSlide]["text"]); + if (OpenLP.currentSlide < OpenLP.currentSlides.length - 1) + $("#nextslide").html(OpenLP.currentSlides[OpenLP.currentSlide + 1]["text"]); + else + $("#nextslide").html("Next: " + OpenLP.nextSong); + }, + updateClock: function() { + var div = $("#clock"); + var t = new Date(); + var h = t.getHours(); + if (h > 12) + h = h - 12; + var m = t.getMinutes(); + if (m < 10) + m = '0' + m + ''; + div.html(h + ":" + m); + }, + pollServer: function () { + $.getJSON( + "/api/poll", + function (data, status) { + OpenLP.updateClock(); + if (OpenLP.currentItem != data.results.item) { + OpenLP.currentItem = data.results.item; + OpenLP.loadSlides(); + } + else if (OpenLP.currentSlide != data.results.slide) { + OpenLP.currentSlide = parseInt(data.results.slide, 10); + OpenLP.updateSlide(); + } + } + ); + } +} +$.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 caf4ba396..70f02ff36 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -34,6 +34,9 @@ the remotes. ``/`` Go to the web interface. +``/stage`` + Show the stage view. + ``/files/{filename}`` Serve a static file. @@ -241,6 +244,7 @@ class HttpConnection(object): self.parent = parent self.routes = [ (u'^/$', self.serve_file), + (u'^/(stage)$', self.serve_file), (r'^/files/(.*)$', self.serve_file), (r'^/api/poll$', self.poll), (r'^/api/controller/(live|preview)/(.*)$', self.controller), @@ -256,18 +260,18 @@ class HttpConnection(object): def _get_service_items(self): service_items = [] service_manager = self.parent.parent.serviceManager - item = service_manager.findServiceItem()[0] - if item >= 0 and item < len(service_manager.serviceItems): - curitem = service_manager.serviceItems[item] + if self.parent.current_item: + cur_uuid = self.parent.current_item._uuid else: - curitem = None + cur_uuid = None for item in service_manager.serviceItems: service_item = item[u'service_item'] service_items.append({ + u'id': unicode(service_item._uuid), u'title': unicode(service_item.get_display_title()), u'plugin': unicode(service_item.name), u'notes': unicode(service_item.notes), - u'selected': (item == curitem) + u'selected': (service_item._uuid == cur_uuid) }) return service_items @@ -312,6 +316,8 @@ class HttpConnection(object): log.debug(u'serve file request %s' % filename) if not filename: filename = u'index.html' + elif filename == u'stage': + filename = u'stage.html' path = os.path.normpath(os.path.join(self.parent.html_dir, filename)) if not path.startswith(self.parent.html_dir): return HttpResponse(code=u'404 Not Found') @@ -349,7 +355,7 @@ class HttpConnection(object): """ result = { u'slide': self.parent.current_slide or 0, - u'item': self.parent.current_item.title \ + u'item': self.parent.current_item._uuid \ if self.parent.current_item else u'' } return HttpResponse(json.dumps({u'results': result}), diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index 297437d93..bfb05d486 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -24,10 +24,12 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtCore, QtGui, QtNetwork from openlp.core.lib import SettingsTab, translate +ZERO_URL = u'0.0.0.0' + class RemoteTab(SettingsTab): """ RemoteTab is the Remotes settings tab in the settings dialog. @@ -51,13 +53,29 @@ class RemoteTab(SettingsTab): self.addressEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp( u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'), self)) self.addressEdit.setObjectName(u'addressEdit') + QtCore.QObject.connect(self.addressEdit, + QtCore.SIGNAL(u'textChanged(const QString&)'), self.setUrls) self.serverSettingsLayout.addRow(self.addressLabel, self.addressEdit) self.portLabel = QtGui.QLabel(self.serverSettingsGroupBox) self.portLabel.setObjectName(u'portLabel') self.portSpinBox = QtGui.QSpinBox(self.serverSettingsGroupBox) self.portSpinBox.setMaximum(32767) self.portSpinBox.setObjectName(u'portSpinBox') + QtCore.QObject.connect(self.portSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), self.setUrls) self.serverSettingsLayout.addRow(self.portLabel, self.portSpinBox) + self.remoteUrlLabel = QtGui.QLabel(self.serverSettingsGroupBox) + self.remoteUrlLabel.setObjectName(u'remoteUrlLabel') + self.remoteUrl = QtGui.QLabel(self.serverSettingsGroupBox) + self.remoteUrl.setObjectName(u'remoteUrl') + self.remoteUrl.setOpenExternalLinks(True) + self.serverSettingsLayout.addRow(self.remoteUrlLabel, self.remoteUrl) + self.stageUrlLabel = QtGui.QLabel(self.serverSettingsGroupBox) + self.stageUrlLabel.setObjectName(u'stageUrlLabel') + self.stageUrl = QtGui.QLabel(self.serverSettingsGroupBox) + self.stageUrl.setObjectName(u'stageUrl') + self.stageUrl.setOpenExternalLinks(True) + self.serverSettingsLayout.addRow(self.stageUrlLabel, self.stageUrl) self.leftLayout.addWidget(self.serverSettingsGroupBox) self.leftLayout.addStretch() self.rightLayout.addStretch() @@ -69,6 +87,34 @@ class RemoteTab(SettingsTab): 'Serve on IP address:')) self.portLabel.setText(translate('RemotePlugin.RemoteTab', 'Port number:')) + self.remoteUrlLabel.setText(translate('RemotePlugin.RemoteTab', + 'Remote URL:')) + self.stageUrlLabel.setText(translate('RemotePlugin.RemoteTab', + 'Stage view URL:')) + + def setUrls(self): + ipAddress = None + if self.addressEdit.text() == ZERO_URL: + for ip in QtNetwork.QNetworkInterface.allAddresses(): + if ip.protocol() == 0 and ip != QtNetwork.QHostAddress.LocalHost: + ipAddress = ip.toString() + break + else: + ipAddress = self.addressEdit.text() + if not ipAddress: + self.remoteUrlLabel.setVisible(False) + self.remoteUrl.setVisible(False) + self.stageUrlLabel.setVisible(False) + self.stageUrl.setVisible(False) + return + self.remoteUrlLabel.setVisible(True) + self.remoteUrl.setVisible(True) + self.stageUrlLabel.setVisible(True) + self.stageUrl.setVisible(True) + url = u'http://%s:%s/' % (ipAddress, self.portSpinBox.value()) + self.remoteUrl.setText(u'
    %s' % (url, url)) + url = url + u'stage' + self.stageUrl.setText(u'%s' % (url, url)) def load(self): self.portSpinBox.setValue( @@ -76,7 +122,8 @@ class RemoteTab(SettingsTab): QtCore.QVariant(4316)).toInt()[0]) self.addressEdit.setText( QtCore.QSettings().value(self.settingsSection + u'/ip address', - QtCore.QVariant(u'0.0.0.0')).toString()) + QtCore.QVariant(ZERO_URL)).toString()) + self.setUrls() def save(self): QtCore.QSettings().setValue(self.settingsSection + u'/port',