diff options
author | Jan Dalheimer <jan@dalheimer.de> | 2015-05-28 19:38:29 +0200 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2015-06-06 21:23:05 +0200 |
commit | 3a8b238052163952831fb5924b2483a375e86ebd (patch) | |
tree | ab120b4fac3a5345a20e7a09e1e7477e67d9ed6f /logic/resources/Resource.h | |
parent | 161dc66c2c8d5f973ee69dab36c3969a7efd7495 (diff) | |
download | PrismLauncher-3a8b238052163952831fb5924b2483a375e86ebd.tar.gz PrismLauncher-3a8b238052163952831fb5924b2483a375e86ebd.tar.bz2 PrismLauncher-3a8b238052163952831fb5924b2483a375e86ebd.zip |
NOISSUE Various changes from multiauth that are unrelated to it
Diffstat (limited to 'logic/resources/Resource.h')
-rw-r--r-- | logic/resources/Resource.h | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/logic/resources/Resource.h b/logic/resources/Resource.h new file mode 100644 index 00000000..d566b2a2 --- /dev/null +++ b/logic/resources/Resource.h @@ -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; +}; |