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

committed by
Petr Mrázek

parent
161dc66c2c
commit
3a8b238052
60
logic/resources/IconResourceHandler.cpp
Normal file
60
logic/resources/IconResourceHandler.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "IconResourceHandler.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
QString IconResourceHandler::m_theme = "multimc";
|
||||
QList<std::weak_ptr<IconResourceHandler>> IconResourceHandler::m_iconHandlers;
|
||||
|
||||
IconResourceHandler::IconResourceHandler(const QString &key)
|
||||
: m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
void IconResourceHandler::setTheme(const QString &theme)
|
||||
{
|
||||
m_theme = theme;
|
||||
|
||||
for (auto handler : m_iconHandlers)
|
||||
{
|
||||
std::shared_ptr<IconResourceHandler> ptr = handler.lock();
|
||||
if (ptr)
|
||||
{
|
||||
ptr->setResult(ptr->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IconResourceHandler::init(std::shared_ptr<ResourceHandler> &ptr)
|
||||
{
|
||||
m_iconHandlers.append(std::dynamic_pointer_cast<IconResourceHandler>(ptr));
|
||||
setResult(get());
|
||||
}
|
||||
|
||||
QVariant IconResourceHandler::get() const
|
||||
{
|
||||
const QDir iconsDir = QDir(":/icons/" + m_theme);
|
||||
|
||||
QVariantMap out;
|
||||
for (const QFileInfo &sizeInfo : iconsDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
|
||||
{
|
||||
const QDir dir = QDir(sizeInfo.absoluteFilePath());
|
||||
const QString dirName = sizeInfo.fileName();
|
||||
const int size = dirName.left(dirName.indexOf('x')).toInt();
|
||||
if (dir.exists(m_key + ".png") && dirName != "scalable")
|
||||
{
|
||||
out.insert(dir.absoluteFilePath(m_key + ".png"), size);
|
||||
}
|
||||
else if (dir.exists(m_key + ".svg") && dirName == "scalable")
|
||||
{
|
||||
out.insert(dir.absoluteFilePath(m_key + ".svg"), size);
|
||||
}
|
||||
}
|
||||
|
||||
if (out.isEmpty())
|
||||
{
|
||||
qWarning() << "Couldn't find any icons for" << m_key;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
22
logic/resources/IconResourceHandler.h
Normal file
22
logic/resources/IconResourceHandler.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ResourceHandler.h"
|
||||
|
||||
class IconResourceHandler : public ResourceHandler
|
||||
{
|
||||
public:
|
||||
explicit IconResourceHandler(const QString &key);
|
||||
|
||||
static void setTheme(const QString &theme);
|
||||
|
||||
private:
|
||||
void init(std::shared_ptr<ResourceHandler> &ptr) override;
|
||||
|
||||
QString m_key;
|
||||
static QString m_theme;
|
||||
static QList<std::weak_ptr<IconResourceHandler>> m_iconHandlers;
|
||||
|
||||
QVariant get() const;
|
||||
};
|
121
logic/resources/Resource.cpp
Normal file
121
logic/resources/Resource.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include "Resource.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "WebResourceHandler.h"
|
||||
#include "IconResourceHandler.h"
|
||||
#include "ResourceObserver.h"
|
||||
|
||||
QMap<QString, std::function<std::shared_ptr<ResourceHandler>(const QString &)>> Resource::m_handlers;
|
||||
QMap<QPair<int, int>, std::function<QVariant(QVariant)>> Resource::m_transfomers;
|
||||
QMap<QString, std::weak_ptr<Resource>> Resource::m_resources;
|
||||
|
||||
Resource::Resource(const QString &resource)
|
||||
{
|
||||
if (!m_handlers.contains("web"))
|
||||
{
|
||||
registerHandler<WebResourceHandler>("web");
|
||||
}
|
||||
if (!m_handlers.contains("icon"))
|
||||
{
|
||||
registerHandler<IconResourceHandler>("icon");
|
||||
}
|
||||
|
||||
Q_ASSERT(resource.contains(':'));
|
||||
const QString resourceId = resource.left(resource.indexOf(':'));
|
||||
Q_ASSERT(m_handlers.contains(resourceId));
|
||||
m_handler = m_handlers.value(resourceId)(resource.mid(resource.indexOf(':') + 1));
|
||||
m_handler->init(m_handler);
|
||||
m_handler->setResource(this);
|
||||
Q_ASSERT(m_handler);
|
||||
}
|
||||
Resource::~Resource()
|
||||
{
|
||||
qDeleteAll(m_observers);
|
||||
}
|
||||
|
||||
Resource::Ptr Resource::create(const QString &resource)
|
||||
{
|
||||
Resource::Ptr ptr = m_resources.contains(resource)
|
||||
? m_resources.value(resource).lock()
|
||||
: nullptr;
|
||||
if (!ptr)
|
||||
{
|
||||
struct ConstructableResource : public Resource
|
||||
{
|
||||
explicit ConstructableResource(const QString &resource)
|
||||
: Resource(resource) {}
|
||||
};
|
||||
ptr = std::make_shared<ConstructableResource>(resource);
|
||||
m_resources.insert(resource, ptr);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Resource::Ptr Resource::applyTo(ResourceObserver *observer)
|
||||
{
|
||||
m_observers.append(observer);
|
||||
observer->setSource(shared_from_this()); // give the observer a shared_ptr for us so we don't get deleted
|
||||
observer->resourceUpdated();
|
||||
return shared_from_this();
|
||||
}
|
||||
Resource::Ptr Resource::applyTo(QObject *target, const char *property)
|
||||
{
|
||||
// the cast to ResourceObserver* is required to ensure the right overload gets choosen
|
||||
return applyTo(static_cast<ResourceObserver *>(new QObjectResourceObserver(target, property)));
|
||||
}
|
||||
|
||||
Resource::Ptr Resource::placeholder(Resource::Ptr other)
|
||||
{
|
||||
m_placeholder = other;
|
||||
for (ResourceObserver *observer : m_observers)
|
||||
{
|
||||
observer->resourceUpdated();
|
||||
}
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
QVariant Resource::getResourceInternal(const int typeId) const
|
||||
{
|
||||
if (m_handler->result().isNull() && m_placeholder)
|
||||
{
|
||||
return m_placeholder->getResourceInternal(typeId);
|
||||
}
|
||||
const QVariant variant = m_handler->result();
|
||||
const auto typePair = qMakePair(int(variant.type()), typeId);
|
||||
if (m_transfomers.contains(typePair))
|
||||
{
|
||||
return m_transfomers.value(typePair)(variant);
|
||||
}
|
||||
else
|
||||
{
|
||||
return variant;
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::reportResult()
|
||||
{
|
||||
for (ResourceObserver *observer : m_observers)
|
||||
{
|
||||
observer->resourceUpdated();
|
||||
}
|
||||
}
|
||||
void Resource::reportFailure(const QString &reason)
|
||||
{
|
||||
for (ResourceObserver *observer : m_observers)
|
||||
{
|
||||
observer->setFailure(reason);
|
||||
}
|
||||
}
|
||||
void Resource::reportProgress(const int progress)
|
||||
{
|
||||
for (ResourceObserver *observer : m_observers)
|
||||
{
|
||||
observer->setProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::notifyObserverDeleted(ResourceObserver *observer)
|
||||
{
|
||||
m_observers.removeAll(observer);
|
||||
}
|
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;
|
||||
};
|
28
logic/resources/ResourceHandler.cpp
Normal file
28
logic/resources/ResourceHandler.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "ResourceHandler.h"
|
||||
|
||||
#include "Resource.h"
|
||||
|
||||
void ResourceHandler::setResult(const QVariant &result)
|
||||
{
|
||||
m_result = result;
|
||||
if (m_resource)
|
||||
{
|
||||
m_resource->reportResult();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceHandler::setFailure(const QString &reason)
|
||||
{
|
||||
if (m_resource)
|
||||
{
|
||||
m_resource->reportFailure(reason);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceHandler::setProgress(const int progress)
|
||||
{
|
||||
if (m_resource)
|
||||
{
|
||||
m_resource->reportProgress(progress);
|
||||
}
|
||||
}
|
33
logic/resources/ResourceHandler.h
Normal file
33
logic/resources/ResourceHandler.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <QVariant>
|
||||
#include <memory>
|
||||
|
||||
class Resource;
|
||||
|
||||
/** Base class for things that can retrieve a resource.
|
||||
*
|
||||
* Subclass, provide a constructor that takes a single QString as argument, and
|
||||
* call Resource::registerHandler<MyResourceHandler>("<id>"), where <id> is the
|
||||
* prefix of the resource ("web", "icon", etc.)
|
||||
*/
|
||||
class ResourceHandler
|
||||
{
|
||||
public:
|
||||
virtual ~ResourceHandler() {}
|
||||
|
||||
void setResource(Resource *resource) { m_resource = resource; }
|
||||
// reimplement this if you need to do something after you have been put in a shared pointer
|
||||
virtual void init(std::shared_ptr<ResourceHandler>&) {}
|
||||
|
||||
QVariant result() const { return m_result; }
|
||||
|
||||
protected: // use these methods to notify the resource of changes
|
||||
void setResult(const QVariant &result);
|
||||
void setFailure(const QString &reason);
|
||||
void setProgress(const int progress);
|
||||
|
||||
private:
|
||||
QVariant m_result;
|
||||
Resource *m_resource = nullptr;
|
||||
};
|
55
logic/resources/ResourceObserver.cpp
Normal file
55
logic/resources/ResourceObserver.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "ResourceObserver.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "Resource.h"
|
||||
|
||||
static const char *defaultPropertyForTarget(QObject *target)
|
||||
{
|
||||
if (target->inherits("QLabel"))
|
||||
{
|
||||
return "pixmap";
|
||||
}
|
||||
else if (target->inherits("QAction") ||
|
||||
target->inherits("QMenu") ||
|
||||
target->inherits("QAbstractButton"))
|
||||
{
|
||||
return "icon";
|
||||
}
|
||||
// for unit tests
|
||||
else if (target->inherits("DummyObserverObject"))
|
||||
{
|
||||
return "property";
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT_X(false, "ResourceObserver.cpp: defaultPropertyForTarget", "Unrecognized QObject subclass");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QObjectResourceObserver::QObjectResourceObserver(QObject *target, const char *property)
|
||||
: QObject(target), m_target(target)
|
||||
{
|
||||
const QMetaObject *mo = m_target->metaObject();
|
||||
m_property = mo->property(mo->indexOfProperty(
|
||||
property ?
|
||||
property
|
||||
: defaultPropertyForTarget(target)));
|
||||
}
|
||||
void QObjectResourceObserver::resourceUpdated()
|
||||
{
|
||||
m_property.write(m_target, getInternal(m_property.type()));
|
||||
}
|
||||
|
||||
|
||||
ResourceObserver::~ResourceObserver()
|
||||
{
|
||||
m_resource->notifyObserverDeleted(this);
|
||||
}
|
||||
|
||||
QVariant ResourceObserver::getInternal(const int typeId) const
|
||||
{
|
||||
Q_ASSERT(m_resource);
|
||||
return m_resource->getResourceInternal(typeId);
|
||||
}
|
67
logic/resources/ResourceObserver.h
Normal file
67
logic/resources/ResourceObserver.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMetaProperty>
|
||||
|
||||
class QVariant;
|
||||
class Resource;
|
||||
|
||||
/// Base class for things that can use a resource
|
||||
class ResourceObserver
|
||||
{
|
||||
public:
|
||||
virtual ~ResourceObserver();
|
||||
|
||||
protected: // these methods are called by the Resource when something changes
|
||||
virtual void resourceUpdated() = 0;
|
||||
virtual void setFailure(const QString &) {}
|
||||
virtual void setProgress(const int) {}
|
||||
|
||||
private:
|
||||
friend class Resource;
|
||||
void setSource(std::shared_ptr<Resource> resource) { m_resource = resource; }
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
T get() const { return getInternal(qMetaTypeId<T>()).template value<T>(); }
|
||||
QVariant getInternal(const int typeId) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Resource> m_resource;
|
||||
};
|
||||
|
||||
/** Observer for QObject properties
|
||||
*
|
||||
* Give it a target and the name of a property, and that property will be set when the resource changes.
|
||||
*
|
||||
* If no name is given an attempt to find a default property for some common classes is done.
|
||||
*/
|
||||
class QObjectResourceObserver : public QObject, public ResourceObserver
|
||||
{
|
||||
public:
|
||||
explicit QObjectResourceObserver(QObject *target, const char *property = nullptr);
|
||||
|
||||
void resourceUpdated() override;
|
||||
|
||||
private:
|
||||
QObject *m_target;
|
||||
QMetaProperty m_property;
|
||||
};
|
||||
|
||||
template <typename Ret, typename Arg, typename Func>
|
||||
class FunctionResourceObserver : public ResourceObserver
|
||||
{
|
||||
std::function<Ret(Arg)> m_function;
|
||||
public:
|
||||
template <typename T>
|
||||
explicit FunctionResourceObserver(T &&func)
|
||||
: m_function(std::forward<Func>(func)) {}
|
||||
|
||||
void resourceUpdated() override
|
||||
{
|
||||
m_function(get<Arg>());
|
||||
}
|
||||
};
|
103
logic/resources/ResourceProxyModel.cpp
Normal file
103
logic/resources/ResourceProxyModel.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "ResourceProxyModel.h"
|
||||
|
||||
#include <QItemSelectionRange>
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceObserver.h"
|
||||
|
||||
//Q_DECLARE_METATYPE(QVector<int>)
|
||||
|
||||
class ModelResourceObserver : public ResourceObserver
|
||||
{
|
||||
public:
|
||||
explicit ModelResourceObserver(const QModelIndex &index, const int role)
|
||||
: m_index(index), m_role(role)
|
||||
{
|
||||
qRegisterMetaType<QVector<int>>("QVector<int>");
|
||||
}
|
||||
|
||||
void resourceUpdated() override
|
||||
{
|
||||
if (m_index.isValid())
|
||||
{
|
||||
QMetaObject::invokeMethod(const_cast<QAbstractItemModel *>(m_index.model()),
|
||||
"dataChanged", Qt::QueuedConnection,
|
||||
Q_ARG(QModelIndex, m_index), Q_ARG(QModelIndex, m_index), Q_ARG(QVector<int>, QVector<int>() << m_role));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QPersistentModelIndex m_index;
|
||||
int m_role;
|
||||
};
|
||||
|
||||
ResourceProxyModel::ResourceProxyModel(const int resultTypeId, QObject *parent)
|
||||
: QIdentityProxyModel(parent), m_resultTypeId(resultTypeId)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant ResourceProxyModel::data(const QModelIndex &proxyIndex, int role) const
|
||||
{
|
||||
const QModelIndex mapped = mapToSource(proxyIndex);
|
||||
if (mapped.isValid() && role == Qt::DecorationRole && !mapToSource(proxyIndex).data(role).toString().isEmpty())
|
||||
{
|
||||
if (!m_resources.contains(mapped))
|
||||
{
|
||||
Resource::Ptr res = Resource::create(mapToSource(proxyIndex).data(role).toString())
|
||||
->applyTo(new ModelResourceObserver(proxyIndex, role));
|
||||
|
||||
const QVariant placeholder = mapped.data(PlaceholderRole);
|
||||
if (!placeholder.isNull() && placeholder.type() == QVariant::String)
|
||||
{
|
||||
res->placeholder(Resource::create(placeholder.toString()));
|
||||
}
|
||||
|
||||
m_resources.insert(mapped, res);
|
||||
}
|
||||
|
||||
return m_resources.value(mapped)->getResourceInternal(m_resultTypeId);
|
||||
}
|
||||
return mapped.data(role);
|
||||
}
|
||||
|
||||
void ResourceProxyModel::setSourceModel(QAbstractItemModel *model)
|
||||
{
|
||||
if (sourceModel())
|
||||
{
|
||||
disconnect(sourceModel(), 0, this, 0);
|
||||
}
|
||||
if (model)
|
||||
{
|
||||
connect(model, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &tl, const QModelIndex &br, const QVector<int> &roles)
|
||||
{
|
||||
if (roles.contains(Qt::DecorationRole) || roles.isEmpty())
|
||||
{
|
||||
const QItemSelectionRange range(tl, br);
|
||||
for (const QModelIndex &index : range.indexes())
|
||||
{
|
||||
m_resources.remove(index);
|
||||
}
|
||||
}
|
||||
else if (roles.contains(PlaceholderRole))
|
||||
{
|
||||
const QItemSelectionRange range(tl, br);
|
||||
for (const QModelIndex &index : range.indexes())
|
||||
{
|
||||
if (m_resources.contains(index))
|
||||
{
|
||||
const QVariant placeholder = index.data(PlaceholderRole);
|
||||
if (!placeholder.isNull() && placeholder.type() == QVariant::String)
|
||||
{
|
||||
m_resources.value(index)->placeholder(Resource::create(placeholder.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_resources.value(index)->placeholder(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
QIdentityProxyModel::setSourceModel(model);
|
||||
}
|
36
logic/resources/ResourceProxyModel.h
Normal file
36
logic/resources/ResourceProxyModel.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <QIdentityProxyModel>
|
||||
#include <memory>
|
||||
|
||||
/// Convenience proxy model that transforms resource identifiers (strings) for Qt::DecorationRole into other types.
|
||||
class ResourceProxyModel : public QIdentityProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// resultTypeId is found using qMetaTypeId<T>()
|
||||
explicit ResourceProxyModel(const int resultTypeId, QObject *parent = nullptr);
|
||||
|
||||
enum
|
||||
{
|
||||
// provide this role from your model if you want to show a placeholder
|
||||
PlaceholderRole = Qt::UserRole + 0xabc // some random offset to not collide with other stuff
|
||||
};
|
||||
|
||||
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
||||
void setSourceModel(QAbstractItemModel *model) override;
|
||||
|
||||
template <typename T>
|
||||
static QAbstractItemModel *mixin(QAbstractItemModel *model)
|
||||
{
|
||||
ResourceProxyModel *proxy = new ResourceProxyModel(qMetaTypeId<T>(), model);
|
||||
proxy->setSourceModel(model);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private:
|
||||
// mutable because it needs to be available from the const data()
|
||||
mutable QMap<QPersistentModelIndex, std::shared_ptr<class Resource>> m_resources;
|
||||
|
||||
const int m_resultTypeId;
|
||||
};
|
67
logic/resources/WebResourceHandler.cpp
Normal file
67
logic/resources/WebResourceHandler.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "WebResourceHandler.h"
|
||||
|
||||
#include "net/CacheDownload.h"
|
||||
#include "net/HttpMetaCache.h"
|
||||
#include "net/NetJob.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Env.h"
|
||||
|
||||
QMap<QString, NetJob *> WebResourceHandler::m_activeDownloads;
|
||||
|
||||
WebResourceHandler::WebResourceHandler(const QString &url)
|
||||
: QObject(), m_url(url)
|
||||
{
|
||||
MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", url);
|
||||
if (!entry->stale)
|
||||
{
|
||||
setResultFromFile(entry->getFullPath());
|
||||
}
|
||||
else if (m_activeDownloads.contains(url))
|
||||
{
|
||||
NetJob *job = m_activeDownloads.value(url);
|
||||
connect(job, &NetJob::succeeded, this, &WebResourceHandler::succeeded);
|
||||
connect(job, &NetJob::failed, this, [job, this]() {setFailure(job->failReason());});
|
||||
connect(job, &NetJob::progress, this, &WebResourceHandler::progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetJob *job = new NetJob("Icon download");
|
||||
job->addNetAction(CacheDownload::make(QUrl(url), entry));
|
||||
connect(job, &NetJob::succeeded, this, &WebResourceHandler::succeeded);
|
||||
connect(job, &NetJob::failed, this, [job, this]() {setFailure(job->failReason());});
|
||||
connect(job, &NetJob::progress, this, &WebResourceHandler::progress);
|
||||
connect(job, &NetJob::finished, job, [job](){m_activeDownloads.remove(m_activeDownloads.key(job));job->deleteLater();});
|
||||
m_activeDownloads.insert(url, job);
|
||||
job->start();
|
||||
}
|
||||
}
|
||||
|
||||
void WebResourceHandler::succeeded()
|
||||
{
|
||||
MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", m_url);
|
||||
setResultFromFile(entry->getFullPath());
|
||||
m_activeDownloads.remove(m_activeDownloads.key(qobject_cast<NetJob *>(sender())));
|
||||
}
|
||||
void WebResourceHandler::progress(qint64 current, qint64 total)
|
||||
{
|
||||
if (total == 0)
|
||||
{
|
||||
setProgress(101);
|
||||
}
|
||||
else
|
||||
{
|
||||
setProgress(current / total);
|
||||
}
|
||||
}
|
||||
|
||||
void WebResourceHandler::setResultFromFile(const QString &file)
|
||||
{
|
||||
try
|
||||
{
|
||||
setResult(FS::read(file));
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
setFailure(e.cause());
|
||||
}
|
||||
}
|
23
logic/resources/WebResourceHandler.h
Normal file
23
logic/resources/WebResourceHandler.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "ResourceHandler.h"
|
||||
|
||||
class NetJob;
|
||||
|
||||
class WebResourceHandler : public QObject, public ResourceHandler
|
||||
{
|
||||
public:
|
||||
explicit WebResourceHandler(const QString &url);
|
||||
|
||||
private slots:
|
||||
void succeeded();
|
||||
void progress(qint64 current, qint64 total);
|
||||
|
||||
private:
|
||||
static QMap<QString, NetJob *> m_activeDownloads;
|
||||
|
||||
QString m_url;
|
||||
|
||||
void setResultFromFile(const QString &file);
|
||||
};
|
Reference in New Issue
Block a user