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