From 271ad9e4fdb4f003abd33b59ca9cadfb5bab9823 Mon Sep 17 00:00:00 2001
From: Petr Mrázek <peterix@gmail.com>
Date: Sat, 26 Sep 2015 13:45:29 +0200
Subject: GH-1072 split resource system to UI and logic parts

---
 application/CMakeLists.txt              |  6 +++
 application/MultiMC.cpp                 | 37 +++++-------------
 logic/CMakeLists.txt                    |  4 --
 logic/resources/IconResourceHandler.cpp | 62 ------------------------------
 logic/resources/IconResourceHandler.h   | 27 -------------
 logic/resources/Resource.cpp            | 41 +++++++++++---------
 logic/resources/ResourceProxyModel.h    |  4 +-
 logic/resources/WebResourceHandler.cpp  | 67 ---------------------------------
 logic/resources/WebResourceHandler.h    | 23 -----------
 9 files changed, 43 insertions(+), 228 deletions(-)
 delete mode 100644 logic/resources/IconResourceHandler.cpp
 delete mode 100644 logic/resources/IconResourceHandler.h
 delete mode 100644 logic/resources/WebResourceHandler.cpp
 delete mode 100644 logic/resources/WebResourceHandler.h

diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt
index f72b6a16..47563693 100644
--- a/application/CMakeLists.txt
+++ b/application/CMakeLists.txt
@@ -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
diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp
index 98919d30..a893c875 100644
--- a/application/MultiMC.cpp
+++ b/application/MultiMC.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
+	//FIXME: none of this should be here.
+	Resource::registerHandler<WebResourceHandler>("web");
+	Resource::registerHandler<IconResourceHandler>("icon");
+
+	Resource::registerTransformer([](const QByteArray &data) -> QPixmap
 	{
-		QIcon icon;
-		for (auto it = map.constBegin(); it != map.constEnd(); ++it)
-		{
-			icon.addFile(it.key(), QSize(it.value().toInt(), it.value().toInt()));
-		}
-		return icon;
+		return QPixmap::fromImage(QImage::fromData(data));
 	});
-	Resource::registerTransformer([](const QVariantMap &map) -> QPixmap
+	Resource::registerTransformer([](const QByteArray &data) -> QIcon
 	{
-		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();
-		}
+		return QIcon(QPixmap::fromImage(QImage::fromData(data)));
 	});
-	Resource::registerTransformer([](const QByteArray &data) -> QPixmap
-	{ return QPixmap::fromImage(QImage::fromData(data)); });
-	Resource::registerTransformer([](const QByteArray &data) -> QIcon
-	{ return QIcon(QPixmap::fromImage(QImage::fromData(data))); });
 }
 
 
diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt
index f16f054a..457e97f3 100644
--- a/logic/CMakeLists.txt
+++ b/logic/CMakeLists.txt
@@ -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
 
diff --git a/logic/resources/IconResourceHandler.cpp b/logic/resources/IconResourceHandler.cpp
deleted file mode 100644
index 99353b6c..00000000
--- a/logic/resources/IconResourceHandler.cpp
+++ /dev/null
@@ -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;
-}
diff --git a/logic/resources/IconResourceHandler.h b/logic/resources/IconResourceHandler.h
deleted file mode 100644
index 44fafc07..00000000
--- a/logic/resources/IconResourceHandler.h
+++ /dev/null
@@ -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;
-};
diff --git a/logic/resources/Resource.cpp b/logic/resources/Resource.cpp
index 3cc6b648..e95675d7 100644
--- a/logic/resources/Resource.cpp
+++ b/logic/resources/Resource.cpp
@@ -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);
diff --git a/logic/resources/ResourceProxyModel.h b/logic/resources/ResourceProxyModel.h
index f9a83d1d..98a3dbd1 100644
--- a/logic/resources/ResourceProxyModel.h
+++ b/logic/resources/ResourceProxyModel.h
@@ -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:
diff --git a/logic/resources/WebResourceHandler.cpp b/logic/resources/WebResourceHandler.cpp
deleted file mode 100644
index 7ced5bc6..00000000
--- a/logic/resources/WebResourceHandler.cpp
+++ /dev/null
@@ -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());
-	}
-}
diff --git a/logic/resources/WebResourceHandler.h b/logic/resources/WebResourceHandler.h
deleted file mode 100644
index 88804af3..00000000
--- a/logic/resources/WebResourceHandler.h
+++ /dev/null
@@ -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);
-};
-- 
cgit