Use QML WorkerScript for loading and updating models

This commit is contained in:
Thomas Perl 2015-01-18 14:22:05 +01:00
parent 376b3225f6
commit d8fd1ff3dd
6 changed files with 126 additions and 33 deletions

View file

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

View file

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

View file

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

View file

@ -0,0 +1,67 @@
/**
*
* gPodder QML UI Reference Implementation
* Copyright (c) 2015, Thomas Perl <m@thp.io>
*
* 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)();
}
}
}

42
common/modelworker.js Normal file
View file

@ -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; i++) {
if (model.count < i) {
model.append(data[i]);
} else {
model.set(i, data[i]);
}
}
while (model.count > data.length) {
model.remove(model.count-1);
}
model.sync();
}
function updateModelWith(model, key, value, update) {
for (var row=0; row<model.count; row++) {
var current = model.get(row);
if (current[key] == value) {
for (var key in update) {
model.setProperty(row, key, update[key]);
}
}
}
model.sync();
}
WorkerScript.onMessage = function (msg) {
if (msg.action === 'updateModelFrom') {
updateModelFrom(msg.model, msg.data);
WorkerScript.sendMessage({callback: msg.callback});
} else if (msg.action === 'updateModelWith') {
updateModelWith(msg.model, msg.key, msg.value, msg.update);
WorkerScript.sendMessage({callback: msg.callback});
} else {
console.log('Unknown action: ' + msg.action);
}
}

View file

@ -18,31 +18,6 @@
*
*/
function updateModelFrom(model, data) {
for (var i=0; i<data.length; i++) {
if (model.count < i) {
model.append(data[i]);
} else {
model.set(i, data[i]);
}
}
while (model.count > data.length) {
model.remove(model.count-1);
}
}
function updateModelWith(model, key, value, update) {
for (var row=0; row<model.count; row++) {
var current = model.get(row);
if (current[key] == value) {
for (var key in update) {
model.setProperty(row, key, update[key]);
}
}
}
}
function formatDuration(duration) {
if (duration !== 0 && !duration) {
return ''