GH-1072 split resource system to UI and logic parts
This commit is contained in:
		@@ -120,6 +120,12 @@ SET(MULTIMC_SOURCES
 | 
			
		||||
	BuildConfig.h
 | 
			
		||||
	${PROJECT_BINARY_DIR}/BuildConfig.cpp
 | 
			
		||||
 | 
			
		||||
	# Resource handlers and transformers
 | 
			
		||||
	handlers/IconResourceHandler.cpp
 | 
			
		||||
	handlers/IconResourceHandler.h
 | 
			
		||||
	handlers/WebResourceHandler.cpp
 | 
			
		||||
	handlers/WebResourceHandler.h
 | 
			
		||||
 | 
			
		||||
	# GUI - general utilities
 | 
			
		||||
	GuiUtil.h
 | 
			
		||||
	GuiUtil.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,8 @@
 | 
			
		||||
 | 
			
		||||
#include "trans/TranslationDownloader.h"
 | 
			
		||||
#include "resources/Resource.h"
 | 
			
		||||
#include "resources/IconResourceHandler.h"
 | 
			
		||||
#include "handlers/IconResourceHandler.h"
 | 
			
		||||
#include "handlers/WebResourceHandler.h"
 | 
			
		||||
 | 
			
		||||
#include "ftb/FTBPlugin.h"
 | 
			
		||||
 | 
			
		||||
@@ -341,36 +342,18 @@ void MultiMC::initIcons()
 | 
			
		||||
		ENV.m_icons->directoryChanged(value.toString());
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	Resource::registerTransformer([](const QVariantMap &map) -> QIcon
 | 
			
		||||
	{
 | 
			
		||||
		QIcon icon;
 | 
			
		||||
		for (auto it = map.constBegin(); it != map.constEnd(); ++it)
 | 
			
		||||
		{
 | 
			
		||||
			icon.addFile(it.key(), QSize(it.value().toInt(), it.value().toInt()));
 | 
			
		||||
		}
 | 
			
		||||
		return icon;
 | 
			
		||||
	});
 | 
			
		||||
	Resource::registerTransformer([](const QVariantMap &map) -> QPixmap
 | 
			
		||||
	{
 | 
			
		||||
		QVariantList sizes = map.values();
 | 
			
		||||
		if (sizes.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			return QPixmap();
 | 
			
		||||
		}
 | 
			
		||||
		std::sort(sizes.begin(), sizes.end());
 | 
			
		||||
		if (sizes.last().toInt() != -1) // only scalable available
 | 
			
		||||
		{
 | 
			
		||||
			return QPixmap(map.key(sizes.last()));
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return QPixmap();
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	//FIXME: none of this should be here.
 | 
			
		||||
	Resource::registerHandler<WebResourceHandler>("web");
 | 
			
		||||
	Resource::registerHandler<IconResourceHandler>("icon");
 | 
			
		||||
 | 
			
		||||
	Resource::registerTransformer([](const QByteArray &data) -> QPixmap
 | 
			
		||||
	{ return QPixmap::fromImage(QImage::fromData(data)); });
 | 
			
		||||
	{
 | 
			
		||||
		return QPixmap::fromImage(QImage::fromData(data));
 | 
			
		||||
	});
 | 
			
		||||
	Resource::registerTransformer([](const QByteArray &data) -> QIcon
 | 
			
		||||
	{ return QIcon(QPixmap::fromImage(QImage::fromData(data))); });
 | 
			
		||||
	{
 | 
			
		||||
		return QIcon(QPixmap::fromImage(QImage::fromData(data)));
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -46,16 +46,12 @@ set(LOGIC_SOURCES
 | 
			
		||||
	QObjectPtr.h
 | 
			
		||||
 | 
			
		||||
	# Resources
 | 
			
		||||
	resources/IconResourceHandler.cpp
 | 
			
		||||
	resources/IconResourceHandler.h
 | 
			
		||||
	resources/Resource.cpp
 | 
			
		||||
	resources/Resource.h
 | 
			
		||||
	resources/ResourceHandler.cpp
 | 
			
		||||
	resources/ResourceHandler.h
 | 
			
		||||
	resources/ResourceObserver.cpp
 | 
			
		||||
	resources/ResourceObserver.h
 | 
			
		||||
	resources/WebResourceHandler.cpp
 | 
			
		||||
	resources/WebResourceHandler.h
 | 
			
		||||
	resources/ResourceProxyModel.h
 | 
			
		||||
	resources/ResourceProxyModel.cpp
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
#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;
 | 
			
		||||
 | 
			
		||||
	// notify everyone
 | 
			
		||||
	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));
 | 
			
		||||
	// we always have a result, so lets report it now!
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "ResourceHandler.h"
 | 
			
		||||
 | 
			
		||||
#include "multimc_logic_export.h"
 | 
			
		||||
 | 
			
		||||
class MULTIMC_LOGIC_EXPORT IconResourceHandler : public ResourceHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	explicit IconResourceHandler(const QString &key);
 | 
			
		||||
 | 
			
		||||
	/// Sets the current theme and notifies all IconResourceHandlers of the change
 | 
			
		||||
	static void setTheme(const QString &theme);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	// we need to keep track of all IconResourceHandlers so that we can update them if the theme changes
 | 
			
		||||
	void init(std::shared_ptr<ResourceHandler> &ptr) override;
 | 
			
		||||
	static QList<std::weak_ptr<IconResourceHandler>> m_iconHandlers;
 | 
			
		||||
 | 
			
		||||
	QString m_key;
 | 
			
		||||
	static QString m_theme;
 | 
			
		||||
 | 
			
		||||
	// the workhorse, returns QVariantMap (filename => size) for m_key/m_theme
 | 
			
		||||
	QVariant get() const;
 | 
			
		||||
};
 | 
			
		||||
@@ -2,38 +2,45 @@
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
#include "WebResourceHandler.h"
 | 
			
		||||
#include "IconResourceHandler.h"
 | 
			
		||||
#include "ResourceObserver.h"
 | 
			
		||||
#include "ResourceHandler.h"
 | 
			
		||||
 | 
			
		||||
// definition of static members of Resource
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
struct NullResourceResult {};
 | 
			
		||||
Q_DECLARE_METATYPE(NullResourceResult)
 | 
			
		||||
class NullResourceHandler : public ResourceHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	explicit NullResourceHandler()
 | 
			
		||||
	{
 | 
			
		||||
		setResult(QVariant::fromValue<NullResourceResult>(NullResourceResult()));
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Resource::Resource(const QString &resource)
 | 
			
		||||
	: m_resource(resource)
 | 
			
		||||
{
 | 
			
		||||
	// register default handlers
 | 
			
		||||
	// QUESTION: move elsewhere?
 | 
			
		||||
	if (!m_handlers.contains("web"))
 | 
			
		||||
	if (!resource.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		registerHandler<WebResourceHandler>("web");
 | 
			
		||||
		// a valid resource identifier has the format <id>:<data>
 | 
			
		||||
		Q_ASSERT(resource.contains(':'));
 | 
			
		||||
		// "parse" the resource identifier into id and data
 | 
			
		||||
		const QString resourceId = resource.left(resource.indexOf(':'));
 | 
			
		||||
		const QString resourceData = resource.mid(resource.indexOf(':') + 1);
 | 
			
		||||
 | 
			
		||||
		// create and set up the handler
 | 
			
		||||
		Q_ASSERT(m_handlers.contains(resourceId));
 | 
			
		||||
		m_handler = m_handlers.value(resourceId)(resourceData);
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_handlers.contains("icon"))
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		registerHandler<IconResourceHandler>("icon");
 | 
			
		||||
		m_handler = std::make_shared<NullResourceHandler>();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// a valid resource identifier has the format <id>:<data>
 | 
			
		||||
	Q_ASSERT(resource.contains(':'));
 | 
			
		||||
	// "parse" the resource identifier into id and data
 | 
			
		||||
	const QString resourceId = resource.left(resource.indexOf(':'));
 | 
			
		||||
	const QString resourceData = resource.mid(resource.indexOf(':') + 1);
 | 
			
		||||
 | 
			
		||||
	// create and set up the handler
 | 
			
		||||
	Q_ASSERT(m_handlers.contains(resourceId));
 | 
			
		||||
	m_handler = m_handlers.value(resourceId)(resourceData);
 | 
			
		||||
	Q_ASSERT(m_handler);
 | 
			
		||||
	m_handler->init(m_handler);
 | 
			
		||||
	m_handler->setResource(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,10 @@
 | 
			
		||||
#include <QIdentityProxyModel>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "multimc_logic_export.h"
 | 
			
		||||
 | 
			
		||||
/// Convenience proxy model that transforms resource identifiers (strings) for Qt::DecorationRole into other types.
 | 
			
		||||
class ResourceProxyModel : public QIdentityProxyModel
 | 
			
		||||
class MULTIMC_LOGIC_EXPORT ResourceProxyModel : public QIdentityProxyModel
 | 
			
		||||
{
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
#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());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
#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