Port Closure to variadic templates.
This commit is contained in:
parent
d6b84558f6
commit
8171192df5
|
@ -19,80 +19,47 @@
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "core/timeconstants.h"
|
#include "core/timeconstants.h"
|
||||||
|
|
||||||
namespace _detail {
|
namespace _detail {
|
||||||
|
|
||||||
Closure::Closure(QObject* sender,
|
ClosureBase::ClosureBase(ObjectHelper* helper)
|
||||||
const char* signal,
|
: helper_(helper) {
|
||||||
QObject* receiver,
|
|
||||||
const char* slot,
|
|
||||||
const ClosureArgumentWrapper* val0,
|
|
||||||
const ClosureArgumentWrapper* val1,
|
|
||||||
const ClosureArgumentWrapper* val2,
|
|
||||||
const ClosureArgumentWrapper* val3)
|
|
||||||
: QObject(receiver),
|
|
||||||
callback_(NULL),
|
|
||||||
val0_(val0),
|
|
||||||
val1_(val1),
|
|
||||||
val2_(val2),
|
|
||||||
val3_(val3) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
Connect(sender, signal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Closure::Closure(QObject* sender,
|
ClosureBase::~ClosureBase() {
|
||||||
const char* signal,
|
|
||||||
std::tr1::function<void()> callback)
|
|
||||||
: callback_(callback) {
|
|
||||||
Connect(sender, signal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Closure::~Closure() {
|
ObjectHelper* ClosureBase::helper() const {
|
||||||
|
return helper_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Closure::Connect(QObject* sender, const char* signal) {
|
ObjectHelper::ObjectHelper(
|
||||||
bool success = connect(sender, signal, SLOT(Invoked()));
|
QObject* sender,
|
||||||
Q_ASSERT(success);
|
const char* signal,
|
||||||
success = connect(sender, SIGNAL(destroyed()), SLOT(Cleanup()));
|
ClosureBase* closure)
|
||||||
Q_ASSERT(success);
|
: closure_(closure) {
|
||||||
Q_UNUSED(success);
|
connect(sender, signal, SLOT(Invoked()));
|
||||||
|
connect(sender, SIGNAL(destroyed()), SLOT(deleteLater()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Closure::Invoked() {
|
void ObjectHelper::Invoked() {
|
||||||
if (callback_) {
|
closure_->Invoke();
|
||||||
callback_();
|
|
||||||
} else {
|
|
||||||
slot_.invoke(
|
|
||||||
parent(),
|
|
||||||
val0_ ? val0_->arg() : QGenericArgument(),
|
|
||||||
val1_ ? val1_->arg() : QGenericArgument(),
|
|
||||||
val2_ ? val2_->arg() : QGenericArgument(),
|
|
||||||
val3_ ? val3_->arg() : QGenericArgument());
|
|
||||||
}
|
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Closure::Cleanup() {
|
template<>
|
||||||
disconnect();
|
void Arg<boost::tuples::tuple<>>(
|
||||||
deleteLater();
|
const boost::tuples::tuple<>&,
|
||||||
}
|
QList<QGenericArgument>* list) {}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Arg<boost::tuples::null_type>(
|
||||||
|
const boost::tuples::null_type&,
|
||||||
|
QList<QGenericArgument>* list) {}
|
||||||
|
|
||||||
} // namespace _detail
|
} // namespace _detail
|
||||||
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QObject* sender, const char* signal,
|
|
||||||
QObject* receiver, const char* slot) {
|
|
||||||
return new _detail::Closure(sender, signal, receiver, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoAfter(QObject* receiver, const char* slot, int msec) {
|
void DoAfter(QObject* receiver, const char* slot, int msec) {
|
||||||
QTimer::singleShot(msec, receiver, slot);
|
QTimer::singleShot(msec, receiver, slot);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,211 +18,169 @@
|
||||||
#ifndef CLOSURE_H
|
#ifndef CLOSURE_H
|
||||||
#define CLOSURE_H
|
#define CLOSURE_H
|
||||||
|
|
||||||
#include <tr1/functional>
|
|
||||||
|
|
||||||
#include <QMetaMethod>
|
#include <QMetaMethod>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include "core/logging.h"
|
|
||||||
|
|
||||||
namespace _detail {
|
namespace _detail {
|
||||||
|
|
||||||
class ClosureArgumentWrapper {
|
class ObjectHelper;
|
||||||
public:
|
|
||||||
virtual ~ClosureArgumentWrapper() {}
|
|
||||||
|
|
||||||
virtual QGenericArgument arg() const = 0;
|
// Interface for ObjectHelper to call on signal emission.
|
||||||
|
class ClosureBase : boost::noncopyable {
|
||||||
|
public:
|
||||||
|
virtual ~ClosureBase();
|
||||||
|
virtual void Invoke() = 0;
|
||||||
|
|
||||||
|
// Tests only.
|
||||||
|
ObjectHelper* helper() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit ClosureBase(ObjectHelper*);
|
||||||
|
ObjectHelper* helper_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
// QObject helper as templated QObjects do not work.
|
||||||
class ClosureArgument : public ClosureArgumentWrapper {
|
// Connects to the given signal and invokes the closure when called.
|
||||||
public:
|
// Deletes itself and the Closure after being invoked.
|
||||||
explicit ClosureArgument(const T& data) : data_(data) {}
|
class ObjectHelper : public QObject {
|
||||||
|
|
||||||
virtual QGenericArgument arg() const {
|
|
||||||
return Q_ARG(T, data_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T data_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Closure : public QObject, boost::noncopyable {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Closure(QObject* sender, const char* signal,
|
ObjectHelper(
|
||||||
QObject* receiver, const char* slot,
|
QObject* parent,
|
||||||
const ClosureArgumentWrapper* val0 = 0,
|
const char* signal,
|
||||||
const ClosureArgumentWrapper* val1 = 0,
|
ClosureBase* closure);
|
||||||
const ClosureArgumentWrapper* val2 = 0,
|
|
||||||
const ClosureArgumentWrapper* val3 = 0);
|
|
||||||
|
|
||||||
Closure(QObject* sender, const char* signal,
|
|
||||||
std::tr1::function<void()> callback);
|
|
||||||
|
|
||||||
virtual ~Closure();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void Invoked();
|
void Invoked();
|
||||||
void Cleanup();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Connect(QObject* sender, const char* signal);
|
boost::scoped_ptr<ClosureBase> closure_;
|
||||||
|
Q_DISABLE_COPY(ObjectHelper);
|
||||||
QMetaMethod slot_;
|
|
||||||
std::tr1::function<void()> callback_;
|
|
||||||
|
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val0_;
|
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val1_;
|
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val2_;
|
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val3_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedPointerWrapper {
|
|
||||||
public:
|
|
||||||
virtual ~SharedPointerWrapper() {}
|
|
||||||
virtual QObject* data() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper to unpack a tuple into a QList.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SharedPointer : public SharedPointerWrapper {
|
void Arg(const T& tail, QList<QGenericArgument>* list) {
|
||||||
|
typedef decltype(tail.get_head()) HeadType;
|
||||||
|
list->append(Q_ARG(HeadType, tail.get_head()));
|
||||||
|
Arg(tail.get_tail(), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialisation for starting with an empty tuple, ie. no arguments.
|
||||||
|
template<>
|
||||||
|
void Arg<boost::tuples::tuple<>>(
|
||||||
|
const boost::tuples::tuple<>&,
|
||||||
|
QList<QGenericArgument>* list);
|
||||||
|
|
||||||
|
// Specialisation for the end of a tuple, where get_tail() returns null_type.
|
||||||
|
template<>
|
||||||
|
void Arg<boost::tuples::null_type>(
|
||||||
|
const boost::tuples::null_type&,
|
||||||
|
QList<QGenericArgument>* list);
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
class Closure : public ClosureBase {
|
||||||
public:
|
public:
|
||||||
explicit SharedPointer(QSharedPointer<T> ptr)
|
Closure(
|
||||||
: ptr_(ptr) {
|
QObject* sender,
|
||||||
|
const char* signal,
|
||||||
|
QObject* receiver,
|
||||||
|
const char* slot,
|
||||||
|
const Args&... args)
|
||||||
|
: ClosureBase(new ObjectHelper(sender, signal, this)),
|
||||||
|
// boost::bind is the easiest way to store an argument list.
|
||||||
|
function_(boost::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* data() const {
|
virtual void Invoke() {
|
||||||
return ptr_.data();
|
function_();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSharedPointer<T> ptr_;
|
void Call(const Args&... args) {
|
||||||
|
auto t = boost::make_tuple(args...);
|
||||||
|
QList<QGenericArgument> arg_list;
|
||||||
|
Arg(t, &arg_list);
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::function<void()> function_;
|
||||||
|
QObject* receiver_;
|
||||||
|
QMetaMethod slot_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// For use with a QSharedPointer as a sender.
|
template <typename T, typename... Args>
|
||||||
class SharedClosure : public Closure {
|
class SharedClosure : public Closure<Args...> {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SharedClosure(SharedPointerWrapper* sender, const char* signal,
|
SharedClosure(
|
||||||
QObject* receiver, const char* slot,
|
QSharedPointer<T> sender,
|
||||||
const ClosureArgumentWrapper* val0 = 0,
|
const char* signal,
|
||||||
const ClosureArgumentWrapper* val1 = 0,
|
QObject* receiver,
|
||||||
const ClosureArgumentWrapper* val2 = 0,
|
const char* slot,
|
||||||
const ClosureArgumentWrapper* val3 = 0)
|
const Args&... args)
|
||||||
: Closure(sender->data(), signal,
|
: Closure<Args...>(
|
||||||
receiver, slot,
|
sender.data(),
|
||||||
val0, val1, val2, val3),
|
signal,
|
||||||
shared_sender_(sender) {
|
receiver,
|
||||||
|
slot,
|
||||||
|
args...),
|
||||||
|
data_(sender) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::scoped_ptr<SharedPointerWrapper> shared_sender_;
|
QSharedPointer<T> data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace _detail
|
} // namespace _detail
|
||||||
|
|
||||||
#define C_ARG(type, data) new _detail::ClosureArgument<type>(data)
|
template <typename... Args>
|
||||||
|
_detail::ClosureBase* NewClosure(
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QObject* sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QObject* sender,
|
QObject* sender,
|
||||||
const char* signal,
|
const char* signal,
|
||||||
QObject* receiver,
|
QObject* receiver,
|
||||||
const char* slot,
|
const char* slot,
|
||||||
const T& val0) {
|
const Args&... args) {
|
||||||
return new _detail::Closure(
|
return new _detail::Closure<Args...>(
|
||||||
sender, signal, receiver, slot,
|
sender, signal, receiver, slot, args...);
|
||||||
C_ARG(T, val0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T0, typename T1>
|
// QSharedPointer variant
|
||||||
_detail::Closure* NewClosure(
|
template <typename T, typename... Args>
|
||||||
QObject* sender,
|
_detail::ClosureBase* NewClosure(
|
||||||
|
QSharedPointer<T> sender,
|
||||||
const char* signal,
|
const char* signal,
|
||||||
QObject* receiver,
|
QObject* receiver,
|
||||||
const char* slot,
|
const char* slot,
|
||||||
const T0& val0,
|
const Args&... args) {
|
||||||
const T1& val1) {
|
return new _detail::SharedClosure<T, Args...>(
|
||||||
return new _detail::Closure(
|
sender, signal, receiver, slot, args...);
|
||||||
sender, signal, receiver, slot,
|
|
||||||
C_ARG(T0, val0), C_ARG(T1, val1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T0, typename T1, typename T2>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QObject* sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot,
|
|
||||||
const T0& val0,
|
|
||||||
const T1& val1,
|
|
||||||
const T2& val2) {
|
|
||||||
return new _detail::Closure(
|
|
||||||
sender, signal, receiver, slot,
|
|
||||||
C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T0, typename T1, typename T2, typename T3>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QObject* sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot,
|
|
||||||
const T0& val0,
|
|
||||||
const T1& val1,
|
|
||||||
const T2& val2,
|
|
||||||
const T3& val3) {
|
|
||||||
return new _detail::Closure(
|
|
||||||
sender, signal, receiver, slot,
|
|
||||||
C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2), C_ARG(T3, val3));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TP>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QSharedPointer<TP> sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot) {
|
|
||||||
return new _detail::SharedClosure(
|
|
||||||
new _detail::SharedPointer<TP>(sender), signal, receiver, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TP, typename T0>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QSharedPointer<TP> sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot,
|
|
||||||
const T0& val0) {
|
|
||||||
return new _detail::SharedClosure(
|
|
||||||
new _detail::SharedPointer<TP>(sender), signal, receiver, slot,
|
|
||||||
C_ARG(T0, val0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TP, typename T0, typename T1>
|
|
||||||
_detail::Closure* NewClosure(
|
|
||||||
QSharedPointer<TP> sender,
|
|
||||||
const char* signal,
|
|
||||||
QObject* receiver,
|
|
||||||
const char* slot,
|
|
||||||
const T0& val0,
|
|
||||||
const T1& val1) {
|
|
||||||
return new _detail::SharedClosure(
|
|
||||||
new _detail::SharedPointer<TP>(sender), signal, receiver, slot,
|
|
||||||
C_ARG(T0, val0), C_ARG(T1, val1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoAfter(QObject* receiver, const char* slot, int msec);
|
void DoAfter(QObject* receiver, const char* slot, int msec);
|
||||||
void DoInAMinuteOrSo(QObject* receiver, const char* slot);
|
void DoInAMinuteOrSo(QObject* receiver, const char* slot);
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2012, David Sansome <me@davidsansome.com>
|
Copyright 2012, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
Clementine is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "googledriveclient.h"
|
#include "googledriveclient.h"
|
||||||
#include "oauthenticator.h"
|
|
||||||
#include "core/closure.h"
|
|
||||||
#include "core/network.h"
|
|
||||||
|
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
|
#include "oauthenticator.h"
|
||||||
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/network.h"
|
||||||
|
|
||||||
using namespace google_drive;
|
using namespace google_drive;
|
||||||
|
|
||||||
const char* File::kFolderMimeType = "application/vnd.google-apps.folder";
|
const char* File::kFolderMimeType = "application/vnd.google-apps.folder";
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
#include "core/closure.h"
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "moodbarloader.h"
|
#include "moodbarloader.h"
|
||||||
#include "moodbarpipeline.h"
|
|
||||||
#include "core/application.h"
|
#include <boost/scoped_ptr.hpp>
|
||||||
#include "core/closure.h"
|
|
||||||
#include "core/qhash_qurl.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -30,7 +27,12 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include "moodbarpipeline.h"
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/qhash_qurl.h"
|
||||||
|
#include "core/utilities.h"
|
||||||
|
|
||||||
MoodbarLoader::MoodbarLoader(Application* app, QObject* parent)
|
MoodbarLoader::MoodbarLoader(Application* app, QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
|
|
|
@ -189,7 +189,7 @@ void GPodderSync::DeviceUpdatesFinished(mygpo::DeviceUpdatesPtr reply) {
|
||||||
// have a list of the episodes.
|
// have a list of the episodes.
|
||||||
PodcastUrlLoaderReply* loader_reply = loader_->Load(url);
|
PodcastUrlLoaderReply* loader_reply = loader_->Load(url);
|
||||||
NewClosure(loader_reply, SIGNAL(Finished(bool)),
|
NewClosure(loader_reply, SIGNAL(Finished(bool)),
|
||||||
this, SLOT(NewPodcastLoaded(PodcastUrlLoaderReply*,QUrl,QList<QSharedPointer<mygpo::Episode> >)),
|
this, SLOT(NewPodcastLoaded(PodcastUrlLoaderReply*,QUrl,QList<mygpo::EpisodePtr>)),
|
||||||
loader_reply, url, episodes_by_podcast[url]);
|
loader_reply, url, episodes_by_podcast[url]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2012, David Sansome <me@davidsansome.com>
|
Copyright 2012, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
Clementine is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "podcastparser.h"
|
|
||||||
#include "podcasturlloader.h"
|
#include "podcasturlloader.h"
|
||||||
#include "core/closure.h"
|
|
||||||
#include "core/network.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
#include "podcastparser.h"
|
||||||
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/network.h"
|
||||||
|
#include "core/utilities.h"
|
||||||
|
|
||||||
const int PodcastUrlLoader::kMaxRedirects = 5;
|
const int PodcastUrlLoader::kMaxRedirects = 5;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
#include "core/closure.h"
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
#include "songkickconcertwidget.h"
|
#include "songkickconcertwidget.h"
|
||||||
|
|
||||||
const char* SongkickConcerts::kSongkickArtistBucket = "id:songkick";
|
const char* SongkickConcerts::kSongkickArtistBucket = "id:songkick";
|
||||||
|
|
|
@ -15,18 +15,20 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "songinfotextview.h"
|
|
||||||
#include "songkickconcertwidget.h"
|
#include "songkickconcertwidget.h"
|
||||||
#include "ui_songkickconcertwidget.h"
|
|
||||||
#include "core/closure.h"
|
|
||||||
#include "core/network.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
|
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
#include "songinfotextview.h"
|
||||||
|
#include "ui_songkickconcertwidget.h"
|
||||||
|
#include "core/closure.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/network.h"
|
||||||
|
#include "core/utilities.h"
|
||||||
|
|
||||||
const int SongKickConcertWidget::kStaticMapWidth = 100;
|
const int SongKickConcertWidget::kStaticMapWidth = 100;
|
||||||
const int SongKickConcertWidget::kStaticMapHeight = 100;
|
const int SongKickConcertWidget::kStaticMapHeight = 100;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -U__STRICT_ANSI__ -fpermissive")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -fpermissive -U__STRICT_ANSI__")
|
||||||
|
|
||||||
if(USE_SYSTEM_GMOCK)
|
if(USE_SYSTEM_GMOCK)
|
||||||
include_directories(${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
|
include_directories(${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
TEST(ClosureTest, ClosureInvokesReceiver) {
|
TEST(ClosureTest, ClosureInvokesReceiver) {
|
||||||
TestQObject sender;
|
TestQObject sender;
|
||||||
TestQObject receiver;
|
TestQObject receiver;
|
||||||
_detail::Closure* closure = NewClosure(
|
_detail::ClosureBase* closure = NewClosure(
|
||||||
&sender, SIGNAL(Emitted()),
|
&sender, SIGNAL(Emitted()),
|
||||||
&receiver, SLOT(Invoke()));
|
&receiver, SLOT(Invoke()));
|
||||||
EXPECT_EQ(0, receiver.invoked());
|
EXPECT_EQ(0, receiver.invoked());
|
||||||
|
@ -22,17 +22,18 @@ TEST(ClosureTest, ClosureInvokesReceiver) {
|
||||||
TEST(ClosureTest, ClosureDeletesSelf) {
|
TEST(ClosureTest, ClosureDeletesSelf) {
|
||||||
TestQObject sender;
|
TestQObject sender;
|
||||||
TestQObject receiver;
|
TestQObject receiver;
|
||||||
_detail::Closure* closure = NewClosure(
|
_detail::ClosureBase* closure = NewClosure(
|
||||||
&sender, SIGNAL(Emitted()),
|
&sender, SIGNAL(Emitted()),
|
||||||
&receiver, SLOT(Invoke()));
|
&receiver, SLOT(Invoke()));
|
||||||
QSignalSpy spy(closure, SIGNAL(destroyed()));
|
_detail::ObjectHelper* helper = closure->helper();
|
||||||
|
QSignalSpy spy(helper, SIGNAL(destroyed()));
|
||||||
EXPECT_EQ(0, receiver.invoked());
|
EXPECT_EQ(0, receiver.invoked());
|
||||||
sender.Emit();
|
sender.Emit();
|
||||||
EXPECT_EQ(1, receiver.invoked());
|
EXPECT_EQ(1, receiver.invoked());
|
||||||
|
|
||||||
EXPECT_EQ(0, spy.count());
|
EXPECT_EQ(0, spy.count());
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QObject::connect(closure, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
QObject::connect(helper, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
||||||
loop.exec();
|
loop.exec();
|
||||||
EXPECT_EQ(1, spy.count());
|
EXPECT_EQ(1, spy.count());
|
||||||
}
|
}
|
||||||
|
@ -41,23 +42,23 @@ TEST(ClosureTest, ClosureDoesNotCrashWithSharedPointerSender) {
|
||||||
TestQObject receiver;
|
TestQObject receiver;
|
||||||
TestQObject* sender;
|
TestQObject* sender;
|
||||||
boost::scoped_ptr<QSignalSpy> spy;
|
boost::scoped_ptr<QSignalSpy> spy;
|
||||||
QPointer<_detail::Closure> closure;
|
QPointer<_detail::ObjectHelper> closure;
|
||||||
{
|
{
|
||||||
QSharedPointer<TestQObject> sender_shared(new TestQObject);
|
QSharedPointer<TestQObject> sender_shared(new TestQObject);
|
||||||
sender = sender_shared.data();
|
sender = sender_shared.data();
|
||||||
closure = QPointer<_detail::Closure>(NewClosure(
|
closure = QPointer<_detail::ObjectHelper>(NewClosure(
|
||||||
sender_shared, SIGNAL(Emitted()),
|
sender_shared, SIGNAL(Emitted()),
|
||||||
&receiver, SLOT(Invoke())));
|
&receiver, SLOT(Invoke()))->helper());
|
||||||
spy.reset(new QSignalSpy(sender, SIGNAL(destroyed())));
|
spy.reset(new QSignalSpy(sender, SIGNAL(destroyed())));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(0, receiver.invoked());
|
ASSERT_EQ(0, receiver.invoked());
|
||||||
sender->Emit();
|
sender->Emit();
|
||||||
EXPECT_EQ(1, receiver.invoked());
|
ASSERT_EQ(1, receiver.invoked());
|
||||||
|
|
||||||
EXPECT_EQ(0, spy->count());
|
ASSERT_EQ(0, spy->count());
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QObject::connect(sender, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
QObject::connect(sender, SIGNAL(destroyed()), &loop, SLOT(quit()));
|
||||||
loop.exec();
|
loop.exec();
|
||||||
EXPECT_EQ(1, spy->count());
|
ASSERT_EQ(1, spy->count());
|
||||||
EXPECT_TRUE(closure.isNull());
|
EXPECT_TRUE(closure.isNull());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue