NOISSUE Various changes from multiauth that are unrelated to it
This commit is contained in:

committed by
Petr Mrázek

parent
161dc66c2c
commit
3a8b238052
116
logic/resources/Resource.h
Normal file
116
logic/resources/Resource.h
Normal file
@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "ResourceObserver.h"
|
||||
|
||||
class ResourceHandler;
|
||||
|
||||
namespace Detail
|
||||
{
|
||||
template <typename T> struct Function : public Function<decltype(&T::operator())> {};
|
||||
template <typename Ret, typename Arg> struct Function<Ret(*)(Arg)> : public Function<Ret(Arg)> {};
|
||||
template <typename Ret, typename Arg> struct Function<Ret(Arg)>
|
||||
{
|
||||
using ReturnType = Ret;
|
||||
using Argument = Arg;
|
||||
};
|
||||
template <class C, typename Ret, typename Arg> struct Function<Ret(C::*)(Arg)> : public Function<Ret(Arg)> {};
|
||||
template <class C, typename Ret, typename Arg> struct Function<Ret(C::*)(Arg) const> : public Function<Ret(Arg)> {};
|
||||
template <typename F> struct Function<F&> : public Function<F> {};
|
||||
template <typename F> struct Function<F&&> : public Function<F> {};
|
||||
}
|
||||
|
||||
/** Frontend class for resources
|
||||
*
|
||||
* Usage:
|
||||
* Resource::create("icon:noaccount")->applyTo(accountsAction);
|
||||
* Resource::create("web:http://asdf.com/image.png")->applyTo(imageLbl)->placeholder(Resource::create("icon:loading"));
|
||||
*
|
||||
* Memory management:
|
||||
* Resource caches ResourcePtrs using weak pointers, so while a resource is still existing
|
||||
* when a new resource is created the resources will be the same (including the same handler).
|
||||
*
|
||||
* ResourceObservers keep a shared pointer to the resource, as does the Resource itself to it's
|
||||
* placeholder (if present). This means a resource stays valid while it's still used ("applied to" etc.)
|
||||
* by something. When nothing uses it anymore it gets deleted.
|
||||
*
|
||||
* \note Always pass resource around using ResourcePtr! Copy and move constructors are disabled for a reason.
|
||||
*/
|
||||
class Resource : public std::enable_shared_from_this<Resource>
|
||||
{
|
||||
explicit Resource(const QString &resource);
|
||||
Resource(const Resource &) = delete;
|
||||
Resource(Resource &&) = delete;
|
||||
public:
|
||||
using Ptr = std::shared_ptr<Resource>;
|
||||
|
||||
~Resource();
|
||||
|
||||
/// The returned pointer needs to be stored until either Resource::then is called, or it is used as the argument to Resource::placeholder.
|
||||
static Ptr create(const QString &resource);
|
||||
|
||||
/// This can e.g. be used to set a local icon as the placeholder while a slow (remote) icon is fetched
|
||||
Ptr placeholder(Ptr other);
|
||||
|
||||
/// Use these functions to specify what should happen when e.g. the resource changes
|
||||
Ptr applyTo(ResourceObserver *observer);
|
||||
Ptr applyTo(QObject *target, const char *property = nullptr);
|
||||
template<typename Func>
|
||||
Ptr then(Func &&func)
|
||||
{
|
||||
using Arg = typename std::remove_cv<
|
||||
typename std::remove_reference<typename Detail::Function<Func>::Argument>::type
|
||||
>::type;
|
||||
return applyTo(new FunctionResourceObserver<
|
||||
typename Detail::Function<Func>::ReturnType,
|
||||
Arg, Func
|
||||
>(std::forward<Func>(func)));
|
||||
}
|
||||
|
||||
/// Retrieve the currently active resource. If it's type is different from T a conversion will be attempted.
|
||||
template<typename T>
|
||||
T getResource() const { return getResourceInternal(qMetaTypeId<T>()).template value<T>(); }
|
||||
QVariant getResourceInternal(const int typeId) const;
|
||||
|
||||
template<typename T>
|
||||
static void registerHandler(const QString &id)
|
||||
{
|
||||
m_handlers.insert(id, [](const QString &res) { return std::make_shared<T>(res); });
|
||||
}
|
||||
template<typename Func>
|
||||
static void registerTransformer(Func &&func)
|
||||
{
|
||||
using Out = typename Detail::Function<Func>::ReturnType;
|
||||
using In = typename std::remove_cv<typename std::remove_reference<typename Detail::Function<Func>::Argument>::type>::type;
|
||||
static_assert(!std::is_same<Out, In>::value, "It does not make sense to transform a value to itself");
|
||||
m_transfomers.insert(qMakePair(qMetaTypeId<In>(), qMetaTypeId<Out>()), [func](const QVariant &in)
|
||||
{
|
||||
return QVariant::fromValue<Out>(func(in.value<In>()));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ResourceHandler;
|
||||
void reportResult();
|
||||
void reportFailure(const QString &reason);
|
||||
void reportProgress(const int progress);
|
||||
|
||||
friend class ResourceObserver;
|
||||
void notifyObserverDeleted(ResourceObserver *observer);
|
||||
|
||||
private:
|
||||
QList<ResourceObserver *> m_observers;
|
||||
std::shared_ptr<ResourceHandler> m_handler = nullptr;
|
||||
Ptr m_placeholder = nullptr;
|
||||
|
||||
// a list of resource handler factories, registered using registerHandler
|
||||
static QMap<QString, std::function<std::shared_ptr<ResourceHandler>(const QString &)>> m_handlers;
|
||||
// a list of resource transformers, registered using registerTransformer
|
||||
static QMap<QPair<int, int>, std::function<QVariant(QVariant)>> m_transfomers;
|
||||
static QMap<QString, std::weak_ptr<Resource>> m_resources;
|
||||
};
|
Reference in New Issue
Block a user