From 5d7d66f99b56cce0e833999ba737eb784d347cab Mon Sep 17 00:00:00 2001 From: miruka Date: Wed, 18 Dec 2019 06:16:24 -0400 Subject: [PATCH] Have a QML Future object instead of JS dict --- src/gui/PythonBridge/EventHandlers.qml | 6 +- src/gui/PythonBridge/Future.qml | 25 +++++++ src/gui/PythonBridge/PythonBridge.qml | 93 +++++++++++--------------- 3 files changed, 68 insertions(+), 56 deletions(-) create mode 100644 src/gui/PythonBridge/Future.qml diff --git a/src/gui/PythonBridge/EventHandlers.qml b/src/gui/PythonBridge/EventHandlers.qml index 08018619..50cf9cdf 100644 --- a/src/gui/PythonBridge/EventHandlers.qml +++ b/src/gui/PythonBridge/EventHandlers.qml @@ -14,8 +14,8 @@ QtObject { function onCoroutineDone(uuid, result, error, traceback) { - let onSuccess = py.pendingCoroutines[uuid].onSuccess - let onError = py.pendingCoroutines[uuid].onError + let onSuccess = py.privates.pendingCoroutines[uuid].onSuccess + let onError = py.privates.pendingCoroutines[uuid].onError if (error) { let type = py.getattr(py.getattr(error, "__class__"), "__name__") @@ -31,7 +31,7 @@ QtObject { } else if (onSuccess) { onSuccess(result) } - delete pendingCoroutines[uuid] + delete py.privates.pendingCoroutines[uuid] } diff --git a/src/gui/PythonBridge/Future.qml b/src/gui/PythonBridge/Future.qml new file mode 100644 index 00000000..3e56a2e2 --- /dev/null +++ b/src/gui/PythonBridge/Future.qml @@ -0,0 +1,25 @@ +import QtQuick 2.12 + +QtObject { + id: future + + + property PythonBridge bridge + + readonly property QtObject privates: QtObject { + onPythonFutureChanged: if (cancelPending) future.cancel() + + property var pythonFuture: null + property bool cancelPending: false + } + + + function cancel() { + if (! privates.pythonFuture) { + privates.cancelPending = true + return + } + + bridge.call(bridge.getattr(privates.pythonFuture, "cancel")) + } +} diff --git a/src/gui/PythonBridge/PythonBridge.qml b/src/gui/PythonBridge/PythonBridge.qml index 1ac1f0ea..9214f9f6 100644 --- a/src/gui/PythonBridge/PythonBridge.qml +++ b/src/gui/PythonBridge/PythonBridge.qml @@ -3,86 +3,94 @@ import io.thp.pyotherside 1.5 Python { id: py + Component.onCompleted: { + for (var func in privates.eventHandlers) { + if (! privates.eventHandlers.hasOwnProperty(func)) continue + setHandler(func.replace(/^on/, ""), privates.eventHandlers[func]) + } + + addImportPath("src") + addImportPath("qrc:/src") + + importNames("backend", ["APP"], () => { + loadSettings(() => { + callCoro("saved_accounts.any_saved", [], any => { + if (any) { py.callCoro("load_saved_accounts", []) } + + py.startupAnyAccountsSaved = any + py.ready = true + }) + }) + }) + } property bool ready: false property bool startupAnyAccountsSaved: false - property var pendingCoroutines: ({}) - property EventHandlers eventHandlers: EventHandlers {} + readonly property QtObject privates: QtObject { + readonly property var pendingCoroutines: ({}) + readonly property EventHandlers eventHandlers: EventHandlers {} - - function newQmlFuture() { - return { - _pyFuture: null, - - get pyFuture() { return this._pyFuture }, - - set pyFuture(value) { - this._pyFuture = value - if (this.cancelPending) this.cancel() - }, - - cancelPending: false, - - cancel: function() { - if (! this.pyFuture) { - this.cancelPending = true - return - } - - py.call(py.getattr(this.pyFuture, "cancel")) - }, + function makeFuture(callback) { + return Qt.createComponent("Future.qml") + .createObject(py, {bridge: py}) } } + function setattr(obj, attr, value, callback=null) { py.call(py.getattr(obj, "__setattr__"), [attr, value], callback) } + function callSync(name, args=[]) { return call_sync("APP.backend." + name, args) } + function callCoro(name, args=[], onSuccess=null, onError=null) { let uuid = name + "." + CppUtils.uuid() - pendingCoroutines[uuid] = {onSuccess, onError} + privates.pendingCoroutines[uuid] = {onSuccess, onError} - let qmlFuture = py.newQmlFuture() + let future = privates.makeFuture() call("APP.call_backend_coro", [name, uuid, args], pyFuture => { - qmlFuture.pyFuture = pyFuture + future.privates.pythonFuture = pyFuture }) - return qmlFuture + return future } + function callClientCoro( accountId, name, args=[], onSuccess=null, onError=null ) { - let qmlFuture = py.newQmlFuture() + let future = privates.makeFuture() callCoro("wait_until_client_exists", [accountId], () => { let uuid = accountId + "." + name + "." + CppUtils.uuid() - pendingCoroutines[uuid] = {onSuccess, onError} + privates.pendingCoroutines[uuid] = {onSuccess, onError} let call_args = [accountId, name, uuid, args] call("APP.call_client_coro", call_args, pyFuture => { - qmlFuture.pyFuture = pyFuture + future.privates.pythonFuture = pyFuture }) }) - return qmlFuture + return future } + function saveConfig(backend_attribute, data, callback=null) { if (! py.ready) { return } // config not loaded yet return callCoro(backend_attribute + ".write", [data], callback) } + function loadSettings(callback=null) { let func = "load_settings" @@ -95,25 +103,4 @@ Python { if (callback) { callback(settings, uiState, theme) } }) } - - Component.onCompleted: { - for (var func in eventHandlers) { - if (eventHandlers.hasOwnProperty(func)) { - setHandler(func.replace(/^on/, ""), eventHandlers[func]) - } - } - - addImportPath("src") - addImportPath("qrc:/src") - importNames("backend", ["APP"], () => { - loadSettings(() => { - callCoro("saved_accounts.any_saved", [], any => { - if (any) { py.callCoro("load_saved_accounts", []) } - - py.startupAnyAccountsSaved = any - py.ready = true - }) - }) - }) - } }