Stage View (via remote) plus some remote fixes

bzr-revno: 1523
This commit is contained in:
Jonathan Corwin 2011-05-08 09:21:55 +01:00
commit a6cfb00334
8 changed files with 279 additions and 35 deletions

View File

@ -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

View File

@ -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.

View File

@ -48,6 +48,7 @@ window.OpenLP = {
$.each(data.results.items, function (idx, value) {
var li = $("<li data-icon=\"false\">").append(
$("<a href=\"#\">").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;
}

View File

@ -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;
}

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<!--
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 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 #
###############################################################################
-->
<head>
<meta charset="utf-8" />
<title>OpenLP 2.0 Remote</title>
<link rel="stylesheet" href="/files/stage.css" />
<script type="text/javascript" src="/files/jquery.js"></script>
<script type="text/javascript" src="/files/stage.js"></script>
</head>
<body>
<div id="right">
<div id="clock"></div>
<div id="notes"></div>
</div>
<div id="verseorder"></div>
<div id="currentslide"></div>
<div id="nextslide"></div>
</body>
</html>

View File

@ -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("&nbsp;<span>");
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();

View File

@ -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}),

View File

@ -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'<a href="%s">%s</a>' % (url, url))
url = url + u'stage'
self.stageUrl.setText(u'<a href="%s">%s</a>' % (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',