diff --git a/Options.qml b/Options.qml index 7d32359..65cd55f 100644 --- a/Options.qml +++ b/Options.qml @@ -36,10 +36,10 @@ Pane { hoverEnabled: true ToolTip.visible: hovered ToolTip.text: qsTr("Path to the folder containing the addons") - enabled: Control.status == Control.Ready && addonsReady + enabled: Engine.status == Engine.Ready && addonsReady } Button { - enabled: Control.status == Control.Ready && addonsReady + enabled: Engine.status == Engine.Ready && addonsReady text: qsTr("Browse") onClicked: {fileDialog.selector = index; fileDialog.currentFolder = "file://" + Engine.addonsPaths[index]; fileDialog.visible = true} hoverEnabled: true diff --git a/addon.cpp b/addon.cpp index 90b3972..3cda1fa 100644 --- a/addon.cpp +++ b/addon.cpp @@ -691,7 +691,7 @@ AutoPtr Addon::branchRef(QString name) void Addon::delegate(QString taskname, auto work, auto callback, bool force) { Q_ASSERT_X(QThread::currentThread() == thread(), "delegate", "Attempt to delegate from another thread."); - if (status() != Status::Ready && !force) { + if (m_lock && !force) { qInfo() << name() << "Enqueueing" << taskname; m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}}); return; @@ -700,10 +700,12 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force) setProgress(0); setTotal(0); setStatus(Status::Busy); + m_lock = true; using ret_t = typename std::invoke_result::type; QFuture fut = QtConcurrent::run(m_pool, work); QFutureWatcher *fw = new QFutureWatcher(); connect(fw, &QFutureWatcher::finished, [this, callback, fw, taskname](){ + m_lock = false; if (fw->isCanceled()) { try { fw->waitForFinished(); @@ -714,7 +716,6 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force) } return; } - setStatus(Status::Ready); TaskQueue old; m_tasks.swap(old); @@ -725,7 +726,9 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force) m_tasks.append(old); - if (!m_tasks.isEmpty() && status() != Status::Busy) + if (m_tasks.empty()) + setStatus(Status::Ready); + else if (!m_lock) m_tasks.dequeue().second(); }); connect(fw, &QFutureWatcher::finished, fw, &QFutureWatcher::deleteLater); diff --git a/addon.h b/addon.h index 6c7a4cd..690031f 100644 --- a/addon.h +++ b/addon.h @@ -59,6 +59,8 @@ class Addon : public QObject QMutex m_mutex; QWaitCondition m_wait; void *m_result; + + bool m_lock = false; public: Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QStringList branches READ branches WRITE setBranches NOTIFY branchesChanged) diff --git a/control.cpp b/control.cpp index 03b22c7..027ee16 100644 --- a/control.cpp +++ b/control.cpp @@ -86,7 +86,7 @@ void Control::removeTocSuffixes(QString &string) void Control::delegate(QString taskname, auto work, auto callback) { Q_ASSERT_X(QThread::currentThread() == thread(), "delegate", "Attempt to delegate from another thread."); - if (status() != Status::Ready) { + if (m_lock) { qInfo() << "Enqueueing" << taskname; m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}}); return; @@ -95,12 +95,13 @@ void Control::delegate(QString taskname, auto work, auto callback) setStatusMessage(taskname); setProgress(0); setTotal(0); - setStatus(Status::Busy); + BusyLock lock(this); + m_lock = true; using ret_t = typename std::invoke_result::type; QFuture fut = QtConcurrent::run(m_pool, work); QFutureWatcher *fw = new QFutureWatcher(); - connect(fw, &QFutureWatcher::finished, [this, callback, fw](){ - setStatus(Status::Ready); + connect(fw, &QFutureWatcher::finished, [this, callback, fw, lock=std::move(lock)](){ + m_lock = false; TaskQueue old; m_tasks.swap(old); @@ -111,7 +112,9 @@ void Control::delegate(QString taskname, auto work, auto callback) m_tasks.append(old); - if (!m_tasks.isEmpty() && status() != Status::Busy) + if (m_tasks.empty()) + setStatus(Status::Ready); + else if (!m_lock) m_tasks.dequeue().second(); }); connect(fw, &QFutureWatcher::finished, fw, &QFutureWatcher::deleteLater); @@ -340,6 +343,7 @@ void Control::saveAddonsPaths() void Control::scanForAddons(int i) { if (i == -1) { + BusyLock lock(this); foreach (Addon *addon, m_addons) addon->deleteLater(); QList ol; @@ -703,3 +707,25 @@ bool Control::selfUpdates() const return false; #endif } + +int Control::BusyLock::count = 0; + +Control::BusyLock::BusyLock(Control *c) +{ + m_locked = c; + m_locked->setStatus(Status::Busy); + count++; +} + +Control::BusyLock::BusyLock(BusyLock &&other) +{ + m_locked = other.m_locked; + other.m_locked = nullptr; +} + +Control::BusyLock::~BusyLock() +{ + if (m_locked) + if (!--count && m_locked->m_tasks.empty()) + m_locked->setStatus(Status::Ready); +} diff --git a/control.h b/control.h index aa050f3..f23688b 100644 --- a/control.h +++ b/control.h @@ -45,14 +45,26 @@ public: int check_git_return(int code); + class Control : public QObject { + + class BusyLock + { + static int count; + Control* m_locked = nullptr; + public: + BusyLock(Control* c); + BusyLock(BusyLock&& other); + ~BusyLock(); + }; Q_OBJECT using TaskQueue = QQueue>>; TaskQueue m_tasks; QList m_addons; + bool m_lock = false; public: Q_PROPERTY(QString version READ version CONSTANT) diff --git a/main.qml b/main.qml index 487195c..7684c20 100644 --- a/main.qml +++ b/main.qml @@ -30,7 +30,7 @@ ApplicationWindow { property bool addonsReady: false Component.onCompleted: { availableUpdates = Qt.binding(function(){ - if (!addonsReady) + if (!(Engine.status == Engine.Ready && addonsReady)) return -1; var count = 0 for (var i = 0; i < Engine.addons.length; i++) { @@ -40,16 +40,18 @@ ApplicationWindow { } return count }) - addonsReady = Qt.binding(function(){ - for (var i = 0; i < Engine.addons.length; i++) { - var addon = Engine.addons[i] - if (addon.status == Addon.Status.Busy) - return false - } - return true - }) + addonsReady = Qt.binding(checkAddonsReady) } + function checkAddonsReady(){ + for (var i = 0; i < Engine.addons.length; i++) { + var addon = Engine.addons[i] + console.debug(addon.status) + if (addon.status == Addon.Status.Busy) + return false + } + return true + } function updateAll() { for (var i = 0; i < Engine.addons.length; i++) { var addon = Engine.addons[i] @@ -59,6 +61,8 @@ ApplicationWindow { } onAvailableUpdatesChanged: { + if (availableUpdates == -1) + return; if (availableUpdates > 0) { tray.showMessage("Addons updates available", "You have " + availableUpdates + " addons waiting for update.", 1, 5000) } else { @@ -81,7 +85,7 @@ ApplicationWindow { icon.name: "view-refresh" onTriggered: Engine.scanForAddons() shortcut: StandardKey.Refresh - enabled: Control.status == Control.Ready && addonsReady + enabled: Engine.status == Engine.Ready && addonsReady } Action { id: addAction @@ -94,7 +98,7 @@ ApplicationWindow { icon.name: "export-symbolic" onTriggered: exportListDialog.visible = true - enabled: Control.status == Control.Ready && addonsReady + enabled: Engine.status == Engine.Ready && addonsReady shortcut: StandardKey.SaveAs } Action {