mirror of https://gitlab.com/openlp/openlp.git
Display API abstraction
This commit is contained in:
parent
49190fe6b3
commit
a04ed99dfc
|
@ -12,6 +12,7 @@ module.exports = function(config) {
|
|||
"tests/js/polyfill.js",
|
||||
"tests/js/fake_webchannel.js",
|
||||
"openlp/core/display/html/reveal.js",
|
||||
"openlp/core/display/html/display-init.js",
|
||||
"openlp/core/display/html/display.js",
|
||||
"tests/js/test_*.js"
|
||||
],
|
||||
|
|
|
@ -46,8 +46,8 @@ from openlp.core.common.platform import is_macosx, is_win
|
|||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.display.webengine import init_webview_custom_schemes, set_webview_display_path
|
||||
from openlp.core.lib.filelock import FileLock
|
||||
from openlp.core.display.webengine import init_webview_custom_schemes
|
||||
from openlp.core.loader import loader
|
||||
from openlp.core.resources import qInitResources
|
||||
from openlp.core.server import Server
|
||||
|
@ -295,6 +295,8 @@ def parse_options():
|
|||
dir_name=os.path.join('<AppDir>', '..', '..')))
|
||||
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_true',
|
||||
help='Turn off the Web and Socket Server ')
|
||||
parser.add_argument('--display-custom-path', dest='display_custom_path', default=None,
|
||||
help='Specify the custom path for display renderer (HTML). Useful for development.')
|
||||
parser.add_argument('rargs', nargs='*', default=[])
|
||||
# Parse command line options and deal with them.
|
||||
return parser.parse_args()
|
||||
|
@ -485,6 +487,11 @@ def main():
|
|||
Registry().register('settings_thread', settings_thread)
|
||||
Registry().register('application-qt', application)
|
||||
Registry().register('application', app)
|
||||
if args.display_custom_path:
|
||||
if (args.display_custom_path.startswith('http:') or args.display_custom_path.startswith('https:')):
|
||||
Registry().register('display_custom_url', args.display_custom_path)
|
||||
else:
|
||||
set_webview_display_path(args.display_custom_path)
|
||||
Registry().set_flag('no_web_server', args.no_web_server)
|
||||
# Upgrade settings.
|
||||
app.settings = settings
|
||||
|
|
|
@ -114,12 +114,20 @@ class Registry(metaclass=Singleton):
|
|||
|
||||
def has_function(self, event):
|
||||
"""
|
||||
Returns whether there's any hander associated with the event.
|
||||
Returns whether there's any handler associated with the event.
|
||||
|
||||
:param event: The function to be checked
|
||||
"""
|
||||
return event in self.functions_list
|
||||
|
||||
def has(self, service_name: str) -> bool:
|
||||
"""
|
||||
Returns whether there's any service registered with provided name
|
||||
|
||||
:param service_name: The service name to be checked
|
||||
"""
|
||||
return service_name in self.service_list
|
||||
|
||||
def execute(self, event, *args, **kwargs):
|
||||
"""
|
||||
Execute all the handlers associated with the event and return an array of results.
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*jshint esversion: 9 */
|
||||
class CommunicationBridge {
|
||||
constructor() {
|
||||
this.target = null;
|
||||
this.initOptions = null;
|
||||
}
|
||||
|
||||
requestAction(action, ...values) {
|
||||
if (action == 'init') {
|
||||
this.initOptions = (values && values[0]) || null;
|
||||
}
|
||||
|
||||
let returnValue;
|
||||
if (this.target) {
|
||||
returnValue = this.target._handleNativeCall(action, ...values);
|
||||
}
|
||||
|
||||
if (action == 'init') {
|
||||
this._onInitialized();
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
requestActionAsync(action, returnEvent, ...values) {
|
||||
let returnValue;
|
||||
if (this.target) {
|
||||
returnValue = this.target._handleNativeCall(action, ...values);
|
||||
}
|
||||
|
||||
if (returnValue && ('then' in returnValue)) {
|
||||
returnValue.then((value) => {
|
||||
this._dispatchEvent(returnEvent, value || {});
|
||||
});
|
||||
} else {
|
||||
this._dispatchEvent(returnEvent, returnValue || {});
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
setDisplayTarget(newTarget) {
|
||||
this.target = newTarget;
|
||||
if (this.initOptions) {
|
||||
this.target._handleNativeCall('init', ...[this.initOptions]);
|
||||
this._onInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
isReady() {
|
||||
return !!this.target;
|
||||
}
|
||||
|
||||
pleaseRepaint() {
|
||||
if (window.displayWatcher) {
|
||||
return window.displayWatcher.pleaseRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
_onInitialized() {
|
||||
if (window.displayWatcher) {
|
||||
window.displayWatcher.setInitialised(true);
|
||||
}
|
||||
}
|
||||
|
||||
_dispatchEvent(eventName, eventParameter) {
|
||||
if (window.displayWatcher) {
|
||||
window.displayWatcher.dispatchEvent(eventName, eventParameter || {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initNativeHandlerIfAvailable() {
|
||||
if (window.QWebChannel) {
|
||||
// Means we're running inside OpenLP
|
||||
new window.QWebChannel(window.qt.webChannelTransport, (channel) => {
|
||||
window.displayWatcher = channel.objects.displayWatcher;
|
||||
|
||||
// Defining window title as exposed by OpenLP
|
||||
(window.displayWatcher.getWindowTitle || (() => Promise.resolve('')))()
|
||||
.then((windowTitle) => {
|
||||
if (windowTitle) {
|
||||
const titleTag = document.head.getElementsByTagName('title')[0];
|
||||
if (titleTag) {
|
||||
titleTag.innerText = `${titleTag.innerText} (${windowTitle})`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.initCommunicationBridge = () => {
|
||||
initNativeHandlerIfAvailable();
|
||||
var communicationBridge = new CommunicationBridge();
|
||||
window.communicationBridge = communicationBridge;
|
||||
window.requestAction = communicationBridge.requestAction.bind(communicationBridge);
|
||||
window.requestActionAsync = communicationBridge.requestActionAsync.bind(communicationBridge);
|
||||
window.isReady = communicationBridge.isReady.bind(communicationBridge);
|
||||
};
|
|
@ -6,6 +6,7 @@
|
|||
<link type="text/css" rel="stylesheet" href="display.css">
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script type="text/javascript" src="reveal.js"></script>
|
||||
<script type="text/javascript" src="display-init.js"></script>
|
||||
<script type="text/javascript" src="display.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* display.js is the main Javascript file that is used to drive the display.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Background type enumeration
|
||||
*/
|
||||
|
@ -892,122 +893,122 @@ var Display = {
|
|||
/**
|
||||
* Blank the screen
|
||||
*/
|
||||
toBlack: function (onFinishedEventName) {
|
||||
/* Avoid race conditions where display goes to transparent and quickly goes to black */
|
||||
Display._abortLastTransitionOperation();
|
||||
/*
|
||||
Reveal's black overlay should be shown before the transitions are
|
||||
restored, to avoid screen flashes
|
||||
*/
|
||||
Display._restorePauseBehavior();
|
||||
Display._requestAnimationFrameExclusive(function() {
|
||||
if (!Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
if (onFinishedEventName) {
|
||||
displayWatcher.dispatchEvent(onFinishedEventName, {});
|
||||
toBlack: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
/* Avoid race conditions where display goes to transparent and quickly goes to black */
|
||||
Display._abortLastTransitionOperation();
|
||||
/*
|
||||
Reveal's black overlay should be shown before the transitions are
|
||||
restored, to avoid screen flashes
|
||||
*/
|
||||
Display._restorePauseBehavior();
|
||||
Display._requestAnimationFrameExclusive(function() {
|
||||
if (!Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Hide all but theme background
|
||||
*/
|
||||
toTheme: function (onFinishedEventName) {
|
||||
Display._abortLastTransitionOperation();
|
||||
/*
|
||||
Reveal's black overlay should be shown before the transitions are
|
||||
restored, to avoid screen flashes
|
||||
*/
|
||||
Display._restorePauseBehavior();
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
if (onFinishedEventName) {
|
||||
displayWatcher.dispatchEvent(onFinishedEventName, {});
|
||||
toTheme: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
Display._abortLastTransitionOperation();
|
||||
/*
|
||||
Reveal's black overlay should be shown before the transitions are
|
||||
restored, to avoid screen flashes
|
||||
*/
|
||||
Display._restorePauseBehavior();
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 1;
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Hide everything (CAUTION: Causes a invisible mouse barrier)
|
||||
*/
|
||||
toTransparent: function (onFinishedEventName) {
|
||||
Display._abortLastTransitionOperation();
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 0;
|
||||
if (!Reveal.isPaused()) {
|
||||
/*
|
||||
Removing previously the overlay if it's not paused, to avoid a
|
||||
content flash while going from black screen to transparent
|
||||
*/
|
||||
document.body.classList.add('is-desktop');
|
||||
Reveal.togglePause();
|
||||
}
|
||||
/*
|
||||
Waiting for body transition to happen, now it would be safe to
|
||||
hide the Webview (as other transitions were suppressed)
|
||||
*/
|
||||
Display._abortLastTransitionOperation();
|
||||
Display._addTransitionEndEventToBody(transitionEndEvent);
|
||||
function transitionEndEvent(e) {
|
||||
// Targeting only body
|
||||
if (e.target != documentBody) {
|
||||
return;
|
||||
toTransparent: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
Display._abortLastTransitionOperation();
|
||||
var documentBody = $("body")[0];
|
||||
documentBody.style.opacity = 0;
|
||||
if (!Reveal.isPaused()) {
|
||||
/*
|
||||
Removing previously the overlay if it's not paused, to avoid a
|
||||
content flash while going from black screen to transparent
|
||||
*/
|
||||
document.body.classList.add('is-desktop');
|
||||
Reveal.togglePause();
|
||||
}
|
||||
/*
|
||||
Disabling all transitions (except body) to allow the Webview to attain the
|
||||
transparent state before it gets hidden by Qt.
|
||||
Waiting for body transition to happen, now it would be safe to
|
||||
hide the Webview (as other transitions were suppressed)
|
||||
*/
|
||||
document.body.classList.add('disable-transitions');
|
||||
document.body.classList.add('is-desktop');
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
/*
|
||||
Repainting before hiding the Webview to avoid flashes when
|
||||
showing it again.
|
||||
*/
|
||||
displayWatcher.pleaseRepaint();
|
||||
/* Waiting for repaint to happen before saying that it's done. */
|
||||
Display._requestAnimationFrameExclusive(function() {
|
||||
/* We're transparent now, aborting any transition event between */
|
||||
Display._abortLastTransitionOperation();
|
||||
if (onFinishedEventName) {
|
||||
displayWatcher.dispatchEvent(onFinishedEventName, {});
|
||||
Display._abortLastTransitionOperation();
|
||||
Display._addTransitionEndEventToBody(transitionEndEvent);
|
||||
function transitionEndEvent(e) {
|
||||
// Targeting only body
|
||||
if (e.target != documentBody) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
Disabling all transitions (except body) to allow the Webview to attain the
|
||||
transparent state before it gets hidden by Qt.
|
||||
*/
|
||||
document.body.classList.add('disable-transitions');
|
||||
document.body.classList.add('is-desktop');
|
||||
Display._slidesContainer.style.opacity = 0;
|
||||
Display._footerContainer.style.opacity = 0;
|
||||
/*
|
||||
Repainting before hiding the Webview to avoid flashes when
|
||||
showing it again.
|
||||
*/
|
||||
displayWatcher.pleaseRepaint();
|
||||
/* Waiting for repaint to happen before saying that it's done. */
|
||||
Display._requestAnimationFrameExclusive(function() {
|
||||
/* We're transparent now, aborting any transition event between */
|
||||
Display._abortLastTransitionOperation();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Show the screen
|
||||
*/
|
||||
show: function (onFinishedEventName) {
|
||||
var documentBody = $("body")[0];
|
||||
/*
|
||||
Removing transitionend event, avoids the content being hidden if the user
|
||||
tries to show content again before toTransparent() transitionend event
|
||||
happens
|
||||
*/
|
||||
Display._abortLastTransitionOperation();
|
||||
show: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
var documentBody = $("body")[0];
|
||||
/*
|
||||
Removing transitionend event, avoids the content being hidden if the user
|
||||
tries to show content again before toTransparent() transitionend event
|
||||
happens
|
||||
*/
|
||||
Display._abortLastTransitionOperation();
|
||||
|
||||
Display._slidesContainer.style.opacity = 1;
|
||||
Display._footerContainer.style.opacity = 1;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._restorePauseBehavior();
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
documentBody.style.opacity = 1;
|
||||
if (onFinishedEventName) {
|
||||
displayWatcher.dispatchEvent(onFinishedEventName, {});
|
||||
Display._slidesContainer.style.opacity = 1;
|
||||
Display._footerContainer.style.opacity = 1;
|
||||
if (Reveal.isPaused()) {
|
||||
Reveal.togglePause();
|
||||
}
|
||||
Display._restorePauseBehavior();
|
||||
Display._reenableGlobalTransitions(function() {
|
||||
documentBody.style.opacity = 1;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1413,6 +1414,12 @@ var Display = {
|
|||
return url;
|
||||
},
|
||||
};
|
||||
new QWebChannel(qt.webChannelTransport, function (channel) {
|
||||
window.displayWatcher = channel.objects.displayWatcher;
|
||||
});
|
||||
|
||||
Display._handleNativeCall = (action, ...values) => {
|
||||
if (Display[action]) {
|
||||
return Display[action](...values);
|
||||
}
|
||||
};
|
||||
|
||||
initCommunicationBridge();
|
||||
communicationBridge.setDisplayTarget(Display);
|
||||
|
|
|
@ -557,13 +557,13 @@ class ThemePreviewRenderer(DisplayWindow, LogMixin):
|
|||
"""
|
||||
Calculate the number of lines that fits on one slide
|
||||
"""
|
||||
return self.run_javascript('Display.calculateLineCount();', is_sync=True)
|
||||
return self.run_in_display('calculateLineCount', is_sync=True)
|
||||
|
||||
def clear_slides(self):
|
||||
"""
|
||||
Clear slides
|
||||
"""
|
||||
return self.run_javascript('Display.clearSlides();')
|
||||
return self.run_in_display('clearSlides')
|
||||
|
||||
def generate_footer(self):
|
||||
"""
|
||||
|
@ -859,10 +859,9 @@ class ThemePreviewRenderer(DisplayWindow, LogMixin):
|
|||
return True
|
||||
self.clear_slides()
|
||||
self.log_debug('_text_fits_on_slide: 1\n{text}'.format(text=text))
|
||||
self.run_javascript('Display.setTextSlide("{text}");'
|
||||
.format(text=text.replace('"', '\\"')), is_sync=True)
|
||||
self.run_in_display('setTextSlide', text.replace('"', '\\"'), is_sync=True)
|
||||
self.log_debug('_text_fits_on_slide: 2')
|
||||
does_text_fit = self.run_javascript('Display.doesContentFit();', is_sync=True)
|
||||
does_text_fit = self.run_in_display('doesContentFit', is_sync=True)
|
||||
return does_text_fit
|
||||
|
||||
def save_screenshot(self, fname=None):
|
||||
|
|
|
@ -212,7 +212,7 @@ class WebViewCustomScheme(QtCore.QObject):
|
|||
| QtWebEngineCore.QWebEngineUrlScheme.Flag.LocalScheme
|
||||
| QtWebEngineCore.QWebEngineUrlScheme.Flag.LocalAccessAllowed)
|
||||
|
||||
def create_scheme_handler(self):
|
||||
def create_scheme_handler(self) -> QtWebEngineCore.QWebEngineUrlSchemeHandler:
|
||||
raise Exception('Needs to be implemented.')
|
||||
|
||||
def init_handler(self, profile=None):
|
||||
|
|
|
@ -51,12 +51,17 @@ class DisplayWatcher(QtCore.QObject):
|
|||
"""
|
||||
initialised = QtCore.pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent):
|
||||
def __init__(self, parent, window_title=None):
|
||||
super().__init__()
|
||||
self._display_window = parent
|
||||
self._transient_dispatch_events = {}
|
||||
self._permanent_dispatch_events = {}
|
||||
self._event_counter = 0
|
||||
self._window_title = window_title
|
||||
|
||||
@QtCore.pyqtSlot(result=str)
|
||||
def getWindowTitle(self):
|
||||
return self._window_title
|
||||
|
||||
@QtCore.pyqtSlot(bool)
|
||||
def setInitialised(self, is_initialised):
|
||||
|
@ -130,7 +135,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
This is a window to show the output
|
||||
"""
|
||||
def __init__(self, parent=None, screen=None, can_show_startup_screen=True, start_hidden=False,
|
||||
after_loaded_callback=None):
|
||||
after_loaded_callback=None, window_title=None):
|
||||
"""
|
||||
Create the display window
|
||||
"""
|
||||
|
@ -149,6 +154,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
self._is_manual_close = False
|
||||
self._can_show_startup_screen = can_show_startup_screen
|
||||
self._fbo = None
|
||||
self.window_title = window_title
|
||||
self.setWindowTitle(translate('OpenLP.DisplayWindow', 'Display Window'))
|
||||
self.setWindowFlags(flags)
|
||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
@ -162,15 +168,24 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
self.webview.display_clicked = self.disable_display
|
||||
self.layout.addWidget(self.webview)
|
||||
self.webview.loadFinished.connect(self.after_loaded)
|
||||
self.display_path = 'openlp://display/display.html'
|
||||
self.checkerboard_path = 'openlp://display/checkerboard.png'
|
||||
self.openlp_splash_screen_path = 'openlp://display/openlp-splash-screen.png'
|
||||
self.channel = QtWebChannel.QWebChannel(self)
|
||||
self.display_watcher = DisplayWatcher(self)
|
||||
if not window_title and screen and screen.is_display:
|
||||
window_title = 'Display Window'
|
||||
self.display_watcher = DisplayWatcher(self, window_title)
|
||||
self.channel.registerObject('displayWatcher', self.display_watcher)
|
||||
self.webview.page().setWebChannel(self.channel)
|
||||
self.display_watcher.initialised.connect(self.on_initialised)
|
||||
qUrl = QtCore.QUrl(self.display_path)
|
||||
self.openlp_splash_screen_path = 'openlp://display/openlp-splash-screen.png'
|
||||
# Using custom display if provided
|
||||
if Registry().has('display_custom_url') and Registry().get('display_custom_url') is not None:
|
||||
display_custom_url = Registry().get('display_custom_url')
|
||||
self.display_path = display_custom_url + '/display.html'
|
||||
self.checkerboard_path = display_custom_url + '/checkerboard.png'
|
||||
qUrl = QtCore.QUrl(display_custom_url)
|
||||
else:
|
||||
self.display_path = 'openlp://display/display.html'
|
||||
self.checkerboard_path = 'openlp://display/checkerboard.png'
|
||||
qUrl = QtCore.QUrl(self.display_path)
|
||||
self.set_url(qUrl)
|
||||
self.is_display = False
|
||||
self.scale = 1
|
||||
|
@ -248,7 +263,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
|
||||
def set_background_image(self, image_path):
|
||||
image_uri = image_path.as_uri()
|
||||
self.run_javascript('Display.setBackgroundImage("{image}");'.format(image=image_uri))
|
||||
self.run_in_display('setBackgroundImage', image_uri)
|
||||
|
||||
def set_single_image(self, bg_color, image_path):
|
||||
"""
|
||||
|
@ -256,12 +271,10 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
:param Path image_path: Path to the image
|
||||
"""
|
||||
image_uri = image_path.as_uri()
|
||||
self.run_javascript('Display.setFullscreenImage("{bg_color}", "{image}");'.format(bg_color=bg_color,
|
||||
image=image_uri))
|
||||
self.run_in_display('setFullscreenImage', bg_color, image_uri)
|
||||
|
||||
def set_single_image_data(self, bg_color, image_data):
|
||||
self.run_javascript('Display.setFullscreenImageFromData("{bg_color}", '
|
||||
'"{image_data}");'.format(bg_color=bg_color, image_data=image_data))
|
||||
self.run_in_display('setFullscreenImageFromData', bg_color, image_data)
|
||||
|
||||
def set_startup_screen(self):
|
||||
bg_color = self.settings.value('core/logo background color')
|
||||
|
@ -276,8 +289,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
# if set to hide logo on startup, do not send the logo
|
||||
if self.settings.value('core/logo hide on startup'):
|
||||
image_uri = ''
|
||||
self.run_javascript('Display.setStartupSplashScreen("{bg_color}", "{image}");'.format(bg_color=bg_color,
|
||||
image=image_uri))
|
||||
self.run_in_display('setStartupSplashScreen', bg_color, image_uri)
|
||||
|
||||
def set_url(self, url):
|
||||
"""
|
||||
|
@ -299,18 +311,16 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
"""
|
||||
Add stuff after page initialisation
|
||||
"""
|
||||
js_is_display = str(self.is_display).lower()
|
||||
item_transitions = str(self.settings.value('themes/item transitions')).lower()
|
||||
hide_mouse = str(self.settings.value('advanced/hide mouse') and self.is_display).lower()
|
||||
slide_numbers_in_footer = str(self.settings.value('advanced/slide numbers in footer')).lower()
|
||||
self.run_javascript('Display.init({{'
|
||||
'isDisplay: {is_display},'
|
||||
'doItemTransitions: {do_item_transitions},'
|
||||
'slideNumbersInFooter: {slide_numbers_in_footer},'
|
||||
'hideMouse: {hide_mouse}'
|
||||
'}});'
|
||||
.format(is_display=js_is_display, do_item_transitions=item_transitions,
|
||||
slide_numbers_in_footer=slide_numbers_in_footer, hide_mouse=hide_mouse))
|
||||
item_transitions = self.settings.value('themes/item transitions')
|
||||
hide_mouse = (self.settings.value('advanced/hide mouse') and self.is_display)
|
||||
slide_numbers_in_footer = self.settings.value('advanced/slide numbers in footer')
|
||||
self.run_in_display('init', {
|
||||
'isDisplay': self.is_display,
|
||||
'doItemTransitions': item_transitions,
|
||||
'slideNumbersInFooter': slide_numbers_in_footer,
|
||||
'hideMouse': hide_mouse,
|
||||
'displayTitle': self.window_title
|
||||
})
|
||||
wait_for(lambda: self._is_initialised)
|
||||
if self.scale != 1:
|
||||
self.set_scale(self.scale)
|
||||
|
@ -319,7 +329,33 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
if self.after_loaded_callback:
|
||||
self.after_loaded_callback()
|
||||
|
||||
def run_javascript(self, script, is_sync=False):
|
||||
def run_in_display(self, action, *parameters, raw_parameters=None, is_sync=False, return_event_name=None):
|
||||
if len(parameters):
|
||||
raw_parameters = ''
|
||||
first = True
|
||||
for parameter in parameters:
|
||||
if not first:
|
||||
raw_parameters += ', '
|
||||
else:
|
||||
first = False
|
||||
raw_parameters += json.dumps(parameter)
|
||||
action_name = 'requestAction'
|
||||
action_async = ''
|
||||
if return_event_name:
|
||||
action_name = 'requestActionAsync'
|
||||
action_async = ', \'{event_name}\''.format(event_name=return_event_name)
|
||||
if not raw_parameters:
|
||||
return self._run_javascript('{action_name}(\'{action}\'{action_async})'.format(action_name=action_name,
|
||||
action=action,
|
||||
action_async=action_async),
|
||||
is_sync)
|
||||
else:
|
||||
return self._run_javascript('{action_name}(\'{action}\'{action_async}, {raw_parameters})'
|
||||
.format(action_name=action_name, action=action, action_async=action_async,
|
||||
raw_parameters=raw_parameters),
|
||||
is_sync)
|
||||
|
||||
def _run_javascript(self, script, is_sync=False):
|
||||
"""
|
||||
Run some Javascript in the WebView
|
||||
|
||||
|
@ -355,14 +391,13 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
|
||||
:param str verse: The verse to go to, e.g. "V1" for songs, or just "0" for other types
|
||||
"""
|
||||
self.run_javascript('Display.goToSlide("{verse}");'.format(verse=verse))
|
||||
self.run_in_display('goToSlide', verse)
|
||||
|
||||
def load_verses(self, verses, is_sync=False):
|
||||
"""
|
||||
Set verses in the display
|
||||
"""
|
||||
json_verses = json.dumps(verses)
|
||||
self.run_javascript('Display.setTextSlides({verses});'.format(verses=json_verses), is_sync=is_sync)
|
||||
self.run_in_display('setTextSlides', verses, is_sync=is_sync)
|
||||
|
||||
def load_images(self, images):
|
||||
"""
|
||||
|
@ -377,65 +412,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
image['thumbnail'] = image['thumbnail'].as_uri()
|
||||
else:
|
||||
image['thumbnail'] = image['path']
|
||||
json_images = json.dumps(imagesr)
|
||||
self.run_javascript('Display.setImageSlides({images});'.format(images=json_images))
|
||||
|
||||
def load_video(self, video):
|
||||
"""
|
||||
Load video in the display
|
||||
"""
|
||||
video = copy.deepcopy(video)
|
||||
video['path'] = video['path'].as_uri()
|
||||
json_video = json.dumps(video)
|
||||
self.run_javascript('Display.setVideo({video});'.format(video=json_video))
|
||||
|
||||
def play_video(self):
|
||||
"""
|
||||
Play the currently loaded video
|
||||
"""
|
||||
self.run_javascript('Display.playVideo();')
|
||||
|
||||
def pause_video(self):
|
||||
"""
|
||||
Pause the currently playing video
|
||||
"""
|
||||
self.run_javascript('Display.pauseVideo();')
|
||||
|
||||
def stop_video(self):
|
||||
"""
|
||||
Stop the currently playing video
|
||||
"""
|
||||
self.run_javascript('Display.stopVideo();')
|
||||
|
||||
def set_video_playback_rate(self, rate):
|
||||
"""
|
||||
Set the playback rate of the current video.
|
||||
|
||||
The rate can be any valid float, with 0.0 being stopped, 1.0 being normal speed,
|
||||
over 1.0 is faster, under 1.0 is slower, and negative is backwards.
|
||||
|
||||
:param rate: A float indicating the playback rate.
|
||||
"""
|
||||
self.run_javascript('Display.setPlaybackRate({rate});'.format(rate=rate))
|
||||
|
||||
def set_video_volume(self, level):
|
||||
"""
|
||||
Set the volume of the current video.
|
||||
|
||||
The volume should be an int from 0 to 100, where 0 is no sound and 100 is maximum volume. Any
|
||||
values outside this range will raise a ``ValueError``.
|
||||
|
||||
:param level: A number between 0 and 100
|
||||
"""
|
||||
if level < 0 or level > 100:
|
||||
raise ValueError('Volume should be from 0 to 100, was "{}"'.format(level))
|
||||
self.run_javascript('Display.setVideoVolume({level});'.format(level=level))
|
||||
|
||||
def toggle_video_mute(self):
|
||||
"""
|
||||
Toggle the mute of the current video
|
||||
"""
|
||||
self.run_javascript('Display.toggleVideoMute();')
|
||||
self.run_in_display('setImageSlides', imagesr)
|
||||
|
||||
def save_screenshot(self, fname=None):
|
||||
"""
|
||||
|
@ -477,7 +454,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
theme_copy.font_main_name = self._fix_font_name(theme.font_main_name)
|
||||
theme_copy.font_footer_name = self._fix_font_name(theme.font_footer_name)
|
||||
exported_theme = theme_copy.export_theme(is_js=True)
|
||||
self.run_javascript('Display.setTheme({theme});'.format(theme=exported_theme), is_sync=is_sync)
|
||||
self.run_in_display('setTheme', raw_parameters=exported_theme, is_sync=is_sync)
|
||||
|
||||
def reload_theme(self):
|
||||
"""
|
||||
|
@ -485,13 +462,13 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
DO NOT use this when changing slides. Only use this if you need to force an update
|
||||
to the current visible slides.
|
||||
"""
|
||||
self.run_javascript('Display.resetTheme();')
|
||||
self.run_in_display('resetTheme')
|
||||
|
||||
def get_video_types(self):
|
||||
"""
|
||||
Get the types of videos playable by the embedded media player
|
||||
"""
|
||||
return self.run_javascript('Display.getVideoTypes();', is_sync=True)
|
||||
return self.run_in_display('getVideoTypes', is_sync=True)
|
||||
|
||||
def show_display(self):
|
||||
"""
|
||||
|
@ -505,7 +482,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
self.display_watcher.unregister_event_listener(TRANSITION_END_EVENT_NAME)
|
||||
if self.isHidden():
|
||||
self.setVisible(True)
|
||||
self.run_javascript('Display.show();')
|
||||
self.run_in_display('show')
|
||||
self.hide_mode = None
|
||||
|
||||
def hide_display(self, mode=HideMode.Screen):
|
||||
|
@ -530,13 +507,13 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
# Hide window only after all webview CSS ransitions are done
|
||||
self.display_watcher.register_event_listener(TRANSITION_END_EVENT_NAME,
|
||||
lambda _: self.setVisible(False))
|
||||
self.run_javascript("Display.toTransparent('{}');".format(TRANSITION_END_EVENT_NAME))
|
||||
self.run_in_display('toTransparent', return_event_name=TRANSITION_END_EVENT_NAME)
|
||||
else:
|
||||
self.run_javascript('Display.toTransparent();')
|
||||
self.run_in_display('toTransparent')
|
||||
elif mode == HideMode.Blank:
|
||||
self.run_javascript('Display.toBlack();')
|
||||
self.run_in_display('toBlack')
|
||||
elif mode == HideMode.Theme:
|
||||
self.run_javascript('Display.toTheme();')
|
||||
self.run_in_display('toTheme')
|
||||
self.hide_mode = mode
|
||||
|
||||
def disable_display(self):
|
||||
|
@ -554,7 +531,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
This function ensures that the current item won't flash momentarily when the webengineview
|
||||
is displayed for a subsequent song or image.
|
||||
"""
|
||||
self.run_javascript('Display.finishWithCurrentItem();', True)
|
||||
self.run_in_display('finishWithCurrentItem', is_sync=True)
|
||||
self.webview.update()
|
||||
|
||||
def set_scale(self, scale):
|
||||
|
@ -564,7 +541,7 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
|
|||
self.scale = scale
|
||||
# Only scale if initialised (scale run again once initialised)
|
||||
if self._is_initialised:
|
||||
self.run_javascript('Display.setScale({scale});'.format(scale=scale * 100))
|
||||
self.run_in_display('setScale', scale * 100)
|
||||
|
||||
def alert(self, text, settings):
|
||||
"""
|
||||
|
|
|
@ -39,7 +39,7 @@ def loader():
|
|||
MediaController()
|
||||
PluginManager()
|
||||
# Set up the path with plugins
|
||||
Renderer()
|
||||
Renderer(window_title='Renderer')
|
||||
# Create slide controllers
|
||||
PreviewController()
|
||||
LiveController()
|
||||
|
|
|
@ -147,7 +147,8 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
|||
if screen.is_display:
|
||||
will_start_hidden = self._current_hide_mode == HideMode.Screen
|
||||
display = DisplayWindow(self, screen, start_hidden=will_start_hidden,
|
||||
after_loaded_callback=self._display_after_loaded_callback)
|
||||
after_loaded_callback=self._display_after_loaded_callback,
|
||||
window_title='Live Screen' if self.is_live else 'Preview Screen')
|
||||
self.displays.append(display)
|
||||
self._reset_blank(False)
|
||||
if self.display:
|
||||
|
@ -398,7 +399,7 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
|||
self.slide_layout.setSpacing(0)
|
||||
self.slide_layout.setObjectName('SlideLayout')
|
||||
# Set up the preview display
|
||||
self.preview_display = DisplayWindow(self)
|
||||
self.preview_display = DisplayWindow(self, window_title='Live' if self.is_live else 'Preview')
|
||||
self.slide_layout.addWidget(self.preview_display)
|
||||
self.slide_layout.resize.connect(self.on_preview_resize)
|
||||
# Actual preview screen
|
||||
|
|
|
@ -48,7 +48,8 @@ class UiThemeProgressDialog(object):
|
|||
self.theme_preview_layout.margin = 8
|
||||
self.theme_preview_layout.setSpacing(0)
|
||||
self.theme_preview_layout.setObjectName('preview_web_layout')
|
||||
self.theme_display = ThemePreviewRenderer(theme_progress_dialog, can_show_startup_screen=False)
|
||||
self.theme_display = ThemePreviewRenderer(theme_progress_dialog, can_show_startup_screen=False,
|
||||
window_title='Theme Progress Dialog')
|
||||
self.theme_display.setObjectName('theme_display')
|
||||
self.theme_preview_layout.addWidget(self.theme_display)
|
||||
self.theme_progress_layout.addWidget(self.preview_area)
|
||||
|
|
|
@ -100,7 +100,7 @@ class Ui_ThemeWizard(object):
|
|||
self.preview_area_layout.margin = 8
|
||||
self.preview_area_layout.setSpacing(0)
|
||||
self.preview_area_layout.setObjectName('preview_web_layout')
|
||||
self.preview_box = ThemePreviewRenderer(self)
|
||||
self.preview_box = ThemePreviewRenderer(self, window_title="Theme Editor Preview")
|
||||
self.preview_box.setObjectName('preview_box')
|
||||
self.preview_area_layout.addWidget(self.preview_box)
|
||||
self.preview_layout.addWidget(self.preview_area)
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of the plugin which manages storing and
|
||||
displaying of alerts.
|
||||
"""
|
||||
import json
|
||||
|
||||
from PyQt5 import QtCore, QtGui
|
||||
|
||||
|
@ -77,7 +76,7 @@ class AlertsManager(QtCore.QObject, RegistryBase, LogMixin, RegistryProperties):
|
|||
'repeat': self.settings.value('alerts/repeat'),
|
||||
'scroll': self.settings.value('alerts/scroll')
|
||||
}
|
||||
self.live_controller.display.alert(text, json.dumps(alert_settings))
|
||||
self.live_controller.display.alert(text, alert_settings)
|
||||
|
||||
def _hex_to_rgb(self, rgb_values):
|
||||
"""
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "karma start --single-run",
|
||||
"lint": "jshint openlp/core/display/html/display.js"
|
||||
"lint": "jshint openlp/core/display/html/display*.js"
|
||||
},
|
||||
"jshintConfig": {
|
||||
"esversion": 6
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
function _createDiv(attrs) {
|
||||
function _createDiv(attrs, inElement) {
|
||||
var div = document.createElement("div");
|
||||
for (key in attrs) {
|
||||
div.setAttribute(key, attrs[key]);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
if (inElement) {
|
||||
inElement.appendChild(div);
|
||||
} else {
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
|
@ -321,92 +325,6 @@ describe("Transitions", function () {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
describe("Screen Visibility", function () {
|
||||
var TRANSITION_TIMEOUT = 2000;
|
||||
|
||||
beforeEach(function() {
|
||||
window.displayWatcher = jasmine.createSpyObj('DisplayWatcher', ['dispatchEvent', 'setInitialised', 'pleaseRepaint']);
|
||||
document.body.innerHTML = "";
|
||||
var revealDiv = _createDiv({"class": "reveal"});
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
var footerDiv = _createDiv({"class": "footer"});
|
||||
slidesDiv.innerHTML = "<section><section><p></p></section></section>";
|
||||
revealDiv.append(slidesDiv);
|
||||
revealDiv.append(footerDiv);
|
||||
document.body.style.transition = "opacity 75ms ease-in-out";
|
||||
Display.init({isDisplay: true, doItemTransition: false});
|
||||
});
|
||||
afterEach(function() {
|
||||
// Reset theme
|
||||
Display._theme = null;
|
||||
});
|
||||
|
||||
it("should trigger dispatchEvent when toTransparent(eventName) is called with an event parameter", function (done) {
|
||||
var testEventName = 'event_32';
|
||||
displayWatcher.dispatchEvent = function(eventName) {
|
||||
if (eventName == testEventName) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
Display.toTransparent(testEventName);
|
||||
|
||||
setTimeout(function() {
|
||||
fail('dispatchEvent not called');
|
||||
done();
|
||||
}, TRANSITION_TIMEOUT);
|
||||
});
|
||||
|
||||
it("should trigger dispatchEvent when toBlack(eventName) is called with an event parameter", function (done) {
|
||||
var testEventName = 'event_33';
|
||||
displayWatcher.dispatchEvent = function(eventName) {
|
||||
if (eventName == testEventName) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
Display.toBlack(testEventName);
|
||||
|
||||
setTimeout(function() {
|
||||
fail('dispatchEvent not called');
|
||||
done();
|
||||
}, TRANSITION_TIMEOUT);
|
||||
});
|
||||
|
||||
it("should trigger dispatchEvent when toTheme(eventName) is called with an event parameter", function (done) {
|
||||
var testEventName = 'event_34';
|
||||
displayWatcher.dispatchEvent = function(eventName) {
|
||||
if (eventName == testEventName) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
Display.toTheme(testEventName);
|
||||
|
||||
setTimeout(function() {
|
||||
fail('dispatchEvent not called');
|
||||
done();
|
||||
}, TRANSITION_TIMEOUT);
|
||||
});
|
||||
|
||||
it("should trigger dispatchEvent when show(eventName) is called with an event parameter", function (done) {
|
||||
var testEventName = 'event_35';
|
||||
displayWatcher.dispatchEvent = function(eventName) {
|
||||
if (eventName == testEventName) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
Display.show(testEventName);
|
||||
|
||||
setTimeout(function() {
|
||||
fail('dispatchEvent not called');
|
||||
done();
|
||||
}, TRANSITION_TIMEOUT);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Display.alert", function () {
|
||||
var alertContainer, alertBackground, alertText, settings, text;
|
||||
|
||||
|
@ -785,8 +703,9 @@ describe("Display.setTextSlides", function () {
|
|||
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
var slides_container = _createDiv({"class": "slides"});
|
||||
var footer_container = _createDiv({"class": "footer"});
|
||||
var revealContainer = Display._revealContainer = _createDiv({"class": "reveal"})
|
||||
var slides_container = _createDiv({"class": "slides"}, revealContainer);
|
||||
var footer_container = _createDiv({"class": "footer"}, revealContainer);
|
||||
Display._slidesContainer = slides_container;
|
||||
Display._footerContainer = footer_container;
|
||||
Display._slides = {};
|
||||
|
@ -1203,15 +1122,14 @@ describe("Reveal slidechanged event", function () {
|
|||
}
|
||||
];
|
||||
|
||||
var slidesDiv = _createDiv({"class": "slides"});
|
||||
document.body.innerHTML = '';
|
||||
var revealContainer = Display._revealContainer = _createDiv({"class": "reveal"});
|
||||
|
||||
var slidesDiv = _createDiv({"class": "slides"}, revealContainer);
|
||||
slidesDiv.innerHTML = "<section><p></p></section>";
|
||||
Display._slidesContainer = slidesDiv;
|
||||
var footerDiv = _createDiv({"class": "footer"});
|
||||
var footerDiv = _createDiv({"class": "footer"}, revealContainer);
|
||||
Display._footerContainer = footerDiv;
|
||||
var revealDiv = _createDiv({"class": "reveal"});
|
||||
revealDiv.append(slidesDiv);
|
||||
revealDiv.append(footerDiv);
|
||||
document.body.appendChild(revealDiv);
|
||||
|
||||
Display.init({isDisplay: false, doItemTransitions: false});
|
||||
var oldDisplaySlideChanged = Display._onSlideChanged;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
"use strict";
|
||||
|
||||
describe("The CommunicationBridge object", () => {
|
||||
/** @type {CommunicationBridge} */
|
||||
let testCommunicationBridge;
|
||||
let SimpleTarget;
|
||||
|
||||
beforeEach(() => {
|
||||
testCommunicationBridge = new CommunicationBridge();
|
||||
SimpleTarget = class {
|
||||
_handleNativeCall(action, ...values) {}
|
||||
}
|
||||
});
|
||||
|
||||
it("should exist", () => {
|
||||
expect(CommunicationBridge).toBeDefined()
|
||||
});
|
||||
it("should not be ready after instantiated", () => {
|
||||
expect(testCommunicationBridge.isReady()).toBe(false);
|
||||
});
|
||||
it("should register target", () => {
|
||||
testCommunicationBridge.setDisplayTarget(new SimpleTarget());
|
||||
expect(testCommunicationBridge.isReady()).toBe(true);
|
||||
|
||||
});
|
||||
it("should be able to requestAction", (done) => {
|
||||
const target = new SimpleTarget()
|
||||
target._handleNativeCall = (action, ...values) => done();
|
||||
testCommunicationBridge.setDisplayTarget(target);
|
||||
testCommunicationBridge.requestAction('dummy');
|
||||
});
|
||||
it("should be able to replay init action before setDisplayTarget", (done) => {
|
||||
const target = new SimpleTarget()
|
||||
target._handleNativeCall = (action, ...values) => {
|
||||
if (action == 'init') {
|
||||
expect(values[0]).toBe('replayed init');
|
||||
done();
|
||||
}
|
||||
}
|
||||
testCommunicationBridge.requestAction('init', 'replayed init');
|
||||
testCommunicationBridge.setDisplayTarget(target);
|
||||
});
|
||||
it("should dispatch initialized event", (done) => {
|
||||
displayWatcher.setInitialised = () => done();
|
||||
testCommunicationBridge.setDisplayTarget(new SimpleTarget());
|
||||
testCommunicationBridge.requestAction('init', {do_init: true});
|
||||
});
|
||||
it("should dispatch event on async call and promise-based handlers", (done) => {
|
||||
const target = new SimpleTarget()
|
||||
target._handleNativeCall = (action, ...values) => {
|
||||
if (action == 'async') {
|
||||
return new Promise((resolve) => resolve({value: 'async value'}));
|
||||
}
|
||||
}
|
||||
testCommunicationBridge.setDisplayTarget(target);
|
||||
displayWatcher.dispatchEvent = (event, parameter) => {
|
||||
expect(event).toBe('async_callback');
|
||||
expect(parameter).toEqual({value: 'async value'});
|
||||
done();
|
||||
}
|
||||
|
||||
// THEN: async callback should return value over displayWatch.dispatchEvent()
|
||||
testCommunicationBridge.requestActionAsync('async', 'async_callback');
|
||||
});
|
||||
it("should dispatch event on async call and normal handlers", (done) => {
|
||||
const target = new SimpleTarget()
|
||||
target._handleNativeCall = (action, ...values) => {
|
||||
if (action == 'sync') {
|
||||
return {value: 'sync value'};
|
||||
}
|
||||
}
|
||||
testCommunicationBridge.setDisplayTarget(target);
|
||||
displayWatcher.dispatchEvent = (event, parameter) => {
|
||||
expect(event).toBe('sync_callback');
|
||||
expect(parameter).toEqual({value: 'sync value'});
|
||||
done();
|
||||
}
|
||||
|
||||
// THEN: async callback should return value over displayWatch.dispatchEvent()
|
||||
testCommunicationBridge.requestActionAsync('sync', 'sync_callback');
|
||||
});
|
||||
});
|
|
@ -173,13 +173,13 @@ def test_set_scale_not_initialised(display_window_env, mock_settings):
|
|||
# GIVEN: A display window not yet initialised
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = False
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
|
||||
# WHEN: set scale is run
|
||||
display_window.set_scale(0.5)
|
||||
|
||||
# THEN: javascript should not be run
|
||||
display_window.run_javascript.assert_not_called()
|
||||
display_window.run_in_display.assert_not_called()
|
||||
|
||||
|
||||
def test_set_scale_initialised(display_window_env, mock_settings):
|
||||
|
@ -189,13 +189,31 @@ def test_set_scale_initialised(display_window_env, mock_settings):
|
|||
# GIVEN: A initialised display window
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
|
||||
# WHEN: set scale is run
|
||||
display_window.set_scale(0.5)
|
||||
|
||||
# THEN: javascript should not be run
|
||||
display_window.run_javascript.assert_called_once_with('Display.setScale(50.0);')
|
||||
display_window.run_in_display.assert_called_once_with('setScale', 50.0)
|
||||
|
||||
|
||||
def test_set_display_custom_url_works_http(registry, display_window_env, mock_settings):
|
||||
"""
|
||||
Test that setting a display custom url works with HTTP path
|
||||
"""
|
||||
# GIVEN: A mocked set_url and a custom display path
|
||||
test_path = 'http://localhost:4200?testing=true'
|
||||
registry.register('display_custom_url', test_path)
|
||||
|
||||
with patch('openlp.core.display.window.DisplayWindow.set_url') as mocked_set_url, \
|
||||
patch('openlp.core.display.window.QtCore.QUrl') as mocked_qurl:
|
||||
mocked_qurl.side_effect = lambda input: input
|
||||
# WHEN: creating a DisplayWindow
|
||||
DisplayWindow()
|
||||
|
||||
# THEN: URL should be set with the custom path
|
||||
mocked_set_url.assert_called_once_with(test_path)
|
||||
|
||||
|
||||
def test_set_startup_screen(display_window_env, mock_settings):
|
||||
|
@ -205,7 +223,7 @@ def test_set_startup_screen(display_window_env, mock_settings):
|
|||
# GIVEN: A display window and mocked settings with logo path
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
|
||||
if is_win():
|
||||
image_path = 'c:/my/image.png'
|
||||
|
@ -225,8 +243,9 @@ def test_set_startup_screen(display_window_env, mock_settings):
|
|||
display_window.set_startup_screen()
|
||||
|
||||
# THEN: javascript should be run
|
||||
display_window.run_javascript.assert_called_once_with(
|
||||
'Display.setStartupSplashScreen("red", "openlp-library://local-file/{path}");'.format(path=expect_image_path))
|
||||
display_window.run_in_display.assert_called_once_with('setStartupSplashScreen', "red",
|
||||
"openlp-library://local-file/{path}"
|
||||
.format(path=expect_image_path))
|
||||
|
||||
|
||||
def test_set_startup_screen_default_image(display_window_env, mock_settings):
|
||||
|
@ -236,7 +255,7 @@ def test_set_startup_screen_default_image(display_window_env, mock_settings):
|
|||
# GIVEN: A display window and mocked settings with logo path
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
splash_screen_path = 'openlp://display/openlp-splash-screen.png'
|
||||
expect_splash_screen_path = splash_screen_path
|
||||
display_window.openlp_splash_screen_path = splash_screen_path
|
||||
|
@ -251,8 +270,8 @@ def test_set_startup_screen_default_image(display_window_env, mock_settings):
|
|||
display_window.set_startup_screen()
|
||||
|
||||
# THEN: javascript should be run
|
||||
display_window.run_javascript.assert_called_with(
|
||||
'Display.setStartupSplashScreen("blue", "{path}");'.format(path=expect_splash_screen_path))
|
||||
display_window.run_in_display.assert_called_with('setStartupSplashScreen', 'blue',
|
||||
"{path}".format(path=expect_splash_screen_path))
|
||||
|
||||
|
||||
def test_set_startup_screen_missing(display_window_env, mock_settings):
|
||||
|
@ -262,7 +281,7 @@ def test_set_startup_screen_missing(display_window_env, mock_settings):
|
|||
# GIVEN: A display window and mocked settings with logo path missing
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.openlp_splash_screen_path = Path('/default/splash_screen.png')
|
||||
settings = {
|
||||
'core/logo background color': 'green',
|
||||
|
@ -275,8 +294,7 @@ def test_set_startup_screen_missing(display_window_env, mock_settings):
|
|||
display_window.set_startup_screen()
|
||||
|
||||
# THEN: javascript should be run
|
||||
display_window.run_javascript.assert_called_with(
|
||||
'Display.setStartupSplashScreen("green", "");')
|
||||
display_window.run_in_display.assert_called_with('setStartupSplashScreen', 'green', '')
|
||||
|
||||
|
||||
def test_set_startup_screen_hide(display_window_env, mock_settings):
|
||||
|
@ -286,7 +304,7 @@ def test_set_startup_screen_hide(display_window_env, mock_settings):
|
|||
# GIVEN: A display window and mocked settings with hide logo true
|
||||
display_window = DisplayWindow()
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.openlp_splash_screen_path = Path('/default/splash_screen.png')
|
||||
settings = {
|
||||
'core/logo background color': 'orange',
|
||||
|
@ -299,8 +317,7 @@ def test_set_startup_screen_hide(display_window_env, mock_settings):
|
|||
display_window.set_startup_screen()
|
||||
|
||||
# THEN: javascript should be run
|
||||
display_window.run_javascript.assert_called_once_with(
|
||||
'Display.setStartupSplashScreen("orange", "");')
|
||||
display_window.run_in_display.assert_called_once_with('setStartupSplashScreen', 'orange', '')
|
||||
|
||||
|
||||
def test_after_loaded(display_window_env, mock_settings, registry):
|
||||
|
@ -313,7 +330,7 @@ def test_after_loaded(display_window_env, mock_settings, registry):
|
|||
mock_settings.value.return_value = True
|
||||
display_window.scale = 2
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.set_scale = MagicMock()
|
||||
display_window.set_startup_screen = MagicMock()
|
||||
|
||||
|
@ -321,17 +338,16 @@ def test_after_loaded(display_window_env, mock_settings, registry):
|
|||
display_window.after_loaded()
|
||||
|
||||
# THEN: The following functions should have been called
|
||||
display_window.run_javascript.assert_called_once_with('Display.init({'
|
||||
'isDisplay: true,'
|
||||
'doItemTransitions: true,'
|
||||
'slideNumbersInFooter: true,'
|
||||
'hideMouse: true'
|
||||
'});')
|
||||
display_window.run_in_display.assert_called_once_with('init', {'isDisplay': True,
|
||||
'doItemTransitions': True,
|
||||
'slideNumbersInFooter': True,
|
||||
'hideMouse': True,
|
||||
'displayTitle': None})
|
||||
display_window.set_scale.assert_called_once_with(2)
|
||||
display_window.set_startup_screen.assert_called_once()
|
||||
|
||||
|
||||
def test_after_loaded_hide_mouse_not_display(display_window_env, mock_settings, registry):
|
||||
def test_after_loaded_hide_mouse_not_display(display_window_env, mock_settings):
|
||||
"""
|
||||
Test the mouse is showing even if the `hide mouse` setting is set while is_display=false
|
||||
"""
|
||||
|
@ -341,7 +357,7 @@ def test_after_loaded_hide_mouse_not_display(display_window_env, mock_settings,
|
|||
mock_settings.value.return_value = True
|
||||
display_window.scale = 2
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.set_scale = MagicMock()
|
||||
display_window.set_startup_screen = MagicMock()
|
||||
|
||||
|
@ -349,12 +365,11 @@ def test_after_loaded_hide_mouse_not_display(display_window_env, mock_settings,
|
|||
display_window.after_loaded()
|
||||
|
||||
# THEN: Display.init should be called where is_display=false, do_item_transitions=true, show_mouse=false
|
||||
display_window.run_javascript.assert_called_once_with('Display.init({'
|
||||
'isDisplay: false,'
|
||||
'doItemTransitions: true,'
|
||||
'slideNumbersInFooter: true,'
|
||||
'hideMouse: false'
|
||||
'});')
|
||||
display_window.run_in_display.assert_called_once_with('init', {'isDisplay': False,
|
||||
'doItemTransitions': True,
|
||||
'slideNumbersInFooter': True,
|
||||
'hideMouse': False,
|
||||
'displayTitle': None})
|
||||
|
||||
|
||||
def test_after_loaded_callback(display_window_env, mock_settings, registry):
|
||||
|
@ -367,7 +382,7 @@ def test_after_loaded_callback(display_window_env, mock_settings, registry):
|
|||
display_window.is_display = True
|
||||
mock_settings.value.return_value = True
|
||||
display_window._is_initialised = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.set_scale = MagicMock()
|
||||
display_window.set_startup_screen = MagicMock()
|
||||
|
||||
|
@ -379,7 +394,7 @@ def test_after_loaded_callback(display_window_env, mock_settings, registry):
|
|||
|
||||
|
||||
@patch.object(time, 'time')
|
||||
def test_run_javascript_no_sync_no_wait(mock_time, display_window_env, mock_settings):
|
||||
def test_run_in_display_no_sync_no_wait(mock_time, display_window_env, mock_settings):
|
||||
"""
|
||||
test a script is run on the webview
|
||||
"""
|
||||
|
@ -389,7 +404,7 @@ def test_run_javascript_no_sync_no_wait(mock_time, display_window_env, mock_sett
|
|||
display_window.webview.page = MagicMock(return_value=webengine_page)
|
||||
|
||||
# WHEN: javascript is requested to run
|
||||
display_window.run_javascript('javascript to execute')
|
||||
display_window._run_javascript('javascript to execute')
|
||||
|
||||
# THEN: javascript should be run with no delay
|
||||
webengine_page.runJavaScript.assert_called_once_with('javascript to execute')
|
||||
|
@ -397,7 +412,7 @@ def test_run_javascript_no_sync_no_wait(mock_time, display_window_env, mock_sett
|
|||
|
||||
|
||||
@patch.object(time, 'time')
|
||||
def test_run_javascript_sync_no_wait(mock_time, display_window_env, mock_settings):
|
||||
def test_run_in_display_sync_no_wait(mock_time, display_window_env, mock_settings):
|
||||
"""
|
||||
test a synced script is run on the webview and immediately returns a result
|
||||
"""
|
||||
|
@ -411,7 +426,7 @@ def test_run_javascript_sync_no_wait(mock_time, display_window_env, mock_setting
|
|||
display_window.webview.page.return_value = webengine_page
|
||||
|
||||
# WHEN: javascript is requested to run
|
||||
result = display_window.run_javascript('javascript to execute', True)
|
||||
result = display_window._run_javascript('javascript to execute', True)
|
||||
|
||||
# THEN: javascript should be run with no delay and return with the correct result
|
||||
assert result == 1234
|
||||
|
@ -428,7 +443,7 @@ def test_fix_font_bold_windows(mocked_is_win, display_window_env, mock_settings)
|
|||
mocked_is_win.return_value = True
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
font_name = 'Arial Rounded MT Bold'
|
||||
|
||||
# WHEN: The font is processed
|
||||
|
@ -447,7 +462,7 @@ def test_fix_font_bold_not_windows(mocked_is_win, display_window_env, mock_setti
|
|||
mocked_is_win.return_value = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
font_name = 'Arial Rounded MT Bold'
|
||||
|
||||
# WHEN: The font is processed
|
||||
|
@ -466,7 +481,7 @@ def test_fix_font_foundry(mocked_is_win, display_window_env, mock_settings):
|
|||
mocked_is_win.return_value = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
font_name = 'CMG Sans [Foundry]'
|
||||
|
||||
# WHEN: The font is processed
|
||||
|
@ -483,7 +498,7 @@ def test_set_theme_is_display_video(display_window_env, mock_settings, mock_geom
|
|||
# GIVEN: A display window and a video theme
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = True
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
theme = Theme()
|
||||
theme.background_type = 'video'
|
||||
result_theme = Theme()
|
||||
|
@ -494,8 +509,7 @@ def test_set_theme_is_display_video(display_window_env, mock_settings, mock_geom
|
|||
display_window.set_theme(theme, is_sync=False, service_item_type=ServiceItemType.Text)
|
||||
|
||||
# THEN: The final theme should be transparent
|
||||
display_window.run_javascript.assert_called_once_with('Display.setTheme({theme});'.format(theme=result_theme),
|
||||
is_sync=False)
|
||||
display_window.run_in_display.assert_called_once_with('setTheme', raw_parameters=result_theme, is_sync=False)
|
||||
|
||||
|
||||
def test_set_theme_not_display_video(display_window_env, mock_settings, mock_geometry):
|
||||
|
@ -505,7 +519,7 @@ def test_set_theme_not_display_video(display_window_env, mock_settings, mock_geo
|
|||
# GIVEN: A display window and a video theme
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = False
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
theme = Theme()
|
||||
theme.background_type = 'video'
|
||||
theme.background_border_color = 'border_colour'
|
||||
|
@ -523,8 +537,7 @@ def test_set_theme_not_display_video(display_window_env, mock_settings, mock_geo
|
|||
display_window.set_theme(theme, is_sync=False, service_item_type=False)
|
||||
|
||||
# THEN: The final theme should use 'border_colour' for it's colour values
|
||||
display_window.run_javascript.assert_called_once_with('Display.setTheme({theme});'.format(theme=result_theme),
|
||||
is_sync=False)
|
||||
display_window.run_in_display.assert_called_once_with('setTheme', raw_parameters=result_theme, is_sync=False)
|
||||
|
||||
|
||||
def test_set_theme_not_display_live(display_window_env, mock_settings, mock_geometry):
|
||||
|
@ -534,7 +547,7 @@ def test_set_theme_not_display_live(display_window_env, mock_settings, mock_geom
|
|||
# GIVEN: A display window and a video theme
|
||||
display_window = DisplayWindow()
|
||||
display_window.is_display = False
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
theme = Theme()
|
||||
theme.background_type = 'live'
|
||||
result_theme = Theme()
|
||||
|
@ -549,8 +562,7 @@ def test_set_theme_not_display_live(display_window_env, mock_settings, mock_geom
|
|||
display_window.set_theme(theme, is_sync=False, service_item_type=False)
|
||||
|
||||
# THEN: The final theme should use the preset colour values
|
||||
display_window.run_javascript.assert_called_once_with('Display.setTheme({theme});'.format(theme=result_theme),
|
||||
is_sync=False)
|
||||
display_window.run_in_display.assert_called_once_with('setTheme', raw_parameters=result_theme, is_sync=False)
|
||||
|
||||
|
||||
@patch('openlp.core.display.window.Registry.execute')
|
||||
|
@ -564,7 +576,7 @@ def test_show_display(mocked_screenlist, mocked_registry_execute, display_window
|
|||
display_window.is_display = True
|
||||
display_window.isHidden = MagicMock(return_value=True)
|
||||
display_window.setVisible = MagicMock()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
mocked_screenlist.screens = [1, 2]
|
||||
|
||||
# WHEN: Show display is run
|
||||
|
@ -572,7 +584,7 @@ def test_show_display(mocked_screenlist, mocked_registry_execute, display_window
|
|||
|
||||
# THEN: Should show the display and set the hide mode to none
|
||||
display_window.setVisible.assert_called_once_with(True)
|
||||
display_window.run_javascript.assert_called_once_with('Display.show();')
|
||||
display_window.run_in_display.assert_called_once_with('show')
|
||||
|
||||
|
||||
@patch('openlp.core.display.window.ScreenList')
|
||||
|
@ -582,7 +594,7 @@ def test_show_display_no_display(mocked_screenlist, display_window_env, mock_set
|
|||
"""
|
||||
# GIVEN: A Display window, one screen and core/display on monitor disabled
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.is_display = True
|
||||
mocked_screenlist.return_value = [1]
|
||||
mock_settings.value.return_value = False
|
||||
|
@ -591,7 +603,7 @@ def test_show_display_no_display(mocked_screenlist, display_window_env, mock_set
|
|||
display_window.show_display()
|
||||
|
||||
# THEN: Shouldn't run the js show fn
|
||||
assert display_window.run_javascript.call_count == 0
|
||||
assert display_window.run_in_display.call_count == 0
|
||||
|
||||
|
||||
def test_hide_display_to_screen(display_window_env, mock_settings):
|
||||
|
@ -600,7 +612,7 @@ def test_hide_display_to_screen(display_window_env, mock_settings):
|
|||
"""
|
||||
# GIVEN: Display window and setting advanced/disable transparent display = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.setVisible = MagicMock()
|
||||
mock_settings.value.return_value = False
|
||||
|
||||
|
@ -609,7 +621,7 @@ def test_hide_display_to_screen(display_window_env, mock_settings):
|
|||
|
||||
# THEN: Should hide the display with the js transparency function (not setVisible)
|
||||
display_window.setVisible.call_count == 0
|
||||
display_window.run_javascript.assert_called_once_with('Display.toTransparent();')
|
||||
display_window.run_in_display.assert_called_once_with('toTransparent')
|
||||
|
||||
|
||||
def test_hide_display_to_blank(display_window_env, mock_settings):
|
||||
|
@ -618,14 +630,14 @@ def test_hide_display_to_blank(display_window_env, mock_settings):
|
|||
"""
|
||||
# GIVEN: Display window and setting advanced/disable transparent display = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
mock_settings.value.return_value = False
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Blank
|
||||
display_window.hide_display(HideMode.Blank)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and set the hide mode
|
||||
display_window.run_javascript.assert_called_once_with('Display.toBlack();')
|
||||
display_window.run_in_display.assert_called_once_with('toBlack')
|
||||
|
||||
|
||||
def test_hide_display_to_theme(display_window_env, mock_settings):
|
||||
|
@ -634,14 +646,14 @@ def test_hide_display_to_theme(display_window_env, mock_settings):
|
|||
"""
|
||||
# GIVEN: Display window and setting advanced/disable transparent display = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
mock_settings.value.return_value = False
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Theme
|
||||
display_window.hide_display(HideMode.Theme)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and set the hide mode
|
||||
display_window.run_javascript.assert_called_once_with('Display.toTheme();')
|
||||
display_window.run_in_display.assert_called_once_with('toTheme')
|
||||
|
||||
|
||||
def test_hide_display_to_transparent(display_window_env, mock_settings):
|
||||
|
@ -650,7 +662,7 @@ def test_hide_display_to_transparent(display_window_env, mock_settings):
|
|||
"""
|
||||
# GIVEN: Display window and setting advanced/disable transparent display = False
|
||||
display_window = DisplayWindow()
|
||||
display_window.run_javascript = MagicMock()
|
||||
display_window.run_in_display = MagicMock()
|
||||
display_window.setVisible = MagicMock()
|
||||
mock_settings.value.return_value = False
|
||||
|
||||
|
@ -658,7 +670,7 @@ def test_hide_display_to_transparent(display_window_env, mock_settings):
|
|||
display_window.hide_display(HideMode.Screen)
|
||||
|
||||
# THEN: Should run the correct javascript on the display and not set the visiblity
|
||||
display_window.run_javascript.assert_called_once_with('Display.toTransparent();')
|
||||
display_window.run_in_display.assert_called_once_with('toTransparent')
|
||||
assert display_window.setVisible.call_count == 0
|
||||
|
||||
|
||||
|
@ -774,12 +786,27 @@ def test_display_watcher_unregisters_registered_permanent_and_transient_event(di
|
|||
event_listener_permanent.assert_not_called()
|
||||
|
||||
|
||||
def test_display_watcher_generates_event_names(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that the display watcher generate unique event names
|
||||
"""
|
||||
# GIVEN: Display window
|
||||
display_window = DisplayWindow()
|
||||
|
||||
# WHEN: Getting unique event names
|
||||
first_event_name = display_window.display_watcher.get_unique_event_name()
|
||||
second_event_name = display_window.display_watcher.get_unique_event_name()
|
||||
|
||||
# THEN: Event names should be different
|
||||
assert first_event_name != second_event_name
|
||||
|
||||
|
||||
def test_hide_transparent_to_screen(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when going transparent, and the disable transparent setting is enabled,
|
||||
the screen mode should be used.
|
||||
"""
|
||||
# GIVEN: Display window, setting advanced/disable transparent display = True and mocked run_javascript
|
||||
# GIVEN: Display window, setting advanced/disable transparent display = True and mocked run_in_display
|
||||
display_window = DisplayWindow()
|
||||
display_window.setVisible = MagicMock()
|
||||
has_ran_event = False
|
||||
|
@ -788,11 +815,11 @@ def test_hide_transparent_to_screen(display_window_env, mock_settings):
|
|||
nonlocal has_ran_event
|
||||
has_ran_event = True
|
||||
|
||||
def on_dispatch_event(_):
|
||||
def on_dispatch_event(*args, **kwargs):
|
||||
display_window.display_watcher.register_event_listener(TRANSITION_END_EVENT_NAME, set_has_ran_event, False)
|
||||
display_window.display_watcher.dispatchEvent(TRANSITION_END_EVENT_NAME, {})
|
||||
|
||||
display_window.run_javascript = MagicMock(side_effect=on_dispatch_event)
|
||||
display_window.run_in_display = MagicMock(side_effect=on_dispatch_event)
|
||||
mock_settings.value.return_value = True
|
||||
|
||||
# WHEN: Hide display is run with HideMode.Screen
|
||||
|
@ -887,3 +914,79 @@ def test_close_event_accepts_event_manual_close(display_window_env, mock_setting
|
|||
|
||||
# THEN: The event should have been ignored
|
||||
assert mocked_event.ignore.called is False
|
||||
|
||||
|
||||
def test_run_in_display_run(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when run_in_display is called
|
||||
"""
|
||||
# GIVEN: A DisplayWindow instance and a mocked _run_javascript
|
||||
display_window = DisplayWindow()
|
||||
display_window._run_javascript = MagicMock()
|
||||
|
||||
# WHEN: The run_is_display is called
|
||||
display_window.run_in_display('test_event')
|
||||
|
||||
# THEN: The event should be called
|
||||
display_window._run_javascript.assert_called_once_with('requestAction(\'test_event\')', False)
|
||||
|
||||
|
||||
def test_run_in_display_honors_is_sync(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when run_in_display honors is_sync flag
|
||||
"""
|
||||
# GIVEN: A DisplayWindow instance and a mocked _run_javascript
|
||||
display_window = DisplayWindow()
|
||||
display_window._run_javascript = MagicMock()
|
||||
|
||||
# WHEN: The run_is_display is called
|
||||
display_window.run_in_display('test_event', is_sync=True)
|
||||
|
||||
# THEN: The event should be called
|
||||
display_window._run_javascript.assert_called_once_with('requestAction(\'test_event\')', True)
|
||||
|
||||
|
||||
def test_run_in_display_honors_raw_parameters(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when run_in_display honors raw_parameters parameters
|
||||
"""
|
||||
# GIVEN: A DisplayWindow instance and a mocked _run_javascript
|
||||
display_window = DisplayWindow()
|
||||
display_window._run_javascript = MagicMock()
|
||||
|
||||
# WHEN: The run_is_display is called
|
||||
display_window.run_in_display('test_event', raw_parameters='a test: testing')
|
||||
|
||||
# THEN: The event should be called
|
||||
display_window._run_javascript.assert_called_once_with('requestAction(\'test_event\', a test: testing)', False)
|
||||
|
||||
|
||||
def test_run_in_display_honors_return_event_name(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when run_in_display honors return_event_name parameter
|
||||
"""
|
||||
# GIVEN: A DisplayWindow instance and a mocked _run_javascript
|
||||
display_window = DisplayWindow()
|
||||
display_window._run_javascript = MagicMock()
|
||||
|
||||
# WHEN: The run_is_display is called
|
||||
display_window.run_in_display('test_event', return_event_name='test_event')
|
||||
|
||||
# THEN: The event should be called
|
||||
display_window._run_javascript.assert_called_once_with('requestActionAsync(\'test_event\', \'test_event\')', False)
|
||||
|
||||
|
||||
def test_run_in_display_dumps_json(display_window_env, mock_settings):
|
||||
"""
|
||||
Test that when run_in_display is called with parameters, each of it will be dumped as a JSON string
|
||||
"""
|
||||
# GIVEN: A DisplayWindow instance and a mocked _run_javascript
|
||||
display_window = DisplayWindow()
|
||||
display_window._run_javascript = MagicMock()
|
||||
|
||||
# WHEN: The run_is_display is called
|
||||
display_window.run_in_display('test_event', 1.23, 'a "string', [1, 2, 'test'], {"test1": "test2"})
|
||||
|
||||
# THEN: The parameters should be correctly converted to JSON
|
||||
display_window._run_javascript.assert_called_once_with('requestAction(\'test_event\', 1.23, "a \\"string\", '
|
||||
'[1, 2, "test"], {"test1": "test2"})', False)
|
||||
|
|
Loading…
Reference in New Issue