openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #20685
[Merge] lp:~trb143/openlp/cherrypy into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/cherrypy into lp:openlp.
Requested reviews:
Andreas Preikschat (googol)
Related bugs:
Bug #826724 in OpenLP: "Make the Web Remote password protected"
https://bugs.launchpad.net/openlp/+bug/826724
Bug #826731 in OpenLP: "Add optional SSL to web remote"
https://bugs.launchpad.net/openlp/+bug/826731
For more details, see:
https://code.launchpad.net/~trb143/openlp/cherrypy/+merge/167121
Add a /live option to the remote interface to all images of the live to be displayed.
This is a no secure option like stage.
Add comments to settings
Minor cleanups
--
https://code.launchpad.net/~trb143/openlp/cherrypy/+merge/167121
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2013-04-20 20:34:46 +0000
+++ openlp/core/ui/mainwindow.py 2013-06-03 18:51:25 +0000
@@ -779,8 +779,8 @@
"""
We need to make sure, that the SlidePreview's size is correct.
"""
- self.preview_controller.previewSizeChanged()
- self.live_controller.previewSizeChanged()
+ self.preview_controller.preview_size_changed()
+ self.live_controller.preview_size_changed()
def on_settings_shortcuts_item_clicked(self):
"""
@@ -989,8 +989,8 @@
self.application.set_busy_cursor()
self.image_manager.update_display()
self.renderer.update_display()
- self.preview_controller.screenSizeChanged()
- self.live_controller.screenSizeChanged()
+ self.preview_controller.screen_size_changed()
+ self.live_controller.screen_size_changed()
self.setFocus()
self.activateWindow()
self.application.set_normal_cursor()
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2013-04-23 21:46:07 +0000
+++ openlp/core/ui/slidecontroller.py 2013-06-03 18:51:25 +0000
@@ -89,7 +89,7 @@
Set up the Slide Controller.
"""
DisplayController.__init__(self, parent, is_live)
- Registry().register_function(u'bootstrap_post_set_up', self.screenSizeChanged)
+ Registry().register_function(u'bootstrap_post_set_up', self.screen_size_changed)
self.screens = ScreenList()
try:
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height())
@@ -121,6 +121,8 @@
self.update_slide_limits()
self.panel = QtGui.QWidget(parent.controlSplitter)
self.slideList = {}
+ self.slide_count = 0
+ self.slide_image = None
# Layout for holding panel
self.panel_layout = QtGui.QVBoxLayout(self.panel)
self.panel_layout.setSpacing(0)
@@ -321,18 +323,18 @@
self.slide_layout.insertWidget(0, self.preview_display)
self.preview_display.hide()
# Actual preview screen
- self.slidePreview = QtGui.QLabel(self)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.slidePreview.sizePolicy().hasHeightForWidth())
- self.slidePreview.setSizePolicy(sizePolicy)
- self.slidePreview.setFrameShape(QtGui.QFrame.Box)
- self.slidePreview.setFrameShadow(QtGui.QFrame.Plain)
- self.slidePreview.setLineWidth(1)
- self.slidePreview.setScaledContents(True)
- self.slidePreview.setObjectName(u'slidePreview')
- self.slide_layout.insertWidget(0, self.slidePreview)
+ self.slide_preview = QtGui.QLabel(self)
+ size_policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
+ size_policy.setHorizontalStretch(0)
+ size_policy.setVerticalStretch(0)
+ size_policy.setHeightForWidth(self.slide_preview.sizePolicy().hasHeightForWidth())
+ self.slide_preview.setSizePolicy(size_policy)
+ self.slide_preview.setFrameShape(QtGui.QFrame.Box)
+ self.slide_preview.setFrameShadow(QtGui.QFrame.Plain)
+ self.slide_preview.setLineWidth(1)
+ self.slide_preview.setScaledContents(True)
+ self.slide_preview.setObjectName(u'slide_preview')
+ self.slide_layout.insertWidget(0, self.slide_preview)
self.grid.addLayout(self.slide_layout, 0, 0, 1, 1)
if self.is_live:
self.current_shortcut = u''
@@ -517,10 +519,9 @@
self.service_manager.next_item()
self.keypress_loop = False
- def screenSizeChanged(self):
+ def screen_size_changed(self):
"""
- Settings dialog has changed the screen size of adjust output and
- screen previews.
+ Settings dialog has changed the screen size of adjust output and screen previews.
"""
# rebuild display as screen size changed
if self.display:
@@ -536,14 +537,14 @@
except ZeroDivisionError:
self.ratio = 1
self.media_controller.setup_display(self.display, False)
- self.previewSizeChanged()
+ self.preview_size_changed()
self.preview_display.setup()
service_item = ServiceItem()
self.preview_display.web_view.setHtml(build_html(service_item, self.preview_display.screen, None, self.is_live,
plugins=self.plugin_manager.plugins))
self.media_controller.setup_display(self.preview_display, True)
if self.service_item:
- self.refreshServiceItem()
+ self.refresh_service_item()
def __addActionsToWidget(self, widget):
"""
@@ -554,7 +555,7 @@
self.previousService, self.nextService,
self.escapeItem])
- def previewSizeChanged(self):
+ def preview_size_changed(self):
"""
Takes care of the SlidePreview's size. Is called when one of the the
splitters is moved or when the screen size is changed. Note, that this
@@ -563,14 +564,14 @@
if self.ratio < float(self.preview_frame.width()) / float(self.preview_frame.height()):
# We have to take the height as limit.
max_height = self.preview_frame.height() - self.grid.margin() * 2
- self.slidePreview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
+ self.slide_preview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.preview_display.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.preview_display.screen = {
u'size': self.preview_display.geometry()}
else:
# We have to take the width as limit.
max_width = self.preview_frame.width() - self.grid.margin() * 2
- self.slidePreview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
+ self.slide_preview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.screen = {
u'size': self.preview_display.geometry()}
@@ -624,17 +625,16 @@
"""
self.slide_limits = Settings().value(self.main_window.advanced_settings_section + u'/slide limits')
- def enableToolBar(self, item):
+ def enable_tool_bar(self, item):
"""
- Allows the toolbars to be reconfigured based on Controller Type
- and ServiceItem Type
+ Allows the toolbars to be reconfigured based on Controller Type and ServiceItem Type
"""
if self.is_live:
- self.enableLiveToolBar(item)
+ self.enable_live_tool_bar(item)
else:
- self.enablePreviewToolBar(item)
+ self.enable_preview_tool_bar(item)
- def enableLiveToolBar(self, item):
+ def enable_live_tool_bar(self, item):
"""
Allows the live toolbar to be customised
"""
@@ -663,7 +663,7 @@
# See bug #791050
self.toolbar.show()
- def enablePreviewToolBar(self, item):
+ def enable_preview_tool_bar(self, item):
"""
Allows the Preview toolbar to be customised
"""
@@ -682,15 +682,15 @@
# See bug #791050
self.toolbar.show()
- def refreshServiceItem(self):
+ def refresh_service_item(self):
"""
Method to update the service item if the screen has changed
"""
- log.debug(u'refreshServiceItem live = %s' % self.is_live)
+ log.debug(u'refresh_service_item live = %s' % self.is_live)
if self.service_item.is_text() or self.service_item.is_image():
item = self.service_item
item.render()
- self._processItem(item, self.selected_row)
+ self._process_item(item, self.selected_row)
def add_service_item(self, item):
"""
@@ -703,14 +703,14 @@
if self.song_edit:
slideno = self.selected_row
self.song_edit = False
- self._processItem(item, slideno)
+ self._process_item(item, slideno)
def replaceServiceManagerItem(self, item):
"""
Replacement item following a remote edit
"""
if item == self.service_item:
- self._processItem(item, self.preview_list_widget.currentRow())
+ self._process_item(item, self.preview_list_widget.currentRow())
def addServiceManagerItem(self, item, slideno):
"""
@@ -729,7 +729,7 @@
self.__checkUpdateSelectedSlide(slidenum)
self.slideSelected()
else:
- self._processItem(item, slidenum)
+ self._process_item(item, slidenum)
if self.is_live and item.auto_play_slides_loop and item.timed_slide_interval > 0:
self.play_slides_loop.setChecked(item.auto_play_slides_loop)
self.delay_spin_box.setValue(int(item.timed_slide_interval))
@@ -739,7 +739,7 @@
self.delay_spin_box.setValue(int(item.timed_slide_interval))
self.onPlaySlidesOnce()
- def _processItem(self, service_item, slideno):
+ def _process_item(self, service_item, slideno):
"""
Loads a ServiceItem into the system from ServiceManager
Display the slide number passed
@@ -827,10 +827,9 @@
self.preview_list_widget.setVerticalHeaderLabels(text)
if self.service_item.is_text():
self.preview_list_widget.resizeRowsToContents()
- self.preview_list_widget.setColumnWidth(0,
- self.preview_list_widget.viewport().size().width())
+ self.preview_list_widget.setColumnWidth(0, self.preview_list_widget.viewport().size().width())
self.__updatePreviewSelection(slideno)
- self.enableToolBar(service_item)
+ self.enable_tool_bar(service_item)
# Pass to display for viewing.
# Postpone image build, we need to do this later to avoid the theme
# flashing on the screen
@@ -1050,27 +1049,28 @@
def updatePreview(self):
"""
- This updates the preview frame, for example after changing a slide or
- using *Blank to Theme*.
+ This updates the preview frame, for example after changing a slide or using *Blank to Theme*.
"""
log.debug(u'updatePreview %s ' % self.screens.current[u'primary'])
if not self.screens.current[u'primary'] and self.service_item and \
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
- # Grab now, but try again in a couple of seconds if slide change
- # is slow
- QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
- QtCore.QTimer.singleShot(2.5, self.grabMainDisplay)
+ # Grab now, but try again in a couple of seconds if slide change is slow
+ QtCore.QTimer.singleShot(0.5, self.grab_maindisplay)
+ QtCore.QTimer.singleShot(2.5, self.grab_maindisplay)
else:
- self.slidePreview.setPixmap(self.display.preview())
+ self.slide_image = self.display.preview()
+ self.slide_preview.setPixmap(self.slide_image)
+ self.slide_count += 1
- def grabMainDisplay(self):
+ def grab_maindisplay(self):
"""
Creates an image of the current screen and updates the preview frame.
"""
- winid = QtGui.QApplication.desktop().winId()
+ win_id = QtGui.QApplication.desktop().winId()
rect = self.screens.current[u'size']
- winimg = QtGui.QPixmap.grabWindow(winid, rect.x(), rect.y(), rect.width(), rect.height())
- self.slidePreview.setPixmap(winimg)
+ win_image = QtGui.QPixmap.grabWindow(win_id, rect.x(), rect.y(), rect.width(), rect.height())
+ self.slide_preview.setPixmap(win_image)
+ self.slide_image = win_image
def on_slide_selected_next_action(self, checked):
"""
@@ -1276,7 +1276,7 @@
self.media_controller.video(self.controller_type, item, self.hide_mode())
if not self.is_live:
self.preview_display.show()
- self.slidePreview.hide()
+ self.slide_preview.hide()
def onMediaClose(self):
"""
@@ -1285,7 +1285,7 @@
log.debug(u'SlideController onMediaClose')
self.media_controller.media_reset(self)
self.preview_display.hide()
- self.slidePreview.show()
+ self.slide_preview.show()
def _resetBlank(self):
"""
=== added file 'openlp/plugins/remotes/html/live.css'
--- openlp/plugins/remotes/html/live.css 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.css 2013-06-03 18:51:25 +0000
@@ -0,0 +1,39 @@
+/******************************************************************************
+* OpenLP - Open Source Lyrics Projection *
+* --------------------------------------------------------------------------- *
+* Copyright (c) 2008-2013 Raoul Snyman *
+* Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan *
+* Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, *
+* Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. *
+* Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, *
+* Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
+* Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, *
+* Frode Woldsund, Martin Zibricky *
+* --------------------------------------------------------------------------- *
+* 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;
+}
+
+.size {
+ position: absolute;
+ top: 0px;
+ vertical-align: middle;
+ height: 100%;
+ background-size: cover;
+ background-repeat: no-repeat;
+}
\ No newline at end of file
=== added file 'openlp/plugins/remotes/html/live.html'
--- openlp/plugins/remotes/html/live.html 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.html 2013-06-03 18:51:25 +0000
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<!--
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# 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>${live_title}</title>
+ <link rel="stylesheet" href="/files/live.css" />
+ <link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
+ <script type="text/javascript" src="/files/jquery.js"></script>
+ <script type="text/javascript" src="/files/live.js"></script>
+</head>
+<body>
+<img id="image" class="size"/>
+</body>
+</html>
\ No newline at end of file
=== added file 'openlp/plugins/remotes/html/live.js'
--- openlp/plugins/remotes/html/live.js 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.js 2013-06-03 18:51:25 +0000
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * OpenLP - Open Source Lyrics Projection *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2013 Raoul Snyman *
+ * Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan *
+ * Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, *
+ * Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. *
+ * Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, *
+ * Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
+ * Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, *
+ * Frode Woldsund, Martin Zibricky *
+ * --------------------------------------------------------------------------- *
+ * 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 = {
+ loadSlide: function (event) {
+ $.getJSON(
+ "/live/image",
+ function (data, status) {
+ var img = document.getElementById('image');
+ img.src = data.results.slide_image;
+ img.style.display = 'block';
+ }
+ );
+ },
+ pollServer: function () {
+ $.getJSON(
+ "/live/poll",
+ function (data, status) {
+ if (OpenLP.slideCount != data.results.slide_count) {
+ OpenLP.slideCount = data.results.slide_count;
+ OpenLP.loadSlide();
+ }
+ }
+ );
+ }
+}
+$.ajaxSetup({ cache: false });
+setInterval("OpenLP.pollServer();", 500);
+OpenLP.pollServer();
+
=== modified file 'openlp/plugins/remotes/lib/httpserver.py'
--- openlp/plugins/remotes/lib/httpserver.py 2013-04-23 20:31:19 +0000
+++ openlp/plugins/remotes/lib/httpserver.py 2013-06-03 18:51:25 +0000
@@ -124,7 +124,7 @@
from mako.template import Template
from PyQt4 import QtCore
-from openlp.core.lib import Registry, Settings, PluginStatus, StringContent
+from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte
from openlp.core.utils import AppLocation, translate
from cherrypy._cpcompat import sha, ntob
@@ -136,6 +136,7 @@
"""
Create an encrypted password for the given password.
"""
+ log.debug("make_sha_hash")
return sha(ntob(password)).hexdigest()
@@ -143,6 +144,7 @@
"""
Fetch the password for a provided user.
"""
+ log.debug("Fetch Password")
if username != Settings().value(u'remotes/user id'):
return None
return make_sha_hash(Settings().value(u'remotes/password'))
@@ -175,9 +177,11 @@
self.root = self.Public()
self.root.files = self.Files()
self.root.stage = self.Stage()
+ self.root.live = self.Live()
self.root.router = self.router
self.root.files.router = self.router
self.root.stage.router = self.router
+ self.root.live.router = self.router
cherrypy.tree.mount(self.root, '/', config=self.define_config())
# Turn off the flood of access messages cause by poll
cherrypy.log.access_log.propagate = False
@@ -213,6 +217,9 @@
u'tools.basic_auth.on': False},
u'/stage': {u'tools.staticdir.on': True,
u'tools.staticdir.dir': self.router.html_dir,
+ u'tools.basic_auth.on': False},
+ u'/live': {u'tools.staticdir.on': True,
+ u'tools.staticdir.dir': self.router.html_dir,
u'tools.basic_auth.on': False}}
return directory_config
@@ -239,7 +246,16 @@
class Stage(object):
"""
- Stageview is read only so security is not relevant and would reduce it's usability
+ Stage view is read only so security is not relevant and would reduce it's usability
+ """
+ @cherrypy.expose
+ def default(self, *args, **kwargs):
+ url = urlparse.urlparse(cherrypy.url())
+ return self.router.process_http_request(url.path, *args)
+
+ class Live(object):
+ """
+ Live view is read only so security is not relevant and would reduce it's usability
"""
@cherrypy.expose
def default(self, *args, **kwargs):
@@ -265,9 +281,12 @@
self.routes = [
(u'^/$', self.serve_file),
(u'^/(stage)$', self.serve_file),
+ (u'^/(live)$', self.serve_file),
(r'^/files/(.*)$', self.serve_file),
(r'^/api/poll$', self.poll),
(r'^/stage/poll$', self.poll),
+ (r'^/live/poll$', self.live_poll),
+ (r'^/live/image$', self.live_image),
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
(r'^/stage/controller/(live|preview)/(.*)$', self.controller),
(r'^/api/service/(.*)$', self.service),
@@ -305,6 +324,7 @@
if response:
return response
else:
+ log.debug('Path not found %s', url_path)
return self._http_not_found()
def _get_service_items(self):
@@ -334,6 +354,7 @@
self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Stage View'),
+ 'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Live View'),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
@@ -359,18 +380,19 @@
def serve_file(self, filename=None):
"""
- Send a file to the socket. For now, just a subset of file types
- and must be top level inside the html folder.
+ Send a file to the socket. For now, just a subset of file types and must be top level inside the html folder.
If subfolders requested return 404, easier for security for the present.
- Ultimately for i18n, this could first look for xx/file.html before
- falling back to file.html... where xx is the language, e.g. 'en'
+ Ultimately for i18n, this could first look for xx/file.html before falling back to file.html.
+ where xx is the language, e.g. 'en'
"""
log.debug(u'serve file request %s' % filename)
if not filename:
filename = u'index.html'
elif filename == u'stage':
filename = u'stage.html'
+ elif filename == u'live':
+ filename = u'live.html'
path = os.path.normpath(os.path.join(self.html_dir, filename))
if not path.startswith(self.html_dir):
return self._http_not_found()
@@ -425,6 +447,26 @@
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': result})
+ def live_poll(self):
+ """
+ Poll OpenLP to determine the current slide count.
+ """
+ result = {
+ u'slide_count': self.live_controller.slide_count
+ }
+ cherrypy.response.headers['Content-Type'] = u'application/json'
+ return json.dumps({u'results': result})
+
+ def live_image(self):
+ """
+ Return the latest display image as a byte stream.
+ """
+ result = {
+ u'slide_image': u'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
+ }
+ cherrypy.response.headers['Content-Type'] = u'application/json'
+ return json.dumps({u'results': result})
+
def display(self, action):
"""
Hide or show the display screen.
=== modified file 'openlp/plugins/remotes/lib/remotetab.py'
--- openlp/plugins/remotes/lib/remotetab.py 2013-03-29 20:58:06 +0000
+++ openlp/plugins/remotes/lib/remotetab.py 2013-06-03 18:51:25 +0000
@@ -86,6 +86,12 @@
self.stage_url.setObjectName(u'stage_url')
self.stage_url.setOpenExternalLinks(True)
self.http_setting_layout.addRow(self.stage_url_label, self.stage_url)
+ self.live_url_label = QtGui.QLabel(self.http_settings_group_box)
+ self.live_url_label.setObjectName(u'live_url_label')
+ self.live_url = QtGui.QLabel(self.http_settings_group_box)
+ self.live_url.setObjectName(u'live_url')
+ self.live_url.setOpenExternalLinks(True)
+ self.http_setting_layout.addRow(self.live_url_label, self.live_url)
self.left_layout.addWidget(self.http_settings_group_box)
self.https_settings_group_box = QtGui.QGroupBox(self.left_column)
self.https_settings_group_box.setCheckable(True)
@@ -116,6 +122,12 @@
self.stage_https_url.setObjectName(u'stage_https_url')
self.stage_https_url.setOpenExternalLinks(True)
self.https_settings_layout.addRow(self.stage_https_url_label, self.stage_https_url)
+ self.live_https_url_label = QtGui.QLabel(self.https_settings_group_box)
+ self.live_https_url_label.setObjectName(u'live_url_label')
+ self.live_https_url = QtGui.QLabel(self.https_settings_group_box)
+ self.live_https_url.setObjectName(u'live_https_url')
+ self.live_https_url.setOpenExternalLinks(True)
+ self.https_settings_layout.addRow(self.live_https_url_label, self.live_https_url)
self.left_layout.addWidget(self.https_settings_group_box)
self.user_login_group_box = QtGui.QGroupBox(self.left_column)
self.user_login_group_box.setCheckable(True)
@@ -163,6 +175,7 @@
self.port_label.setText(translate('RemotePlugin.RemoteTab', 'Port number:'))
self.remote_url_label.setText(translate('RemotePlugin.RemoteTab', 'Remote URL:'))
self.stage_url_label.setText(translate('RemotePlugin.RemoteTab', 'Stage view URL:'))
+ self.live_url_label.setText(translate('RemotePlugin.RemoteTab', 'Live view URL:'))
self.twelve_hour_check_box.setText(translate('RemotePlugin.RemoteTab', 'Display stage time in 12h format'))
self.android_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Android App'))
self.qr_description_label.setText(translate('RemotePlugin.RemoteTab',
@@ -176,6 +189,7 @@
self.https_port_label.setText(self.port_label.text())
self.remote_https_url_label.setText(self.remote_url_label.text())
self.stage_https_url_label.setText(self.stage_url_label.text())
+ self.live_https_url_label.setText(self.live_url_label.text())
self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication'))
self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:'))
self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:'))
@@ -203,10 +217,14 @@
https_url = u'https://%s:%s/' % (ip_address, self.https_port_spin_box.value())
self.remote_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url))
self.remote_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url))
- http_url += u'stage'
- https_url += u'stage'
- self.stage_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url))
- self.stage_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url))
+ http_url_temp = http_url + u'stage'
+ https_url_temp = https_url + u'stage'
+ self.stage_url.setText(u'<a href="%s">%s</a>' % (http_url_temp, http_url_temp))
+ self.stage_https_url.setText(u'<a href="%s">%s</a>' % (https_url_temp, https_url_temp))
+ http_url_temp = http_url + u'live'
+ https_url_temp = https_url + u'live'
+ self.live_url.setText(u'<a href="%s">%s</a>' % (http_url_temp, http_url_temp))
+ self.live_https_url.setText(u'<a href="%s">%s</a>' % (https_url_temp, https_url_temp))
def load(self):
"""
Follow ups