Remove NewClosure
This commit is contained in:
parent
98d5e27a8c
commit
88874f0dcd
@ -1,7 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
set(SOURCES
|
||||
core/closure.cpp
|
||||
core/logging.cpp
|
||||
core/messagehandler.cpp
|
||||
core/messagereply.cpp
|
||||
@ -9,7 +8,6 @@ set(SOURCES
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
core/closure.h
|
||||
core/messagehandler.h
|
||||
core/messagereply.h
|
||||
core/workerpool.h
|
||||
|
@ -1,85 +0,0 @@
|
||||
/* This file is part of Strawberry.
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Strawberry is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Strawberry is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QGenericArgument>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
# include <QRandomGenerator>
|
||||
#endif
|
||||
|
||||
#include "closure.h"
|
||||
|
||||
#include "core/timeconstants.h"
|
||||
|
||||
namespace _detail {
|
||||
|
||||
ClosureBase::ClosureBase(ObjectHelper *helper) : helper_(helper) {}
|
||||
|
||||
ClosureBase::~ClosureBase() {}
|
||||
|
||||
CallbackClosure::CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback)
|
||||
: ClosureBase(new ObjectHelper(sender, signal, this)),
|
||||
callback_(callback) {
|
||||
}
|
||||
|
||||
void CallbackClosure::Invoke() {
|
||||
callback_();
|
||||
}
|
||||
|
||||
ObjectHelper* ClosureBase::helper() const {
|
||||
return helper_;
|
||||
}
|
||||
|
||||
ObjectHelper::ObjectHelper(QObject *sender, const char *signal, ClosureBase *closure) : closure_(closure) {
|
||||
|
||||
QObject::connect(sender, signal, SLOT(Invoked()));
|
||||
QObject::connect(sender, &QObject::destroyed, this, &ObjectHelper::deleteLater);
|
||||
|
||||
}
|
||||
|
||||
ObjectHelper::~ObjectHelper() {}
|
||||
|
||||
void ObjectHelper::Invoked() {
|
||||
closure_->Invoke();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void Unpack(QList<QGenericArgument>*) {}
|
||||
|
||||
} // namespace _detail
|
||||
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback) {
|
||||
return new _detail::CallbackClosure(sender, signal, callback);
|
||||
}
|
||||
|
||||
void DoAfter(QObject *receiver, const char *slot, int msec) {
|
||||
QTimer::singleShot(msec, receiver, slot);
|
||||
}
|
||||
|
||||
void DoInAMinuteOrSo(QObject *receiver, const char *slot) {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
int msec = (60 + QRandomGenerator::global()->bounded(1, 60)) * kMsecPerSec;
|
||||
#else
|
||||
int msec = (60 + (qrand() % 60)) * kMsecPerSec;
|
||||
#endif
|
||||
|
||||
DoAfter(receiver, slot, msec);
|
||||
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/* This file is part of Strawberry.
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Strawberry is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Strawberry is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLOSURE_H
|
||||
#define CLOSURE_H
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaMethod>
|
||||
#include <QSharedPointer>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/logging.h"
|
||||
|
||||
namespace _detail {
|
||||
|
||||
class ObjectHelper;
|
||||
|
||||
// Interface for ObjectHelper to call on signal emission.
|
||||
class ClosureBase {
|
||||
public:
|
||||
virtual ~ClosureBase();
|
||||
virtual void Invoke() = 0;
|
||||
|
||||
// Tests only.
|
||||
ObjectHelper *helper() const;
|
||||
|
||||
protected:
|
||||
explicit ClosureBase(ObjectHelper*);
|
||||
ObjectHelper *helper_;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(ClosureBase)
|
||||
|
||||
};
|
||||
|
||||
// QObject helper as templated QObjects do not work.
|
||||
// Connects to the given signal and invokes the closure when called.
|
||||
// Deletes itself and the Closure after being invoked.
|
||||
class ObjectHelper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ObjectHelper(QObject *sender, const char *signal, ClosureBase *closure);
|
||||
~ObjectHelper() override;
|
||||
|
||||
private slots:
|
||||
void Invoked();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ClosureBase> closure_;
|
||||
Q_DISABLE_COPY(ObjectHelper)
|
||||
|
||||
};
|
||||
|
||||
// Helpers for unpacking a variadic template list.
|
||||
|
||||
// Base case of no arguments.
|
||||
void Unpack(QList<QGenericArgument>*);
|
||||
|
||||
template <typename Arg>
|
||||
void Unpack(QList<QGenericArgument> *list, const Arg &arg) {
|
||||
list->append(Q_ARG(Arg, arg));
|
||||
}
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
void Unpack(QList<QGenericArgument> *list, const Head &head, const Tail&... tail) {
|
||||
Unpack(list, head);
|
||||
Unpack(list, tail...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
class Closure : public ClosureBase {
|
||||
public:
|
||||
Closure(
|
||||
QObject *sender,
|
||||
const char *signal,
|
||||
QObject *receiver,
|
||||
const char *slot,
|
||||
const Args&... args)
|
||||
: ClosureBase(new ObjectHelper(sender, signal, this)),
|
||||
// std::bind is the easiest way to store an argument list.
|
||||
function_(std::bind(&Closure<Args...>::Call, this, args...)),
|
||||
receiver_(receiver) {
|
||||
const QMetaObject *meta_receiver = receiver->metaObject();
|
||||
QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1);
|
||||
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
|
||||
Q_ASSERT(index != -1);
|
||||
slot_ = meta_receiver->method(index);
|
||||
QObject::connect(receiver_, &QObject::destroyed, helper_, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
void Invoke() override {
|
||||
function_();
|
||||
}
|
||||
|
||||
private:
|
||||
void Call(const Args&... args) {
|
||||
QList<QGenericArgument> arg_list;
|
||||
Unpack(&arg_list, args...);
|
||||
|
||||
slot_.invoke(
|
||||
receiver_,
|
||||
arg_list.size() > 0 ? arg_list[0] : QGenericArgument(),
|
||||
arg_list.size() > 1 ? arg_list[1] : QGenericArgument(),
|
||||
arg_list.size() > 2 ? arg_list[2] : QGenericArgument(),
|
||||
arg_list.size() > 3 ? arg_list[3] : QGenericArgument(),
|
||||
arg_list.size() > 4 ? arg_list[4] : QGenericArgument(),
|
||||
arg_list.size() > 5 ? arg_list[5] : QGenericArgument(),
|
||||
arg_list.size() > 6 ? arg_list[6] : QGenericArgument(),
|
||||
arg_list.size() > 7 ? arg_list[7] : QGenericArgument(),
|
||||
arg_list.size() > 8 ? arg_list[8] : QGenericArgument(),
|
||||
arg_list.size() > 9 ? arg_list[9] : QGenericArgument());
|
||||
}
|
||||
|
||||
std::function<void()> function_;
|
||||
QObject *receiver_;
|
||||
QMetaMethod slot_;
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
class SharedClosure : public Closure<Args...> {
|
||||
public:
|
||||
SharedClosure(
|
||||
QSharedPointer<T> sender,
|
||||
const char *signal,
|
||||
QObject *receiver,
|
||||
const char *slot,
|
||||
const Args&... args)
|
||||
: Closure<Args...>(
|
||||
sender.data(),
|
||||
signal,
|
||||
receiver,
|
||||
slot,
|
||||
args...),
|
||||
data_(sender) {
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<T> data_;
|
||||
};
|
||||
|
||||
class CallbackClosure : public ClosureBase {
|
||||
public:
|
||||
CallbackClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
||||
|
||||
void Invoke() override;
|
||||
|
||||
private:
|
||||
std::function<void()> callback_;
|
||||
};
|
||||
|
||||
} // namespace _detail
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||
return new _detail::Closure<Args...>(sender, signal, receiver, slot, args...);
|
||||
}
|
||||
|
||||
// QSharedPointer variant
|
||||
template <typename T, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QSharedPointer<T> sender, const char *signal, QObject *receiver, const char *slot, const Args&... args) {
|
||||
return new _detail::SharedClosure<T, Args...>(sender, signal, receiver, slot, args...);
|
||||
}
|
||||
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void()> callback);
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, std::function<void(Args...)> callback, const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, args...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, void (*callback)(Args...), const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, args...));
|
||||
}
|
||||
|
||||
template <typename T, typename Unused, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QObject *sender, const char *signal, T *receiver, Unused (T::*callback)(Args...), const Args&... args) {
|
||||
return NewClosure(sender, signal, std::bind(callback, receiver, args...));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QFuture<T> future, QObject *receiver, const char *slot, const Args&... args) {
|
||||
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, &QFutureWatcher<T>::deleteLater);
|
||||
return NewClosure(watcher, SIGNAL(finished()), receiver, slot, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename F, typename... Args>
|
||||
_detail::ClosureBase *NewClosure(QFuture<T> future, const F &callback, const Args&... args) {
|
||||
QFutureWatcher<T> *watcher = new QFutureWatcher<T>;
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, &QFutureWatcher<T>::deleteLater);
|
||||
return NewClosure(watcher, SIGNAL(finished()), callback, args...);
|
||||
}
|
||||
|
||||
void DoAfter(QObject *receiver, const char *slot, int msec);
|
||||
void DoAfter(std::function<void()> callback, std::chrono::milliseconds msec);
|
||||
void DoInAMinuteOrSo(QObject *receiver, const char *slot);
|
||||
|
||||
template <typename R, typename P>
|
||||
void DoAfter(std::function<void()> callback, std::chrono::duration<R, P> duration) {
|
||||
QTimer *timer = new QTimer;
|
||||
timer->setSingleShot(true);
|
||||
QObject::connect(timer, &QTimer::timeout, callback);
|
||||
QObject::connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);
|
||||
std::chrono::milliseconds msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
|
||||
timer->start(msec.count());
|
||||
}
|
||||
|
||||
#endif // CLOSURE_H
|
@ -31,6 +31,7 @@
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QDataStream>
|
||||
#include <QMimeData>
|
||||
#include <QIODevice>
|
||||
@ -53,7 +54,6 @@
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/database.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
@ -915,18 +915,22 @@ void CollectionModel::ResetAsync() {
|
||||
#else
|
||||
QFuture<CollectionModel::QueryResult> future = QtConcurrent::run(this, &CollectionModel::RunQuery, root_);
|
||||
#endif
|
||||
NewClosure(future, this, SLOT(ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResult>)), future);
|
||||
QFutureWatcher<CollectionModel::QueryResult> *watcher = new QFutureWatcher<CollectionModel::QueryResult>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<CollectionModel::QueryResult>::finished, this, &CollectionModel::ResetAsyncQueryFinished);
|
||||
|
||||
}
|
||||
|
||||
void CollectionModel::ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResult> future) {
|
||||
void CollectionModel::ResetAsyncQueryFinished() {
|
||||
|
||||
QFutureWatcher<CollectionModel::QueryResult> *watcher = static_cast<QFutureWatcher<CollectionModel::QueryResult>*>(sender());
|
||||
const struct QueryResult result = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
if (QThread::currentThread() != thread() && QThread::currentThread() != backend_->thread()) {
|
||||
backend_->Close();
|
||||
}
|
||||
|
||||
const struct QueryResult result = future.result();
|
||||
|
||||
BeginReset();
|
||||
root_->lazy_loaded = true;
|
||||
|
||||
|
@ -228,7 +228,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
||||
void ClearDiskCache();
|
||||
|
||||
// Called after ResetAsync
|
||||
void ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResult> future);
|
||||
void ResetAsyncQueryFinished();
|
||||
|
||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QDialog>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMap>
|
||||
#include <QSize>
|
||||
#include <QByteArray>
|
||||
@ -47,7 +48,6 @@
|
||||
#include <QStackedWidget>
|
||||
#include <QTableWidget>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/musicstorage.h"
|
||||
#include "widgets/freespacebar.h"
|
||||
@ -247,7 +247,9 @@ void DeviceProperties::UpdateFormats() {
|
||||
#else
|
||||
QFuture<bool> future = QtConcurrent::run(std::bind(&ConnectedDevice::GetSupportedFiletypes, device, &supported_formats_));
|
||||
#endif
|
||||
NewClosure(future, this, SLOT(UpdateFormatsFinished(QFuture<bool>)), future);
|
||||
QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<bool>::finished, this, &DeviceProperties::UpdateFormatsFinished);
|
||||
|
||||
ui_->formats_stack->setCurrentWidget(ui_->formats_page_loading);
|
||||
updating_formats_ = true;
|
||||
@ -283,11 +285,15 @@ void DeviceProperties::accept() {
|
||||
|
||||
void DeviceProperties::OpenDevice() { manager_->Connect(index_); }
|
||||
|
||||
void DeviceProperties::UpdateFormatsFinished(QFuture<bool> future) {
|
||||
void DeviceProperties::UpdateFormatsFinished() {
|
||||
|
||||
QFutureWatcher<bool> *watcher = static_cast<QFutureWatcher<bool>*>(sender());
|
||||
bool result = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
updating_formats_ = false;
|
||||
|
||||
if (!future.result()) {
|
||||
if (!result) {
|
||||
supported_formats_.clear();
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class DeviceProperties : public QDialog {
|
||||
private slots:
|
||||
void ModelChanged();
|
||||
void OpenDevice();
|
||||
void UpdateFormatsFinished(QFuture<bool> future);
|
||||
void UpdateFormatsFinished();
|
||||
|
||||
private:
|
||||
Ui_DeviceProperties *ui_;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QtGlobal>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
@ -69,7 +70,6 @@
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
@ -297,15 +297,24 @@ void EditTagDialog::SetSongs(const SongList &s, const PlaylistItemList &items) {
|
||||
#else
|
||||
QFuture<QList<Data>> future = QtConcurrent::run(this, &EditTagDialog::LoadData, s);
|
||||
#endif
|
||||
NewClosure(future, this, SLOT(SetSongsFinished(QFuture<QList<EditTagDialog::Data>>)), future);
|
||||
QFutureWatcher<QList<Data>> *watcher = new QFutureWatcher<QList<Data>>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<QList<Data>>::finished, this, &EditTagDialog::SetSongsFinished);
|
||||
|
||||
}
|
||||
|
||||
void EditTagDialog::SetSongsFinished(QFuture<QList<Data>> future) {
|
||||
void EditTagDialog::SetSongsFinished() {
|
||||
|
||||
if (!SetLoading(QString())) return;
|
||||
QFutureWatcher<QList<Data>> *watcher = static_cast<QFutureWatcher<QList<Data>>*>(sender());
|
||||
QList<Data> result_data = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
if (!SetLoading(QString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = result_data;
|
||||
|
||||
data_ = future.result();
|
||||
if (data_.count() == 0) {
|
||||
// If there were no valid songs, disable everything
|
||||
ui_->song_list->setEnabled(false);
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <QObject>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDialog>
|
||||
#include <QFuture>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
@ -101,7 +100,7 @@ class EditTagDialog : public QDialog {
|
||||
};
|
||||
|
||||
private slots:
|
||||
void SetSongsFinished(QFuture<QList<EditTagDialog::Data>> future);
|
||||
void SetSongsFinished();
|
||||
void AcceptFinished();
|
||||
|
||||
void SelectionChanged();
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QTimer>
|
||||
#include <QList>
|
||||
#include <QByteArray>
|
||||
@ -50,7 +51,6 @@
|
||||
#include <QTimerEvent>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/timeconstants.h"
|
||||
@ -242,7 +242,13 @@ bool GstEngine::Play(const quint64 offset_nanosec) {
|
||||
if (!current_pipeline_ || current_pipeline_->is_buffering()) return false;
|
||||
|
||||
QFuture<GstStateChangeReturn> future = current_pipeline_->SetState(GST_STATE_PLAYING);
|
||||
NewClosure(future, this, SLOT(PlayDone(QFuture<GstStateChangeReturn>, quint64, int)), future, offset_nanosec, current_pipeline_->id());
|
||||
QFutureWatcher<GstStateChangeReturn> *watcher = new QFutureWatcher<GstStateChangeReturn>();
|
||||
watcher->setFuture(future);
|
||||
int pipeline_id = current_pipeline_->id();
|
||||
QObject::connect(watcher, &QFutureWatcher<GstStateChangeReturn>::finished, this, [this, watcher, offset_nanosec, pipeline_id]() {
|
||||
PlayDone(watcher->result(), offset_nanosec, pipeline_id);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
if (is_fading_out_to_pause_) {
|
||||
current_pipeline_->SetState(GST_STATE_PAUSED);
|
||||
@ -634,9 +640,7 @@ void GstEngine::SeekNow() {
|
||||
}
|
||||
}
|
||||
|
||||
void GstEngine::PlayDone(QFuture<GstStateChangeReturn> future, const quint64 offset_nanosec, const int pipeline_id) {
|
||||
|
||||
GstStateChangeReturn ret = future.result();
|
||||
void GstEngine::PlayDone(const GstStateChangeReturn ret, const quint64 offset_nanosec, const int pipeline_id) {
|
||||
|
||||
if (!current_pipeline_ || pipeline_id != current_pipeline_->id()) {
|
||||
return;
|
||||
|
@ -120,7 +120,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
||||
void FadeoutFinished();
|
||||
void FadeoutPauseFinished();
|
||||
void SeekNow();
|
||||
void PlayDone(QFuture<GstStateChangeReturn> future, const quint64, const int);
|
||||
void PlayDone(const GstStateChangeReturn ret, const quint64, const int);
|
||||
|
||||
void BufferingStarted();
|
||||
void BufferingProgress(int percent);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <QApplication>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSettings>
|
||||
@ -34,7 +35,6 @@
|
||||
#include <QRect>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlist/playlistview.h"
|
||||
|
||||
@ -212,11 +212,16 @@ void MoodbarItemDelegate::StartLoadingColors(const QUrl &url, const QByteArray &
|
||||
data->state_ = Data::State_LoadingColors;
|
||||
|
||||
QFuture<ColorVector> future = QtConcurrent::run(MoodbarRenderer::Colors, bytes, style_, qApp->palette());
|
||||
NewClosure(future, this, SLOT(ColorsLoaded(QUrl, QFuture<ColorVector>)), url, future);
|
||||
QFutureWatcher<ColorVector> *watcher = new QFutureWatcher<ColorVector>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<ColorVector>::finished, [this, watcher, url]() {
|
||||
ColorsLoaded(url, watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void MoodbarItemDelegate::ColorsLoaded(const QUrl &url, QFuture<ColorVector> future) {
|
||||
void MoodbarItemDelegate::ColorsLoaded(const QUrl &url, const ColorVector &colors) {
|
||||
|
||||
Data *data = data_[url];
|
||||
if (!data) {
|
||||
@ -227,7 +232,7 @@ void MoodbarItemDelegate::ColorsLoaded(const QUrl &url, QFuture<ColorVector> fut
|
||||
return;
|
||||
}
|
||||
|
||||
data->colors_ = future.result();
|
||||
data->colors_ = colors;
|
||||
|
||||
// Load the image next.
|
||||
StartLoadingImage(url, data);
|
||||
@ -239,11 +244,16 @@ void MoodbarItemDelegate::StartLoadingImage(const QUrl &url, Data *data) {
|
||||
data->state_ = Data::State_LoadingImage;
|
||||
|
||||
QFuture<QImage> future = QtConcurrent::run(MoodbarRenderer::RenderToImage, data->colors_, data->desired_size_);
|
||||
NewClosure(future, this, SLOT(ImageLoaded(QUrl, QFuture<QImage>)), url, future);
|
||||
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<QImage>::finished, this, [this, watcher, url]() {
|
||||
ImageLoaded(url, watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void MoodbarItemDelegate::ImageLoaded(const QUrl &url, QFuture<QImage> future) {
|
||||
void MoodbarItemDelegate::ImageLoaded(const QUrl &url, const QImage &image) {
|
||||
|
||||
Data *data = data_[url];
|
||||
if (!data) {
|
||||
@ -254,8 +264,6 @@ void MoodbarItemDelegate::ImageLoaded(const QUrl &url, QFuture<QImage> future) {
|
||||
return;
|
||||
}
|
||||
|
||||
QImage image(future.result());
|
||||
|
||||
// If the desired size changed then don't even bother converting the image
|
||||
// to a pixmap, just reload it at the new size.
|
||||
if (!image.isNull() && data->desired_size_ != image.size()) {
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <QObject>
|
||||
#include <QItemDelegate>
|
||||
#include <QCache>
|
||||
#include <QFuture>
|
||||
#include <QSet>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
@ -52,8 +51,8 @@ class MoodbarItemDelegate : public QItemDelegate {
|
||||
void ReloadSettings();
|
||||
|
||||
void DataLoaded(const QUrl &url, MoodbarPipeline *pipeline);
|
||||
void ColorsLoaded(const QUrl &url, QFuture<ColorVector> future);
|
||||
void ImageLoaded(const QUrl &url, QFuture<QImage> future);
|
||||
void ColorsLoaded(const QUrl &url, const ColorVector &colors);
|
||||
void ImageLoaded(const QUrl &url, const QImage &image);
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <QtGlobal>
|
||||
#include <QGuiApplication>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDialog>
|
||||
#include <QScreen>
|
||||
@ -56,7 +58,6 @@
|
||||
#include <QCloseEvent>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/musicstorage.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
@ -394,7 +395,12 @@ bool OrganizeDialog::SetFilenames(const QStringList &filenames) {
|
||||
#else
|
||||
songs_future_ = QtConcurrent::run(this, &OrganizeDialog::LoadSongsBlocking, filenames);
|
||||
#endif
|
||||
NewClosure(songs_future_, [=]() { SetSongs(songs_future_.result()); });
|
||||
QFutureWatcher<SongList> *watcher = new QFutureWatcher<SongList>();
|
||||
watcher->setFuture(songs_future_);
|
||||
QObject::connect(watcher, &QFutureWatcher<SongList>::finished, this, [=]() {
|
||||
SetSongs(watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
SetLoadingSongs(true);
|
||||
return true;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QIODevice>
|
||||
#include <QDataStream>
|
||||
#include <QBuffer>
|
||||
@ -59,7 +60,6 @@
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
@ -406,7 +406,12 @@ void Playlist::SongSaveComplete(TagReaderReply *reply, const QPersistentModelInd
|
||||
PlaylistItemPtr item = item_at(idx.row());
|
||||
if (item) {
|
||||
QFuture<void> future = item->BackgroundReload();
|
||||
NewClosure(future, this, SLOT(ItemReloadComplete(QPersistentModelIndex)), idx);
|
||||
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, this, [this, watcher, idx]() {
|
||||
ItemReloadComplete(idx);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1407,20 +1412,24 @@ void Playlist::Restore() {
|
||||
|
||||
cancel_restore_ = false;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QFuture<QList<PlaylistItemPtr>> future = QtConcurrent::run(&PlaylistBackend::GetPlaylistItems, backend_, id_);
|
||||
QFuture<PlaylistItemList> future = QtConcurrent::run(&PlaylistBackend::GetPlaylistItems, backend_, id_);
|
||||
#else
|
||||
QFuture<QList<PlaylistItemPtr>> future = QtConcurrent::run(backend_, &PlaylistBackend::GetPlaylistItems, id_);
|
||||
QFuture<PlaylistItemList> future = QtConcurrent::run(backend_, &PlaylistBackend::GetPlaylistItems, id_);
|
||||
#endif
|
||||
NewClosure(future, this, SLOT(ItemsLoaded(QFuture<PlaylistItemList>)), future);
|
||||
QFutureWatcher<PlaylistItemList> *watcher = new QFutureWatcher<PlaylistItemList>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<PlaylistItemList>::finished, this, &Playlist::ItemsLoaded);
|
||||
|
||||
}
|
||||
|
||||
void Playlist::ItemsLoaded(QFuture<PlaylistItemList> future) {
|
||||
void Playlist::ItemsLoaded() {
|
||||
|
||||
QFutureWatcher<PlaylistItemList> *watcher = static_cast<QFutureWatcher<PlaylistItemList>*>(sender());
|
||||
PlaylistItemList items = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
if (cancel_restore_) return;
|
||||
|
||||
PlaylistItemList items = future.result();
|
||||
|
||||
// Backend returns empty elements for collection items which it couldn't match (because they got deleted); we don't need those
|
||||
QMutableListIterator<PlaylistItemPtr> it(items);
|
||||
while (it.hasNext()) {
|
||||
|
@ -377,7 +377,7 @@ class Playlist : public QAbstractListModel {
|
||||
void QueueLayoutChanged();
|
||||
void SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx);
|
||||
void ItemReloadComplete(const QPersistentModelIndex &idx);
|
||||
void ItemsLoaded(QFuture<PlaylistItemList> future);
|
||||
void ItemsLoaded();
|
||||
void SongInsertVetoListenerDestroyed();
|
||||
|
||||
private:
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <QThread>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QCompleter>
|
||||
@ -62,7 +63,6 @@
|
||||
#include <QtEvents>
|
||||
#include <QLinearGradient>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
@ -405,7 +405,9 @@ static TagCompletionModel *InitCompletionModel(CollectionBackend *backend, Playl
|
||||
TagCompleter::TagCompleter(CollectionBackend *backend, Playlist::Column column, QLineEdit *editor) : QCompleter(editor), editor_(editor) {
|
||||
|
||||
QFuture<TagCompletionModel*> future = QtConcurrent::run(&InitCompletionModel, backend, column);
|
||||
NewClosure(future, this, SLOT(ModelReady(QFuture<TagCompletionModel*>)), future);
|
||||
QFutureWatcher<TagCompletionModel*> *watcher = new QFutureWatcher<TagCompletionModel*>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<TagCompletionModel*>::finished, this, &TagCompleter::ModelReady);
|
||||
|
||||
}
|
||||
|
||||
@ -413,9 +415,11 @@ TagCompleter::~TagCompleter() {
|
||||
delete model();
|
||||
}
|
||||
|
||||
void TagCompleter::ModelReady(QFuture<TagCompletionModel*> future) {
|
||||
void TagCompleter::ModelReady() {
|
||||
|
||||
TagCompletionModel *model = future.result();
|
||||
QFutureWatcher<TagCompletionModel*> *watcher = static_cast<QFutureWatcher<TagCompletionModel*>*>(sender());
|
||||
TagCompletionModel *model = watcher->result();
|
||||
watcher->deleteLater();
|
||||
setModel(model);
|
||||
setCaseSensitivity(Qt::CaseInsensitive);
|
||||
editor_->setCompleter(this);
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QTreeView>
|
||||
#include <QFuture>
|
||||
#include <QCompleter>
|
||||
#include <QLocale>
|
||||
#include <QVariant>
|
||||
@ -151,7 +150,7 @@ class TagCompleter : public QCompleter {
|
||||
~TagCompleter() override;
|
||||
|
||||
private slots:
|
||||
void ModelReady(QFuture<TagCompletionModel*> future);
|
||||
void ModelReady();
|
||||
|
||||
private:
|
||||
QLineEdit *editor_;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QDialog>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
@ -45,7 +46,6 @@
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/utilities.h"
|
||||
@ -220,18 +220,23 @@ void PlaylistManager::Save(const int id, const QString &filename, const Playlist
|
||||
else {
|
||||
// Playlist is not in the playlist manager: probably save action was triggered from the left side bar and the playlist isn't loaded.
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QFuture<QList<Song>> future = QtConcurrent::run(&PlaylistBackend::GetPlaylistSongs, playlist_backend_, id);
|
||||
QFuture<SongList> future = QtConcurrent::run(&PlaylistBackend::GetPlaylistSongs, playlist_backend_, id);
|
||||
#else
|
||||
QFuture<QList<Song>> future = QtConcurrent::run(playlist_backend_, &PlaylistBackend::GetPlaylistSongs, id);
|
||||
QFuture<SongList> future = QtConcurrent::run(playlist_backend_, &PlaylistBackend::GetPlaylistSongs, id);
|
||||
#endif
|
||||
NewClosure(future, this, SLOT(ItemsLoadedForSavePlaylist(QFuture<SongList>, QString, Playlist::Path)), future, filename, path_type);
|
||||
QFutureWatcher<SongList> *watcher = new QFutureWatcher<SongList>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<SongList>::finished, this, [this, watcher, filename, path_type]() {
|
||||
ItemsLoadedForSavePlaylist(watcher->result(), filename, path_type);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PlaylistManager::ItemsLoadedForSavePlaylist(QFuture<SongList> future, const QString &filename, const Playlist::Path path_type) {
|
||||
void PlaylistManager::ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const Playlist::Path path_type) {
|
||||
|
||||
parser_->Save(future.result(), filename, path_type);
|
||||
parser_->Save(songs, filename, path_type);
|
||||
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ class PlaylistManager : public PlaylistManagerInterface {
|
||||
void OneOfPlaylistsChanged();
|
||||
void UpdateSummaryText();
|
||||
void SongsDiscovered(const SongList& songs);
|
||||
void ItemsLoadedForSavePlaylist(QFuture<SongList> future, const QString& filename, const Playlist::Path path_type);
|
||||
void ItemsLoadedForSavePlaylist(const SongList &songs, const QString& filename, const Playlist::Path path_type);
|
||||
void PlaylistLoaded();
|
||||
|
||||
private:
|
||||
|
@ -757,7 +757,7 @@ void QobuzRequest::FlushAlbumSongsRequests() {
|
||||
if (request.offset > 0) params << Param("offset", QString::number(request.offset));
|
||||
QNetworkReply *reply = CreateRequest(QString("album/get"), params);
|
||||
replies_ << reply;
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply, request] { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album); });
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album); });
|
||||
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,9 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/taskmanager.h"
|
||||
|
||||
#include "playlist/playlist.h"
|
||||
@ -67,13 +68,17 @@ void PlaylistGeneratorInserter::Load(Playlist *destination, const int row, const
|
||||
QObject::connect(generator.get(), &PlaylistGenerator::Error, this, &PlaylistGeneratorInserter::Error);
|
||||
|
||||
QFuture<PlaylistItemList> future = QtConcurrent::run(PlaylistGeneratorInserter::Generate, generator, dynamic_count);
|
||||
NewClosure(future, this, SLOT(Finished(QFuture<PlaylistItemList>)), future);
|
||||
QFutureWatcher<PlaylistItemList> *watcher = new QFutureWatcher<PlaylistItemList>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<PlaylistItemList>::finished, this, &PlaylistGeneratorInserter::Finished);
|
||||
|
||||
}
|
||||
|
||||
void PlaylistGeneratorInserter::Finished(QFuture<PlaylistItemList> future) {
|
||||
void PlaylistGeneratorInserter::Finished() {
|
||||
|
||||
PlaylistItemList items = future.result();
|
||||
QFutureWatcher<PlaylistItemList> *watcher = static_cast<QFutureWatcher<PlaylistItemList>*>(sender());
|
||||
PlaylistItemList items = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
if (items.isEmpty()) {
|
||||
if (is_dynamic_) {
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QString>
|
||||
|
||||
#include "playlist/playlist.h"
|
||||
@ -52,7 +51,7 @@ class PlaylistGeneratorInserter : public QObject {
|
||||
void PlayRequested(QModelIndex idx, Playlist::AutoScroll autoscroll);
|
||||
|
||||
private slots:
|
||||
void Finished(QFuture<PlaylistItemList> future);
|
||||
void Finished();
|
||||
|
||||
private:
|
||||
TaskManager *task_manager_;
|
||||
|
@ -26,11 +26,12 @@
|
||||
#include <QAbstractItemView>
|
||||
#include <QString>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include "smartplaylistsearchpreview.h"
|
||||
#include "ui_smartplaylistsearchpreview.h"
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlistquerygenerator.h"
|
||||
|
||||
@ -115,11 +116,17 @@ void SmartPlaylistSearchPreview::RunSearch(const SmartPlaylistSearch &search) {
|
||||
ui_->busy_container->show();
|
||||
ui_->count_label->hide();
|
||||
QFuture<PlaylistItemList> future = QtConcurrent::run(DoRunSearch, generator_);
|
||||
NewClosure(future, this, SLOT(SearchFinished(QFuture<PlaylistItemList>)), future);
|
||||
QFutureWatcher<PlaylistItemList> *watcher = new QFutureWatcher<PlaylistItemList>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<PlaylistItemList>::finished, this, &SmartPlaylistSearchPreview::SearchFinished);
|
||||
|
||||
}
|
||||
|
||||
void SmartPlaylistSearchPreview::SearchFinished(QFuture<PlaylistItemList> future) {
|
||||
void SmartPlaylistSearchPreview::SearchFinished() {
|
||||
|
||||
QFutureWatcher<PlaylistItemList> *watcher = static_cast<QFutureWatcher<PlaylistItemList>*>(sender());
|
||||
PlaylistItemList all_items = watcher->result();
|
||||
watcher->deleteLater();
|
||||
|
||||
last_search_ = std::dynamic_pointer_cast<PlaylistQueryGenerator>(generator_)->search();
|
||||
generator_.reset();
|
||||
@ -132,7 +139,6 @@ void SmartPlaylistSearchPreview::SearchFinished(QFuture<PlaylistItemList> future
|
||||
return;
|
||||
}
|
||||
|
||||
PlaylistItemList all_items = future.result();
|
||||
PlaylistItemList displayed_items = all_items.mid(0, PlaylistGenerator::kDefaultLimit);
|
||||
|
||||
model_->Clear();
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFuture>
|
||||
#include <QList>
|
||||
|
||||
#include "smartplaylistsearch.h"
|
||||
@ -56,7 +55,7 @@ class SmartPlaylistSearchPreview : public QWidget {
|
||||
void RunSearch(const SmartPlaylistSearch &search);
|
||||
|
||||
private slots:
|
||||
void SearchFinished(QFuture<PlaylistItemList> future);
|
||||
void SearchFinished();
|
||||
|
||||
private:
|
||||
Ui_SmartPlaylistSearchPreview *ui_;
|
||||
|
@ -152,7 +152,6 @@ endmacro(add_test_file)
|
||||
|
||||
add_test_file(src/utilities_test.cpp false)
|
||||
add_test_file(src/concurrentrun_test.cpp false)
|
||||
add_test_file(src/closure_test.cpp false)
|
||||
add_test_file(src/mergedproxymodel_test.cpp false)
|
||||
add_test_file(src/sqlite_test.cpp false)
|
||||
add_test_file(src/tagreader_test.cpp false)
|
||||
|
@ -1,149 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
#include <QSignalSpy>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
TEST(ClosureTest, ClosureInvokesReceiver) {
|
||||
|
||||
TestQObject sender;
|
||||
TestQObject receiver;
|
||||
_detail::ClosureBase* closure = NewClosure(&sender, SIGNAL(Emitted()), &receiver, SLOT(Invoke()));
|
||||
Q_UNUSED(closure);
|
||||
EXPECT_EQ(0, receiver.invoked());
|
||||
sender.Emit();
|
||||
EXPECT_EQ(1, receiver.invoked());
|
||||
|
||||
}
|
||||
|
||||
TEST(ClosureTest, ClosureDeletesSelf) {
|
||||
|
||||
TestQObject sender;
|
||||
TestQObject receiver;
|
||||
_detail::ClosureBase* closure = NewClosure(&sender, SIGNAL(Emitted()), &receiver, SLOT(Invoke()));
|
||||
_detail::ObjectHelper* helper = closure->helper();
|
||||
QSignalSpy spy(helper, SIGNAL(destroyed()));
|
||||
EXPECT_EQ(0, receiver.invoked());
|
||||
sender.Emit();
|
||||
EXPECT_EQ(1, receiver.invoked());
|
||||
|
||||
EXPECT_EQ(0, spy.count());
|
||||
QEventLoop loop;
|
||||
QObject::connect(helper, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
EXPECT_EQ(1, spy.count());
|
||||
|
||||
}
|
||||
|
||||
TEST(ClosureTest, ClosureDoesNotCrashWithSharedPointerSender) {
|
||||
|
||||
TestQObject receiver;
|
||||
TestQObject* sender;
|
||||
std::unique_ptr<QSignalSpy> spy;
|
||||
QPointer<_detail::ObjectHelper> closure;
|
||||
{
|
||||
QSharedPointer<TestQObject> sender_shared(new TestQObject);
|
||||
sender = sender_shared.data();
|
||||
closure = QPointer<_detail::ObjectHelper>(NewClosure(sender_shared, SIGNAL(Emitted()), &receiver, SLOT(Invoke()))->helper());
|
||||
spy.reset(new QSignalSpy(sender, SIGNAL(destroyed())));
|
||||
}
|
||||
ASSERT_EQ(0, receiver.invoked());
|
||||
sender->Emit();
|
||||
ASSERT_EQ(1, receiver.invoked());
|
||||
|
||||
ASSERT_EQ(0, spy->count());
|
||||
QEventLoop loop;
|
||||
QObject::connect(sender, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
ASSERT_EQ(1, spy->count());
|
||||
EXPECT_TRUE(closure.isNull());
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void Foo(bool* called, int question, int* answer) {
|
||||
|
||||
*called = true;
|
||||
*answer = question;
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ClosureTest, ClosureWorksWithFunctionPointers) {
|
||||
|
||||
TestQObject sender;
|
||||
bool called = false;
|
||||
int question = 42;
|
||||
int answer = 0;
|
||||
NewClosure(&sender, SIGNAL(Emitted()), &Foo, &called, question, &answer);
|
||||
EXPECT_FALSE(called);
|
||||
sender.Emit();
|
||||
EXPECT_TRUE(called);
|
||||
EXPECT_EQ(question, answer);
|
||||
|
||||
}
|
||||
|
||||
TEST(ClosureTest, ClosureWorksWithStandardFunctions) {
|
||||
|
||||
TestQObject sender;
|
||||
bool called = false;
|
||||
int question = 42;
|
||||
int answer = 0;
|
||||
std::function<void(bool*,int,int*)> callback(&Foo);
|
||||
NewClosure(&sender, SIGNAL(Emitted()), callback, &called, question, &answer);
|
||||
EXPECT_FALSE(called);
|
||||
sender.Emit();
|
||||
EXPECT_TRUE(called);
|
||||
EXPECT_EQ(question, answer);
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Bar {
|
||||
public:
|
||||
explicit Bar(int a) : foo_(a) {}
|
||||
bool Foo(int* answer) {
|
||||
*answer = foo_;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int foo_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(ClosureTest, ClosureWorksWithMemberFunctionPointers) {
|
||||
|
||||
TestQObject sender;
|
||||
Bar receiver(42);
|
||||
int q = 1;
|
||||
NewClosure(&sender, SIGNAL(Emitted()), &receiver, &Bar::Foo, &q);
|
||||
EXPECT_EQ(1, q);
|
||||
sender.Emit();
|
||||
EXPECT_EQ(42, q);
|
||||
|
||||
}
|
||||
|
||||
TEST(ClosureTest, ClosureCallsLambda) {
|
||||
|
||||
TestQObject sender;
|
||||
bool called = false;
|
||||
NewClosure(&sender, SIGNAL(Emitted()), [&called] () { called = true; });
|
||||
EXPECT_FALSE(called);
|
||||
sender.Emit();
|
||||
EXPECT_TRUE(called);
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user