From d8fd1ff3dd90d0172bc018ebc4305f05bfc546fb Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Sun, 18 Jan 2015 14:22:05 +0100 Subject: [PATCH] Use QML WorkerScript for loading and updating models --- common/GPodderEpisodeListModel.qml | 15 +++-- common/GPodderEpisodeListModelConnections.qml | 4 +- common/GPodderPodcastListModel.qml | 6 +- common/ModelWorkerScript.qml | 67 +++++++++++++++++++ common/modelworker.js | 42 ++++++++++++ common/util.js | 25 ------- 6 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 common/ModelWorkerScript.qml create mode 100644 common/modelworker.js diff --git a/common/GPodderEpisodeListModel.qml b/common/GPodderEpisodeListModel.qml index a51b540..33535b6 100644 --- a/common/GPodderEpisodeListModel.qml +++ b/common/GPodderEpisodeListModel.qml @@ -62,6 +62,10 @@ ListModel { }); } + property var worker: ModelWorkerScript { + id: modelWorker + } + function forEachEpisode(callback) { // Go from bottom up (= chronological order) for (var i=count-1; i>=0; i--) { @@ -122,11 +126,12 @@ ListModel { ready = false; py.call('main.load_episodes', [podcast_id, query], function (episodes) { - Util.updateModelFrom(episodeListModel, episodes); - episodeListModel.ready = true; - if (callback !== undefined) { - callback(); - } + modelWorker.updateModelFrom(episodeListModel, episodes, function () { + episodeListModel.ready = true; + if (callback !== undefined) { + callback(); + } + }); }); } } diff --git a/common/GPodderEpisodeListModelConnections.qml b/common/GPodderEpisodeListModelConnections.qml index 9744dab..22806ad 100644 --- a/common/GPodderEpisodeListModelConnections.qml +++ b/common/GPodderEpisodeListModelConnections.qml @@ -26,11 +26,11 @@ Connections { target: py onDownloadProgress: { - Util.updateModelWith(episodeListModel, 'id', episode_id, + episodeListModel.worker.updateModelWith(episodeListModel, 'id', episode_id, {'progress': progress}); } onPlaybackProgress: { - Util.updateModelWith(episodeListModel, 'id', episode_id, + episodeListModel.worker.updateModelWith(episodeListModel, 'id', episode_id, {'playbackProgress': progress}); } onUpdatedEpisode: { diff --git a/common/GPodderPodcastListModel.qml b/common/GPodderPodcastListModel.qml index 285bf16..aa17c2f 100644 --- a/common/GPodderPodcastListModel.qml +++ b/common/GPodderPodcastListModel.qml @@ -25,9 +25,13 @@ import 'util.js' as Util ListModel { id: podcastListModel + property var worker: ModelWorkerScript { + id: modelWorker + } + function reload() { py.call('main.load_podcasts', [], function (podcasts) { - Util.updateModelFrom(podcastListModel, podcasts); + modelWorker.updateModelFrom(podcastListModel, podcasts); }); } } diff --git a/common/ModelWorkerScript.qml b/common/ModelWorkerScript.qml new file mode 100644 index 0000000..19c0057 --- /dev/null +++ b/common/ModelWorkerScript.qml @@ -0,0 +1,67 @@ + +/** + * + * gPodder QML UI Reference Implementation + * Copyright (c) 2015, Thomas Perl + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +import QtQuick 2.0 + + +WorkerScript { + source: 'modelworker.js' + + property int callbacks_seq: 1 + property var callbacks: ({}) + + function refCallback(callback) { + var id = callbacks_seq++; + callbacks[id] = callback; + return id; + } + + function unrefCallback(callback) { + var result = callbacks[callback]; + delete callbacks[callback]; + return result; + } + + function updateModelFrom(model, data, callback) { + sendMessage({ + action: 'updateModelFrom', + model: model, + data: data, + callback: refCallback(callback), + }); + } + + function updateModelWith(model, key, value, update, callback) { + sendMessage({ + action: 'updateModelWith', + model: model, + key: key, + value: value, + update: update, + callback: refCallback(callback), + }); + } + + onMessage: { + if (messageObject.callback !== undefined) { + unrefCallback(messageObject.callback)(); + } + } +} diff --git a/common/modelworker.js b/common/modelworker.js new file mode 100644 index 0000000..44561bd --- /dev/null +++ b/common/modelworker.js @@ -0,0 +1,42 @@ +function updateModelFrom(model, data) { + // TODO: This is very naive at the moment, we should do proper remove(), + // move(), set() and insert() calls, so that the UI can animate changes. + for (var i=0; i data.length) { + model.remove(model.count-1); + } + + model.sync(); +} + +function updateModelWith(model, key, value, update) { + for (var row=0; row data.length) { - model.remove(model.count-1); - } -} - -function updateModelWith(model, key, value, update) { - for (var row=0; row