Fix notification flood
Avoid sending status changes in between queued operations
This commit is contained in:
+2
-2
@@ -36,10 +36,10 @@ Pane {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: qsTr("Path to the folder containing the addons")
|
ToolTip.text: qsTr("Path to the folder containing the addons")
|
||||||
enabled: Control.status == Control.Ready && addonsReady
|
enabled: Engine.status == Engine.Ready && addonsReady
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
enabled: Control.status == Control.Ready && addonsReady
|
enabled: Engine.status == Engine.Ready && addonsReady
|
||||||
text: qsTr("Browse")
|
text: qsTr("Browse")
|
||||||
onClicked: {fileDialog.selector = index; fileDialog.currentFolder = "file://" + Engine.addonsPaths[index]; fileDialog.visible = true}
|
onClicked: {fileDialog.selector = index; fileDialog.currentFolder = "file://" + Engine.addonsPaths[index]; fileDialog.visible = true}
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|||||||
@@ -691,7 +691,7 @@ AutoPtr<git_reference> Addon::branchRef(QString name)
|
|||||||
void Addon::delegate(QString taskname, auto work, auto callback, bool force)
|
void Addon::delegate(QString taskname, auto work, auto callback, bool force)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(QThread::currentThread() == thread(), "delegate", "Attempt to delegate from another thread.");
|
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;
|
qInfo() << name() << "Enqueueing" << taskname;
|
||||||
m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}});
|
m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}});
|
||||||
return;
|
return;
|
||||||
@@ -700,10 +700,12 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force)
|
|||||||
setProgress(0);
|
setProgress(0);
|
||||||
setTotal(0);
|
setTotal(0);
|
||||||
setStatus(Status::Busy);
|
setStatus(Status::Busy);
|
||||||
|
m_lock = true;
|
||||||
using ret_t = typename std::invoke_result<decltype(work)>::type;
|
using ret_t = typename std::invoke_result<decltype(work)>::type;
|
||||||
QFuture<ret_t> fut = QtConcurrent::run(m_pool, work);
|
QFuture<ret_t> fut = QtConcurrent::run(m_pool, work);
|
||||||
QFutureWatcher<ret_t> *fw = new QFutureWatcher<ret_t>();
|
QFutureWatcher<ret_t> *fw = new QFutureWatcher<ret_t>();
|
||||||
connect(fw, &QFutureWatcher<ret_t>::finished, [this, callback, fw, taskname](){
|
connect(fw, &QFutureWatcher<ret_t>::finished, [this, callback, fw, taskname](){
|
||||||
|
m_lock = false;
|
||||||
if (fw->isCanceled()) {
|
if (fw->isCanceled()) {
|
||||||
try {
|
try {
|
||||||
fw->waitForFinished();
|
fw->waitForFinished();
|
||||||
@@ -714,7 +716,6 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setStatus(Status::Ready);
|
|
||||||
TaskQueue old;
|
TaskQueue old;
|
||||||
m_tasks.swap(old);
|
m_tasks.swap(old);
|
||||||
|
|
||||||
@@ -725,7 +726,9 @@ void Addon::delegate(QString taskname, auto work, auto callback, bool force)
|
|||||||
|
|
||||||
m_tasks.append(old);
|
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();
|
m_tasks.dequeue().second();
|
||||||
});
|
});
|
||||||
connect(fw, &QFutureWatcher<ret_t>::finished, fw, &QFutureWatcher<ret_t>::deleteLater);
|
connect(fw, &QFutureWatcher<ret_t>::finished, fw, &QFutureWatcher<ret_t>::deleteLater);
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class Addon : public QObject
|
|||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
QWaitCondition m_wait;
|
QWaitCondition m_wait;
|
||||||
void *m_result;
|
void *m_result;
|
||||||
|
|
||||||
|
bool m_lock = false;
|
||||||
public:
|
public:
|
||||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||||
Q_PROPERTY(QStringList branches READ branches WRITE setBranches NOTIFY branchesChanged)
|
Q_PROPERTY(QStringList branches READ branches WRITE setBranches NOTIFY branchesChanged)
|
||||||
|
|||||||
+31
-5
@@ -86,7 +86,7 @@ void Control::removeTocSuffixes(QString &string)
|
|||||||
void Control::delegate(QString taskname, auto work, auto callback)
|
void Control::delegate(QString taskname, auto work, auto callback)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(QThread::currentThread() == thread(), "delegate", "Attempt to delegate from another thread.");
|
Q_ASSERT_X(QThread::currentThread() == thread(), "delegate", "Attempt to delegate from another thread.");
|
||||||
if (status() != Status::Ready) {
|
if (m_lock) {
|
||||||
qInfo() << "Enqueueing" << taskname;
|
qInfo() << "Enqueueing" << taskname;
|
||||||
m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}});
|
m_tasks.enqueue({taskname, [this, taskname, work, callback](){delegate(taskname, work,callback);}});
|
||||||
return;
|
return;
|
||||||
@@ -95,12 +95,13 @@ void Control::delegate(QString taskname, auto work, auto callback)
|
|||||||
setStatusMessage(taskname);
|
setStatusMessage(taskname);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
setTotal(0);
|
setTotal(0);
|
||||||
setStatus(Status::Busy);
|
BusyLock lock(this);
|
||||||
|
m_lock = true;
|
||||||
using ret_t = typename std::invoke_result<decltype(work)>::type;
|
using ret_t = typename std::invoke_result<decltype(work)>::type;
|
||||||
QFuture<ret_t> fut = QtConcurrent::run(m_pool, work);
|
QFuture<ret_t> fut = QtConcurrent::run(m_pool, work);
|
||||||
QFutureWatcher<ret_t> *fw = new QFutureWatcher<ret_t>();
|
QFutureWatcher<ret_t> *fw = new QFutureWatcher<ret_t>();
|
||||||
connect(fw, &QFutureWatcher<ret_t>::finished, [this, callback, fw](){
|
connect(fw, &QFutureWatcher<ret_t>::finished, [this, callback, fw, lock=std::move(lock)](){
|
||||||
setStatus(Status::Ready);
|
m_lock = false;
|
||||||
TaskQueue old;
|
TaskQueue old;
|
||||||
m_tasks.swap(old);
|
m_tasks.swap(old);
|
||||||
|
|
||||||
@@ -111,7 +112,9 @@ void Control::delegate(QString taskname, auto work, auto callback)
|
|||||||
|
|
||||||
m_tasks.append(old);
|
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();
|
m_tasks.dequeue().second();
|
||||||
});
|
});
|
||||||
connect(fw, &QFutureWatcher<ret_t>::finished, fw, &QFutureWatcher<ret_t>::deleteLater);
|
connect(fw, &QFutureWatcher<ret_t>::finished, fw, &QFutureWatcher<ret_t>::deleteLater);
|
||||||
@@ -340,6 +343,7 @@ void Control::saveAddonsPaths()
|
|||||||
void Control::scanForAddons(int i)
|
void Control::scanForAddons(int i)
|
||||||
{
|
{
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
|
BusyLock lock(this);
|
||||||
foreach (Addon *addon, m_addons)
|
foreach (Addon *addon, m_addons)
|
||||||
addon->deleteLater();
|
addon->deleteLater();
|
||||||
QList<Addon *> ol;
|
QList<Addon *> ol;
|
||||||
@@ -703,3 +707,25 @@ bool Control::selfUpdates() const
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,14 +45,26 @@ public:
|
|||||||
|
|
||||||
int check_git_return(int code);
|
int check_git_return(int code);
|
||||||
|
|
||||||
|
|
||||||
class Control : public QObject
|
class Control : public QObject
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class BusyLock
|
||||||
|
{
|
||||||
|
static int count;
|
||||||
|
Control* m_locked = nullptr;
|
||||||
|
public:
|
||||||
|
BusyLock(Control* c);
|
||||||
|
BusyLock(BusyLock&& other);
|
||||||
|
~BusyLock();
|
||||||
|
};
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
using TaskQueue = QQueue<QPair<QString,std::function<void()>>>;
|
using TaskQueue = QQueue<QPair<QString,std::function<void()>>>;
|
||||||
TaskQueue m_tasks;
|
TaskQueue m_tasks;
|
||||||
|
|
||||||
QList<Addon *> m_addons;
|
QList<Addon *> m_addons;
|
||||||
|
bool m_lock = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_PROPERTY(QString version READ version CONSTANT)
|
Q_PROPERTY(QString version READ version CONSTANT)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ ApplicationWindow {
|
|||||||
property bool addonsReady: false
|
property bool addonsReady: false
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
availableUpdates = Qt.binding(function(){
|
availableUpdates = Qt.binding(function(){
|
||||||
if (!addonsReady)
|
if (!(Engine.status == Engine.Ready && addonsReady))
|
||||||
return -1;
|
return -1;
|
||||||
var count = 0
|
var count = 0
|
||||||
for (var i = 0; i < Engine.addons.length; i++) {
|
for (var i = 0; i < Engine.addons.length; i++) {
|
||||||
@@ -40,16 +40,18 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
})
|
})
|
||||||
addonsReady = Qt.binding(function(){
|
addonsReady = Qt.binding(checkAddonsReady)
|
||||||
for (var i = 0; i < Engine.addons.length; i++) {
|
|
||||||
var addon = Engine.addons[i]
|
|
||||||
if (addon.status == Addon.Status.Busy)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
function updateAll() {
|
||||||
for (var i = 0; i < Engine.addons.length; i++) {
|
for (var i = 0; i < Engine.addons.length; i++) {
|
||||||
var addon = Engine.addons[i]
|
var addon = Engine.addons[i]
|
||||||
@@ -59,6 +61,8 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAvailableUpdatesChanged: {
|
onAvailableUpdatesChanged: {
|
||||||
|
if (availableUpdates == -1)
|
||||||
|
return;
|
||||||
if (availableUpdates > 0) {
|
if (availableUpdates > 0) {
|
||||||
tray.showMessage("Addons updates available", "You have " + availableUpdates + " addons waiting for update.", 1, 5000)
|
tray.showMessage("Addons updates available", "You have " + availableUpdates + " addons waiting for update.", 1, 5000)
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +85,7 @@ ApplicationWindow {
|
|||||||
icon.name: "view-refresh"
|
icon.name: "view-refresh"
|
||||||
onTriggered: Engine.scanForAddons()
|
onTriggered: Engine.scanForAddons()
|
||||||
shortcut: StandardKey.Refresh
|
shortcut: StandardKey.Refresh
|
||||||
enabled: Control.status == Control.Ready && addonsReady
|
enabled: Engine.status == Engine.Ready && addonsReady
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
id: addAction
|
id: addAction
|
||||||
@@ -94,7 +98,7 @@ ApplicationWindow {
|
|||||||
icon.name: "export-symbolic"
|
icon.name: "export-symbolic"
|
||||||
onTriggered: exportListDialog.visible = true
|
onTriggered: exportListDialog.visible = true
|
||||||
|
|
||||||
enabled: Control.status == Control.Ready && addonsReady
|
enabled: Engine.status == Engine.Ready && addonsReady
|
||||||
shortcut: StandardKey.SaveAs
|
shortcut: StandardKey.SaveAs
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
|
|||||||
Reference in New Issue
Block a user