From 1be7d573326570d63e55e36235537ed2b1831ae1 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 10 Apr 2016 17:01:24 +0200 Subject: NOISSUE re/move some dead code and unused build system parts --- CMakeLists.txt | 9 - api/dead/README.md | 3 + api/dead/src/AbstractCommonModel.cpp | 133 ++++++++ api/dead/src/AbstractCommonModel.h | 462 ++++++++++++++++++++++++++ api/dead/src/BaseConfigObject.cpp | 103 ++++++ api/dead/src/BaseConfigObject.h | 50 +++ api/dead/src/TypeMagic.h | 37 +++ api/dead/src/handlers/IconResourceHandler.cpp | 37 +++ api/dead/src/handlers/IconResourceHandler.h | 23 ++ api/dead/src/handlers/WebResourceHandler.cpp | 68 ++++ api/dead/src/handlers/WebResourceHandler.h | 23 ++ api/dead/src/resources/Resource.cpp | 155 +++++++++ api/dead/src/resources/Resource.h | 132 ++++++++ api/dead/src/resources/ResourceHandler.cpp | 28 ++ api/dead/src/resources/ResourceHandler.h | 36 ++ api/dead/src/resources/ResourceObserver.cpp | 55 +++ api/dead/src/resources/ResourceObserver.h | 73 ++++ api/dead/src/resources/ResourceProxyModel.cpp | 89 +++++ api/dead/src/resources/ResourceProxyModel.h | 39 +++ api/dead/test/tst_Resource.cpp | 116 +++++++ api/logic/AbstractCommonModel.cpp | 133 -------- api/logic/AbstractCommonModel.h | 462 -------------------------- api/logic/BaseConfigObject.cpp | 103 ------ api/logic/BaseConfigObject.h | 50 --- api/logic/CMakeLists.txt | 15 - api/logic/TypeMagic.h | 37 --- api/logic/resources/Resource.cpp | 155 --------- api/logic/resources/Resource.h | 132 -------- api/logic/resources/ResourceHandler.cpp | 28 -- api/logic/resources/ResourceHandler.h | 36 -- api/logic/resources/ResourceObserver.cpp | 55 --- api/logic/resources/ResourceObserver.h | 73 ---- api/logic/resources/ResourceProxyModel.cpp | 89 ----- api/logic/resources/ResourceProxyModel.h | 39 --- application/CMakeLists.txt | 6 - application/MainWindow.cpp | 1 - application/MultiMC.cpp | 17 - application/handlers/IconResourceHandler.cpp | 37 --- application/handlers/IconResourceHandler.h | 23 -- application/handlers/WebResourceHandler.cpp | 68 ---- application/handlers/WebResourceHandler.h | 23 -- cmake/Coverage.cmake | 13 - cmake/Coverity.cmake | 35 -- tests/CMakeLists.txt | 60 +--- tests/tst_Resource.cpp | 116 ------- wonkoclient/WonkoClient.cpp | 1 - 46 files changed, 1664 insertions(+), 1814 deletions(-) create mode 100644 api/dead/README.md create mode 100644 api/dead/src/AbstractCommonModel.cpp create mode 100644 api/dead/src/AbstractCommonModel.h create mode 100644 api/dead/src/BaseConfigObject.cpp create mode 100644 api/dead/src/BaseConfigObject.h create mode 100644 api/dead/src/TypeMagic.h create mode 100644 api/dead/src/handlers/IconResourceHandler.cpp create mode 100644 api/dead/src/handlers/IconResourceHandler.h create mode 100644 api/dead/src/handlers/WebResourceHandler.cpp create mode 100644 api/dead/src/handlers/WebResourceHandler.h create mode 100644 api/dead/src/resources/Resource.cpp create mode 100644 api/dead/src/resources/Resource.h create mode 100644 api/dead/src/resources/ResourceHandler.cpp create mode 100644 api/dead/src/resources/ResourceHandler.h create mode 100644 api/dead/src/resources/ResourceObserver.cpp create mode 100644 api/dead/src/resources/ResourceObserver.h create mode 100644 api/dead/src/resources/ResourceProxyModel.cpp create mode 100644 api/dead/src/resources/ResourceProxyModel.h create mode 100644 api/dead/test/tst_Resource.cpp delete mode 100644 api/logic/AbstractCommonModel.cpp delete mode 100644 api/logic/AbstractCommonModel.h delete mode 100644 api/logic/BaseConfigObject.cpp delete mode 100644 api/logic/BaseConfigObject.h delete mode 100644 api/logic/TypeMagic.h delete mode 100644 api/logic/resources/Resource.cpp delete mode 100644 api/logic/resources/Resource.h delete mode 100644 api/logic/resources/ResourceHandler.cpp delete mode 100644 api/logic/resources/ResourceHandler.h delete mode 100644 api/logic/resources/ResourceObserver.cpp delete mode 100644 api/logic/resources/ResourceObserver.h delete mode 100644 api/logic/resources/ResourceProxyModel.cpp delete mode 100644 api/logic/resources/ResourceProxyModel.h delete mode 100644 application/handlers/IconResourceHandler.cpp delete mode 100644 application/handlers/IconResourceHandler.h delete mode 100644 application/handlers/WebResourceHandler.cpp delete mode 100644 application/handlers/WebResourceHandler.h delete mode 100644 cmake/Coverage.cmake delete mode 100644 cmake/Coverity.cmake delete mode 100644 tests/tst_Resource.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a82c3695..3db0df73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,10 +20,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) ######## Set module path ######## set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/") -# Only used for test coverage -set(MMC_SRC "${PROJECT_SOURCE_DIR}") -set(MMC_BIN "${PROJECT_BINARY_DIR}") - # Output all executables and shared libs in the main build folder, not in subfolders. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) if(UNIX) @@ -37,7 +33,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED true) set(CMAKE_C_STANDARD_REQUIRED true) set(CMAKE_CXX_STANDARD 11) set(CMAKE_C_STANDARD 11) -include(Coverage) include(GenerateExportHeader) set(CMAKE_CXX_FLAGS " -Wall -D_GLIBCXX_USE_CXX11_ABI=0 ${CMAKE_CXX_FLAGS}") if(UNIX AND APPLE) @@ -45,8 +40,6 @@ if(UNIX AND APPLE) endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type") -# cmake code needed for the coverity scan upload -include(Coverity) ################################ 3rd Party Libs ################################ @@ -108,8 +101,6 @@ add_subdirectory(libraries/pack200) # java pack200 compression add_subdirectory(libraries/rainbow) # Qt extension for colors add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader -include(Coverity) - ############################### Built Artifacts ############################### add_subdirectory(tests) diff --git a/api/dead/README.md b/api/dead/README.md new file mode 100644 index 00000000..520b18d3 --- /dev/null +++ b/api/dead/README.md @@ -0,0 +1,3 @@ +This stuff is dead code I collected from the repository that still looks like it might be useful for something. + +Moved on 10. April 2016 - if it hasn't been moved or used in a while, delete this. diff --git a/api/dead/src/AbstractCommonModel.cpp b/api/dead/src/AbstractCommonModel.cpp new file mode 100644 index 00000000..71d75829 --- /dev/null +++ b/api/dead/src/AbstractCommonModel.cpp @@ -0,0 +1,133 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AbstractCommonModel.h" + +BaseAbstractCommonModel::BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent) + : QAbstractListModel(parent), m_orientation(orientation) +{ +} + +int BaseAbstractCommonModel::rowCount(const QModelIndex &parent) const +{ + return m_orientation == Qt::Horizontal ? entryCount() : size(); +} +int BaseAbstractCommonModel::columnCount(const QModelIndex &parent) const +{ + return m_orientation == Qt::Horizontal ? size() : entryCount(); +} +QVariant BaseAbstractCommonModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(), index.parent())) + { + return QVariant(); + } + const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + return formatData(i, role, get(i, entry, role)); +} +QVariant BaseAbstractCommonModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation != m_orientation && role == Qt::DisplayRole) + { + return entryTitle(section); + } + else + { + return QVariant(); + } +} +bool BaseAbstractCommonModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + const bool result = set(i, entry, role, sanetizeData(i, role, value)); + if (result) + { + emit dataChanged(index, index, QVector() << role); + } + return result; +} +Qt::ItemFlags BaseAbstractCommonModel::flags(const QModelIndex &index) const +{ + if (!hasIndex(index.row(), index.column(), index.parent())) + { + return Qt::NoItemFlags; + } + + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + if (canSet(entry)) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; + } + else + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } +} + +void BaseAbstractCommonModel::notifyAboutToAddObject(const int at) +{ + if (m_orientation == Qt::Horizontal) + { + beginInsertColumns(QModelIndex(), at, at); + } + else + { + beginInsertRows(QModelIndex(), at, at); + } +} +void BaseAbstractCommonModel::notifyObjectAdded() +{ + if (m_orientation == Qt::Horizontal) + { + endInsertColumns(); + } + else + { + endInsertRows(); + } +} +void BaseAbstractCommonModel::notifyAboutToRemoveObject(const int at) +{ + if (m_orientation == Qt::Horizontal) + { + beginRemoveColumns(QModelIndex(), at, at); + } + else + { + beginRemoveRows(QModelIndex(), at, at); + } +} +void BaseAbstractCommonModel::notifyObjectRemoved() +{ + if (m_orientation == Qt::Horizontal) + { + endRemoveColumns(); + } + else + { + endRemoveRows(); + } +} + +void BaseAbstractCommonModel::notifyBeginReset() +{ + beginResetModel(); +} +void BaseAbstractCommonModel::notifyEndReset() +{ + endResetModel(); +} diff --git a/api/dead/src/AbstractCommonModel.h b/api/dead/src/AbstractCommonModel.h new file mode 100644 index 00000000..31b86a23 --- /dev/null +++ b/api/dead/src/AbstractCommonModel.h @@ -0,0 +1,462 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +class BaseAbstractCommonModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent = nullptr); + + // begin QAbstractItemModel interface + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + // end QAbstractItemModel interface + + virtual int size() const = 0; + virtual int entryCount() const = 0; + + virtual QVariant formatData(const int index, int role, const QVariant &data) const { return data; } + virtual QVariant sanetizeData(const int index, int role, const QVariant &data) const { return data; } + +protected: + virtual QVariant get(const int index, const int entry, const int role) const = 0; + virtual bool set(const int index, const int entry, const int role, const QVariant &value) = 0; + virtual bool canSet(const int entry) const = 0; + virtual QString entryTitle(const int entry) const = 0; + + void notifyAboutToAddObject(const int at); + void notifyObjectAdded(); + void notifyAboutToRemoveObject(const int at); + void notifyObjectRemoved(); + void notifyBeginReset(); + void notifyEndReset(); + + const Qt::Orientation m_orientation; +}; + +template +class AbstractCommonModel : public BaseAbstractCommonModel +{ +public: + explicit AbstractCommonModel(const Qt::Orientation orientation) + : BaseAbstractCommonModel(orientation) {} + virtual ~AbstractCommonModel() {} + + int size() const override { return m_objects.size(); } + int entryCount() const override { return m_entries.size(); } + + void append(const Object &object) + { + notifyAboutToAddObject(size()); + m_objects.append(object); + notifyObjectAdded(); + } + void prepend(const Object &object) + { + notifyAboutToAddObject(0); + m_objects.prepend(object); + notifyObjectAdded(); + } + void insert(const Object &object, const int index) + { + if (index >= size()) + { + prepend(object); + } + else if (index <= 0) + { + append(object); + } + else + { + notifyAboutToAddObject(index); + m_objects.insert(index, object); + notifyObjectAdded(); + } + } + void remove(const int index) + { + notifyAboutToRemoveObject(index); + m_objects.removeAt(index); + notifyObjectRemoved(); + } + Object get(const int index) const + { + return m_objects.at(index); + } + +private: + friend class CommonModel; + QVariant get(const int index, const int entry, const int role) const override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) + { + return QVariant(); + } + return m_entries[entry].second.value(role)->get(m_objects.at(index)); + } + bool set(const int index, const int entry, const int role, const QVariant &value) override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) + { + return false; + } + IEntry *e = m_entries[entry].second.value(role); + if (!e->canSet()) + { + return false; + } + e->set(m_objects[index], value); + return true; + } + bool canSet(const int entry) const override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) + { + return false; + } + IEntry *e = m_entries[entry].second.value(Qt::EditRole); + return e->canSet(); + } + + QString entryTitle(const int entry) const override + { + return m_entries.at(entry).first; + } + +private: + struct IEntry + { + virtual ~IEntry() {} + virtual void set(Object &object, const QVariant &value) = 0; + virtual QVariant get(const Object &object) const = 0; + virtual bool canSet() const = 0; + }; + template + struct VariableEntry : public IEntry + { + typedef T (Object::*Member); + + explicit VariableEntry(Member member) + : m_member(member) {} + + void set(Object &object, const QVariant &value) override + { + object.*m_member = value.value(); + } + QVariant get(const Object &object) const override + { + return QVariant::fromValue(object.*m_member); + } + bool canSet() const override { return true; } + + private: + Member m_member; + }; + template + struct FunctionEntry : public IEntry + { + typedef T (Object::*Getter)() const; + typedef void (Object::*Setter)(T); + + explicit FunctionEntry(Getter getter, Setter setter) + : m_getter(m_getter), m_setter(m_setter) {} + + void set(Object &object, const QVariant &value) override + { + object.*m_setter(value.value()); + } + QVariant get(const Object &object) const override + { + return QVariant::fromValue(object.*m_getter()); + } + bool canSet() const override { return !!m_setter; } + + private: + Getter m_getter; + Setter m_setter; + }; + + QList m_objects; + QVector>> m_entries; + + void addEntryInternal(IEntry *e, const int entry, const int role) + { + if (m_entries.size() <= entry) + { + m_entries.resize(entry + 1); + } + m_entries[entry].second.insert(role, e); + } + +protected: + template + typename std::enable_if::value && std::is_member_function_pointer::value, void>::type + addEntry(Getter getter, Setter setter, const int entry, const int role) + { + addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); + } + template + typename std::enable_if::value, void>::type + addEntry(Getter getter, const int entry, const int role) + { + addEntryInternal(new FunctionEntry::type>(getter, nullptr), entry, role); + } + template + typename std::enable_if::value, void>::type + addEntry(T (Object::*member), const int entry, const int role) + { + addEntryInternal(new VariableEntry(member), entry, role); + } + + void setEntryTitle(const int entry, const QString &title) + { + m_entries[entry].first = title; + } +}; +template +class AbstractCommonModel : public BaseAbstractCommonModel +{ +public: + explicit AbstractCommonModel(const Qt::Orientation orientation) + : BaseAbstractCommonModel(orientation) {} + virtual ~AbstractCommonModel() + { + qDeleteAll(m_objects); + } + + int size() const override { return m_objects.size(); } + int entryCount() const override { return m_entries.size(); } + + void append(Object *object) + { + notifyAboutToAddObject(size()); + m_objects.append(object); + notifyObjectAdded(); + } + void prepend(Object *object) + { + notifyAboutToAddObject(0); + m_objects.prepend(object); + notifyObjectAdded(); + } + void insert(Object *object, const int index) + { + if (index >= size()) + { + prepend(object); + } + else if (index <= 0) + { + append(object); + } + else + { + notifyAboutToAddObject(index); + m_objects.insert(index, object); + notifyObjectAdded(); + } + } + void remove(const int index) + { + notifyAboutToRemoveObject(index); + m_objects.removeAt(index); + notifyObjectRemoved(); + } + Object *get(const int index) const + { + return m_objects.at(index); + } + int find(Object * const obj) const + { + return m_objects.indexOf(obj); + } + + QList getAll() const + { + return m_objects; + } + +private: + friend class CommonModel; + QVariant get(const int index, const int entry, const int role) const override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) + { + return QVariant(); + } + return m_entries[entry].second.value(role)->get(m_objects.at(index)); + } + bool set(const int index, const int entry, const int role, const QVariant &value) override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) + { + return false; + } + IEntry *e = m_entries[entry].second.value(role); + if (!e->canSet()) + { + return false; + } + e->set(m_objects[index], value); + return true; + } + bool canSet(const int entry) const override + { + if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) + { + return false; + } + IEntry *e = m_entries[entry].second.value(Qt::EditRole); + return e->canSet(); + } + + QString entryTitle(const int entry) const override + { + return m_entries.at(entry).first; + } + +private: + struct IEntry + { + virtual ~IEntry() {} + virtual void set(Object *object, const QVariant &value) = 0; + virtual QVariant get(Object *object) const = 0; + virtual bool canSet() const = 0; + }; + template + struct VariableEntry : public IEntry + { + typedef T (Object::*Member); + + explicit VariableEntry(Member member) + : m_member(member) {} + + void set(Object *object, const QVariant &value) override + { + object->*m_member = value.value(); + } + QVariant get(Object *object) const override + { + return QVariant::fromValue(object->*m_member); + } + bool canSet() const override { return true; } + + private: + Member m_member; + }; + template + struct FunctionEntry : public IEntry + { + typedef T (Object::*Getter)() const; + typedef void (Object::*Setter)(T); + + explicit FunctionEntry(Getter getter, Setter setter) + : m_getter(getter), m_setter(setter) {} + + void set(Object *object, const QVariant &value) override + { + (object->*m_setter)(value.value()); + } + QVariant get(Object *object) const override + { + return QVariant::fromValue((object->*m_getter)()); + } + bool canSet() const override { return !!m_setter; } + + private: + Getter m_getter; + Setter m_setter; + }; + template + struct LambdaEntry : public IEntry + { + using Getter = std::function; + + explicit LambdaEntry(Getter getter) + : m_getter(getter) {} + + void set(Object *object, const QVariant &value) override {} + QVariant get(Object *object) const override + { + return QVariant::fromValue(m_getter(object)); + } + bool canSet() const override { return false; } + + private: + Getter m_getter; + }; + + QList m_objects; + QVector>> m_entries; + + void addEntryInternal(IEntry *e, const int entry, const int role) + { + if (m_entries.size() <= entry) + { + m_entries.resize(entry + 1); + } + m_entries[entry].second.insert(role, e); + } + +protected: + template + typename std::enable_if::value && std::is_member_function_pointer::value, void>::type + addEntry(const int entry, const int role, Getter getter, Setter setter) + { + addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); + } + template + typename std::enable_if::Getter>::value, void>::type + addEntry(const int entry, const int role, typename FunctionEntry::Getter getter) + { + addEntryInternal(new FunctionEntry(getter, nullptr), entry, role); + } + template + typename std::enable_if::value, void>::type + addEntry(const int entry, const int role, T (Object::*member)) + { + addEntryInternal(new VariableEntry(member), entry, role); + } + template + void addEntry(const int entry, const int role, typename LambdaEntry::Getter lambda) + { + addEntryInternal(new LambdaEntry(lambda), entry, role); + } + + void setEntryTitle(const int entry, const QString &title) + { + m_entries[entry].first = title; + } + + void setAll(const QList objects) + { + notifyBeginReset(); + qDeleteAll(m_objects); + m_objects = objects; + notifyEndReset(); + } +}; diff --git a/api/dead/src/BaseConfigObject.cpp b/api/dead/src/BaseConfigObject.cpp new file mode 100644 index 00000000..3040ac2e --- /dev/null +++ b/api/dead/src/BaseConfigObject.cpp @@ -0,0 +1,103 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BaseConfigObject.h" + +#include +#include +#include +#include + +#include "Exception.h" +#include "FileSystem.h" + +BaseConfigObject::BaseConfigObject(const QString &filename) + : m_filename(filename) +{ + m_saveTimer = new QTimer; + m_saveTimer->setSingleShot(true); + // cppcheck-suppress pureVirtualCall + QObject::connect(m_saveTimer, &QTimer::timeout, [this](){saveNow();}); + setSaveTimeout(250); + + m_initialReadTimer = new QTimer; + m_initialReadTimer->setSingleShot(true); + QObject::connect(m_initialReadTimer, &QTimer::timeout, [this]() + { + loadNow(); + m_initialReadTimer->deleteLater(); + m_initialReadTimer = 0; + }); + m_initialReadTimer->start(0); + + // cppcheck-suppress pureVirtualCall + m_appQuitConnection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this](){saveNow();}); +} +BaseConfigObject::~BaseConfigObject() +{ + delete m_saveTimer; + if (m_initialReadTimer) + { + delete m_initialReadTimer; + } + QObject::disconnect(m_appQuitConnection); +} + +void BaseConfigObject::setSaveTimeout(int msec) +{ + m_saveTimer->setInterval(msec); +} + +void BaseConfigObject::scheduleSave() +{ + m_saveTimer->stop(); + m_saveTimer->start(); +} +void BaseConfigObject::saveNow() +{ + if (m_saveTimer->isActive()) + { + m_saveTimer->stop(); + } + if (m_disableSaving) + { + return; + } + + try + { + FS::write(m_filename, doSave()); + } + catch (Exception & e) + { + qCritical() << e.cause(); + } +} +void BaseConfigObject::loadNow() +{ + if (m_saveTimer->isActive()) + { + saveNow(); + } + + try + { + doLoad(FS::read(m_filename)); + } + catch (Exception & e) + { + qWarning() << "Error loading" << m_filename << ":" << e.cause(); + } +} diff --git a/api/dead/src/BaseConfigObject.h b/api/dead/src/BaseConfigObject.h new file mode 100644 index 00000000..1c96b3d1 --- /dev/null +++ b/api/dead/src/BaseConfigObject.h @@ -0,0 +1,50 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class QTimer; + +class BaseConfigObject +{ +public: + void setSaveTimeout(int msec); + +protected: + explicit BaseConfigObject(const QString &filename); + virtual ~BaseConfigObject(); + + // cppcheck-suppress pureVirtualCall + virtual QByteArray doSave() const = 0; + virtual void doLoad(const QByteArray &data) = 0; + + void setSavingDisabled(bool savingDisabled) { m_disableSaving = savingDisabled; } + + QString fileName() const { return m_filename; } + +public: + void scheduleSave(); + void saveNow(); + void loadNow(); + +private: + QTimer *m_saveTimer; + QTimer *m_initialReadTimer; + QString m_filename; + QMetaObject::Connection m_appQuitConnection; + bool m_disableSaving = false; +}; diff --git a/api/dead/src/TypeMagic.h b/api/dead/src/TypeMagic.h new file mode 100644 index 00000000..fa9d12a9 --- /dev/null +++ b/api/dead/src/TypeMagic.h @@ -0,0 +1,37 @@ +#pragma once + +namespace TypeMagic +{ +/** "Cleans" the given type T by stripping references (&) and cv-qualifiers (const, volatile) from it + * const int => int + * QString & => QString + * const unsigned long long & => unsigned long long + * + * Usage: + * using Cleaned = Detail::CleanType; + * static_assert(std::is_same, "Cleaned == int"); + */ +// the order of remove_cv and remove_reference matters! +template +using CleanType = typename std::remove_cv::type>::type; + +/// For functors (structs with operator()), including lambdas, which in **most** cases are functors +/// "Calls" Function or Function +template struct Function : public Function {}; +/// For function pointers (&function), including static members (&Class::member) +template struct Function : public Function {}; +/// Default specialization used by others. +template struct Function +{ + using ReturnType = Ret; + using Argument = Arg; +}; +/// For member functions. Also used by the lambda overload if the lambda captures [this] +template struct Function : public Function {}; +template struct Function : public Function {}; +/// Overload for references +template struct Function : public Function {}; +/// Overload for rvalues +template struct Function : public Function {}; +// for more info: https://functionalcpp.wordpress.com/2013/08/05/function-traits/ +} diff --git a/api/dead/src/handlers/IconResourceHandler.cpp b/api/dead/src/handlers/IconResourceHandler.cpp new file mode 100644 index 00000000..b03553fd --- /dev/null +++ b/api/dead/src/handlers/IconResourceHandler.cpp @@ -0,0 +1,37 @@ +#include "IconResourceHandler.h" +#include + +#include +#include + +QList> IconResourceHandler::m_iconHandlers; + +IconResourceHandler::IconResourceHandler(const QString &key) + : m_key(key) +{ +} + +void IconResourceHandler::setTheme(const QString &theme) +{ + // notify everyone + for (auto handler : m_iconHandlers) + { + std::shared_ptr ptr = handler.lock(); + if (ptr) + { + ptr->setResult(ptr->get()); + } + } +} + +void IconResourceHandler::init(std::shared_ptr &ptr) +{ + m_iconHandlers.append(std::dynamic_pointer_cast(ptr)); + // we always have a result, so lets report it now! + setResult(get()); +} + +QVariant IconResourceHandler::get() const +{ + return XdgIcon::fromTheme(m_key); +} diff --git a/api/dead/src/handlers/IconResourceHandler.h b/api/dead/src/handlers/IconResourceHandler.h new file mode 100644 index 00000000..0cc4de4f --- /dev/null +++ b/api/dead/src/handlers/IconResourceHandler.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +class 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 &ptr) override; + static QList> m_iconHandlers; + + QString m_key; + + // the workhorse, returns QVariantMap (filename => size) for m_key/m_theme + QVariant get() const; +}; diff --git a/api/dead/src/handlers/WebResourceHandler.cpp b/api/dead/src/handlers/WebResourceHandler.cpp new file mode 100644 index 00000000..757b870a --- /dev/null +++ b/api/dead/src/handlers/WebResourceHandler.cpp @@ -0,0 +1,68 @@ +#include "WebResourceHandler.h" + +#include "net/CacheDownload.h" +#include "net/HttpMetaCache.h" +#include "net/NetJob.h" +#include "FileSystem.h" +#include "Env.h" + +//FIXME: wrong. needs to be done elsewhere. +QMap WebResourceHandler::m_activeDownloads; + +WebResourceHandler::WebResourceHandler(const QString &url) + : QObject(), m_url(url) +{ + MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", url); + if (!entry->isStale()) + { + 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(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/api/dead/src/handlers/WebResourceHandler.h b/api/dead/src/handlers/WebResourceHandler.h new file mode 100644 index 00000000..54bef6a1 --- /dev/null +++ b/api/dead/src/handlers/WebResourceHandler.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +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 m_activeDownloads; + + QString m_url; + + void setResultFromFile(const QString &file); +}; diff --git a/api/dead/src/resources/Resource.cpp b/api/dead/src/resources/Resource.cpp new file mode 100644 index 00000000..e95675d7 --- /dev/null +++ b/api/dead/src/resources/Resource.cpp @@ -0,0 +1,155 @@ +#include "Resource.h" + +#include + +#include "ResourceObserver.h" +#include "ResourceHandler.h" + +// definition of static members of Resource +QMap(const QString &)>> Resource::m_handlers; +QMap, std::function> Resource::m_transfomers; +QMap> Resource::m_resources; + +struct NullResourceResult {}; +Q_DECLARE_METATYPE(NullResourceResult) +class NullResourceHandler : public ResourceHandler +{ +public: + explicit NullResourceHandler() + { + setResult(QVariant::fromValue(NullResourceResult())); + } +}; + +Resource::Resource(const QString &resource) + : m_resource(resource) +{ + if (!resource.isEmpty()) + { + // a valid resource identifier has the format : + 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); + } + else + { + m_handler = std::make_shared(); + } + + Q_ASSERT(m_handler); + m_handler->init(m_handler); + m_handler->setResource(this); +} +Resource::~Resource() +{ + qDeleteAll(m_observers); +} + +Resource::Ptr Resource::create(const QString &resource, Ptr placeholder) +{ + const QString storageId = storageIdentifier(resource, placeholder); + + // do we already have a resource? even if m_resources contains it it might not be valid any longer (weak_ptr) + Resource::Ptr ptr = m_resources.contains(storageId) + ? m_resources.value(storageId).lock() + : nullptr; + // did we have one? and is it still valid? + if (!ptr) + { + /* We don't want Resource to have a public constructor, but std::make_shared needs it, + * so we create a subclass of Resource here that exposes the constructor as public. + * The alternative would be making the allocator for std::make_shared a friend, but it + * differs between different STL implementations, so that would be a pain. + */ + struct ConstructableResource : public Resource + { + explicit ConstructableResource(const QString &resource) + : Resource(resource) {} + }; + ptr = std::make_shared(resource); + ptr->m_placeholder = placeholder; + m_resources.insert(storageId, 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(); // ask the observer to poll us immediently, we might already have data + return shared_from_this(); // allow chaining +} +Resource::Ptr Resource::applyTo(QObject *target, const char *property) +{ + // the cast to ResourceObserver* is required to ensure the right overload gets choosen, + // since QObjectResourceObserver also inherits from QObject + return applyTo(static_cast(new QObjectResourceObserver(target, property))); +} + +QVariant Resource::getResourceInternal(const int typeId) const +{ + // no result (yet), but a placeholder? delegate to the placeholder. + 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); + + // do we have an explicit transformer? use it. + if (m_transfomers.contains(typePair)) + { + return m_transfomers.value(typePair)(variant); + } + else + { + // we do not have an explicit transformer, so we just pass the QVariant, which will automatically + // transform some types for us (different numbers to each other etc.) + 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); +} + +QString Resource::storageIdentifier(const QString &id, Resource::Ptr placeholder) +{ + if (placeholder) + { + return id + '#' + storageIdentifier(placeholder->m_resource, placeholder->m_placeholder); + } + else + { + return id; + } +} diff --git a/api/dead/src/resources/Resource.h b/api/dead/src/resources/Resource.h new file mode 100644 index 00000000..63e97b88 --- /dev/null +++ b/api/dead/src/resources/Resource.h @@ -0,0 +1,132 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "ResourceObserver.h" +#include "TypeMagic.h" + +#include "multimc_logic_export.h" + +class ResourceHandler; + +/** 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 Resource::Ptr! Copy and move constructors are disabled for a reason. + */ +class MULTIMC_LOGIC_EXPORT Resource : public std::enable_shared_from_this +{ + // only allow creation from Resource::create and disallow passing around non-pointers + explicit Resource(const QString &resource); + Resource(const Resource &) = delete; + Resource(Resource &&) = delete; +public: + using Ptr = std::shared_ptr; + + ~Resource(); + + /// The returned pointer needs to be stored until either Resource::applyTo or Resource::then is called, or it is passed as + /// a placeholder to Resource::create itself. + static Ptr create(const QString &resource, Ptr placeholder = nullptr); + + /// 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 + Ptr then(Func &&func) + { + // Arg will be the functions argument with references and cv-qualifiers (const, volatile) removed + using Arg = TypeMagic::CleanType::Argument>; + // Ret will be the functions return type + using Ret = typename TypeMagic::Function::ReturnType; + + // FunctionResourceObserver + return applyTo(new FunctionResourceObserver(std::forward(func))); + } + + /// Retrieve the currently active resource. If it's type is different from T a conversion will be attempted. + template + T getResource() const { return getResourceInternal(qMetaTypeId()).template value(); } + + /// @internal Used by ResourceObserver and ResourceProxyModel + QVariant getResourceInternal(const int typeId) const; + + /** Register a new ResourceHandler. T needs to inherit from ResourceHandler + * Usage: Resource::registerHandler("myid"); + */ + template + static void registerHandler(const QString &id) + { + m_handlers.insert(id, [](const QString &res) { return std::make_shared(res); }); + } + /** Register a new resource transformer + * Resource transformers are functions that are responsible for converting between different types, + * for example converting from a QByteArray to a QPixmap. They are registered "externally" because not + * all types might be available in this library, for example gui types like QPixmap. + * + * Usage: Resource::registerTransformer([](const InputType &type) { return OutputType(type); }); + * This assumes that OutputType has a constructor that takes InputType as an argument. More + * complicated transformers can of course also be registered. + * + * When a ResourceObserver requests a type that's different from the actual resource type, a matching + * transformer will be looked up from the list of transformers. + * @note Only one-stage transforms will be performed (you can't registerTransformers for QString => int + * and int => float and expect QString to automatically be transformed into a float. + */ + template + static void registerTransformer(Func &&func) + { + using Out = typename TypeMagic::Function::ReturnType; + using In = TypeMagic::CleanType::Argument>; + static_assert(!std::is_same::value, "It does not make sense to transform a value to itself"); + m_transfomers.insert(qMakePair(qMetaTypeId(), qMetaTypeId()), [func](const QVariant &in) + { + return QVariant::fromValue(func(in.value())); + }); + } + +private: // half private, implementation details + friend class ResourceHandler; + // the following three functions are called by ResourceHandlers + /** Notifies the observers. They will call Resource::getResourceInternal which will call ResourceHandler::result + * or delegate to it's placeholder. + */ + void reportResult(); + void reportFailure(const QString &reason); + void reportProgress(const int progress); + + friend class ResourceObserver; + /// Removes observer from the list of observers so that we don't attempt to notify something that doesn't exist + void notifyObserverDeleted(ResourceObserver *observer); + +private: // truly private + QList m_observers; + std::shared_ptr m_handler = nullptr; + Ptr m_placeholder = nullptr; + const QString m_resource; + + static QString storageIdentifier(const QString &id, Ptr placeholder = nullptr); + QString storageIdentifier() const; + + // a list of resource handler factories, registered using registerHandler + static QMap(const QString &)>> m_handlers; + // a list of resource transformers, registered using registerTransformer + static QMap, std::function> m_transfomers; + // a list of resources so that we can reuse them + static QMap> m_resources; +}; diff --git a/api/dead/src/resources/ResourceHandler.cpp b/api/dead/src/resources/ResourceHandler.cpp new file mode 100644 index 00000000..46a4422c --- /dev/null +++ b/api/dead/src/resources/ResourceHandler.cpp @@ -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); + } +} diff --git a/api/dead/src/resources/ResourceHandler.h b/api/dead/src/resources/ResourceHandler.h new file mode 100644 index 00000000..f09d8904 --- /dev/null +++ b/api/dead/src/resources/ResourceHandler.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "multimc_logic_export.h" + +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(""), where is the + * prefix of the resource ("web", "icon", etc.) + */ +class MULTIMC_LOGIC_EXPORT 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 + // we do this instead of inheriting from std::enable_shared_from_this + virtual void init(std::shared_ptr&) {} + + 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; +}; diff --git a/api/dead/src/resources/ResourceObserver.cpp b/api/dead/src/resources/ResourceObserver.cpp new file mode 100644 index 00000000..4f168fd2 --- /dev/null +++ b/api/dead/src/resources/ResourceObserver.cpp @@ -0,0 +1,55 @@ +#include "ResourceObserver.h" + +#include + +#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); +} diff --git a/api/dead/src/resources/ResourceObserver.h b/api/dead/src/resources/ResourceObserver.h new file mode 100644 index 00000000..c42e41ba --- /dev/null +++ b/api/dead/src/resources/ResourceObserver.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +#include +#include +#include "multimc_logic_export.h" + +class QVariant; +class Resource; + +/// Base class for things that can use a resource +class MULTIMC_LOGIC_EXPORT 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) { m_resource = resource; } + +protected: + template + T get() const { return getInternal(qMetaTypeId()).template value(); } + QVariant getInternal(const int typeId) const; + +private: + std::shared_ptr 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 MULTIMC_LOGIC_EXPORT QObjectResourceObserver : public QObject, public ResourceObserver +{ +public: + explicit QObjectResourceObserver(QObject *target, const char *property = nullptr); + + void resourceUpdated() override; + +private: + QObject *m_target; + QMetaProperty m_property; +}; + +/** Observer for functions, lambdas etc. + * Template arguments: + * * We need Ret and Arg in order to create the std::function + * * We need Func in order to std::forward the function + */ +template +class FunctionResourceObserver : public ResourceObserver +{ + std::function m_function; +public: + template + explicit FunctionResourceObserver(T &&func) + : m_function(std::forward(func)) {} + + void resourceUpdated() override + { + m_function(get()); + } +}; diff --git a/api/dead/src/resources/ResourceProxyModel.cpp b/api/dead/src/resources/ResourceProxyModel.cpp new file mode 100644 index 00000000..f026d9a9 --- /dev/null +++ b/api/dead/src/resources/ResourceProxyModel.cpp @@ -0,0 +1,89 @@ +#include "ResourceProxyModel.h" + +#include + +#include "Resource.h" +#include "ResourceObserver.h" + +class ModelResourceObserver : public ResourceObserver +{ +public: + explicit ModelResourceObserver(const QModelIndex &index, const int role) + : m_index(index), m_role(role) + { + qRegisterMetaType>("QVector"); + } + + void resourceUpdated() override + { + if (m_index.isValid()) + { + // the resource changed, pretend to be the model and notify the views of the update. they will re-poll the model which will return the new resource value + QMetaObject::invokeMethod(const_cast(m_index.model()), + "dataChanged", Qt::QueuedConnection, + Q_ARG(QModelIndex, m_index), Q_ARG(QModelIndex, m_index), Q_ARG(QVector, QVector() << 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); + // valid cell that's a Qt::DecorationRole and that contains a non-empty string + if (mapped.isValid() && role == Qt::DecorationRole && !mapToSource(proxyIndex).data(role).toString().isEmpty()) + { + // do we already have a resource for this index? + if (!m_resources.contains(mapped)) + { + Resource::Ptr placeholder; + const QVariant placeholderIdentifier = mapped.data(PlaceholderRole); + if (!placeholderIdentifier.isNull() && placeholderIdentifier.type() == QVariant::String) + { + placeholder = Resource::create(placeholderIdentifier.toString()); + } + + // create the Resource and apply the observer for models + Resource::Ptr res = Resource::create(mapToSource(proxyIndex).data(role).toString(), placeholder) + ->applyTo(new ModelResourceObserver(proxyIndex, role)); + + m_resources.insert(mapped, res); + } + + return m_resources.value(mapped)->getResourceInternal(m_resultTypeId); + } + // otherwise fall back to the source model + 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 &roles) + { + // invalidate resources so that they will be re-created + if (roles.contains(Qt::DecorationRole) || roles.contains(PlaceholderRole) || roles.isEmpty()) + { + const QItemSelectionRange range(tl, br); + for (const QModelIndex &index : range.indexes()) + { + m_resources.remove(index); + } + } + }); + } + QIdentityProxyModel::setSourceModel(model); +} diff --git a/api/dead/src/resources/ResourceProxyModel.h b/api/dead/src/resources/ResourceProxyModel.h new file mode 100644 index 00000000..98a3dbd1 --- /dev/null +++ b/api/dead/src/resources/ResourceProxyModel.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "multimc_logic_export.h" + +/// Convenience proxy model that transforms resource identifiers (strings) for Qt::DecorationRole into other types. +class MULTIMC_LOGIC_EXPORT ResourceProxyModel : public QIdentityProxyModel +{ + Q_OBJECT +public: + // resultTypeId is found using qMetaTypeId() + 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; + + /// Helper function, usage: m_view->setModel(ResourceProxyModel::mixin(m_model)); + template + static QAbstractItemModel *mixin(QAbstractItemModel *model) + { + ResourceProxyModel *proxy = new ResourceProxyModel(qMetaTypeId(), model); + proxy->setSourceModel(model); + return proxy; + } + +private: + // mutable because it needs to be available from the const data() + mutable QMap> m_resources; + + const int m_resultTypeId; +}; diff --git a/api/dead/test/tst_Resource.cpp b/api/dead/test/tst_Resource.cpp new file mode 100644 index 00000000..4bf41a03 --- /dev/null +++ b/api/dead/test/tst_Resource.cpp @@ -0,0 +1,116 @@ +#include +#include "TestUtil.h" + +#include "resources/Resource.h" +#include "resources/ResourceHandler.h" +#include "resources/ResourceObserver.h" + +class DummyStringResourceHandler : public ResourceHandler +{ +public: + explicit DummyStringResourceHandler(const QString &key) + : m_key(key) {} + + void init(std::shared_ptr &) override + { + setResult(m_key); + } + + QString m_key; +}; +class DummyObserver : public ResourceObserver +{ +public: + void resourceUpdated() override + { + values += get(); + } + + QStringList values; +}; +class DummyObserverObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString property MEMBER property) + +public: + explicit DummyObserverObject(QObject *parent = nullptr) : QObject(parent) {} + + QString property; +}; + +class ResourceTest : public QObject +{ + Q_OBJECT + private + slots: + void initTestCase() + { + Resource::registerHandler("dummy"); + } + void cleanupTestCase() + { + } + + void test_Then() + { + QString val; + Resource::create("dummy:test_Then") + ->then([&val](const QString &key) { val = key; }); + QCOMPARE(val, QStringLiteral("test_Then")); + } + void test_Object() + { + DummyObserver *observer = new DummyObserver; + Resource::create("dummy:test_Object")->applyTo(observer); + QCOMPARE(observer->values, QStringList() << "test_Object"); + } + void test_QObjectProperty() + { + DummyObserverObject *object = new DummyObserverObject; + Resource::create("dummy:test_QObjectProperty")->applyTo(object); + QCOMPARE(object->property, QStringLiteral("test_QObjectProperty")); + } + + void test_DontRequestPlaceholder() + { + // since dummy:asdf immediently gives a value we should not get the placeholder + Resource::create("dummy:asdf", Resource::create("dummy:fdsa")) + ->then([](const QString &key) { QCOMPARE(key, QStringLiteral("asdf")); }); + } + + void test_MergedResources() + { + auto r1 = Resource::create("dummy:asdf"); + auto r2 = Resource::create("dummy:asdf"); + auto r3 = Resource::create("dummy:fdsa"); + auto r4 = Resource::create("dummy:asdf"); + + QCOMPARE(r1, r2); + QCOMPARE(r1, r4); + QVERIFY(r1 != r3); + QVERIFY(r2 != r3); + QVERIFY(r4 != r3); + } + + void test_MergedResourceWithPlaceholder() + { + auto p1 = Resource::create("dummy:placeA"); + auto p2 = Resource::create("dummy:placeB"); + + auto r1 = Resource::create("dummy:asdf"); + auto r2 = Resource::create("dummy:asdf", p1); + auto r3 = Resource::create("dummy:asdf", p2); + auto r4 = Resource::create("dummy:asdf", p1); + + QCOMPARE(r2, r4); + QVERIFY(r1 != r2); + QVERIFY(r1 != r3); + QVERIFY(r1 != r4); + QVERIFY(r2 != r3); + } +}; + +QTEST_GUILESS_MAIN(ResourceTest) + +#include "tst_Resource.moc" diff --git a/api/logic/AbstractCommonModel.cpp b/api/logic/AbstractCommonModel.cpp deleted file mode 100644 index 71d75829..00000000 --- a/api/logic/AbstractCommonModel.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AbstractCommonModel.h" - -BaseAbstractCommonModel::BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent) - : QAbstractListModel(parent), m_orientation(orientation) -{ -} - -int BaseAbstractCommonModel::rowCount(const QModelIndex &parent) const -{ - return m_orientation == Qt::Horizontal ? entryCount() : size(); -} -int BaseAbstractCommonModel::columnCount(const QModelIndex &parent) const -{ - return m_orientation == Qt::Horizontal ? size() : entryCount(); -} -QVariant BaseAbstractCommonModel::data(const QModelIndex &index, int role) const -{ - if (!hasIndex(index.row(), index.column(), index.parent())) - { - return QVariant(); - } - const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - return formatData(i, role, get(i, entry, role)); -} -QVariant BaseAbstractCommonModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation != m_orientation && role == Qt::DisplayRole) - { - return entryTitle(section); - } - else - { - return QVariant(); - } -} -bool BaseAbstractCommonModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - const bool result = set(i, entry, role, sanetizeData(i, role, value)); - if (result) - { - emit dataChanged(index, index, QVector() << role); - } - return result; -} -Qt::ItemFlags BaseAbstractCommonModel::flags(const QModelIndex &index) const -{ - if (!hasIndex(index.row(), index.column(), index.parent())) - { - return Qt::NoItemFlags; - } - - const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); - if (canSet(entry)) - { - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; - } - else - { - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; - } -} - -void BaseAbstractCommonModel::notifyAboutToAddObject(const int at) -{ - if (m_orientation == Qt::Horizontal) - { - beginInsertColumns(QModelIndex(), at, at); - } - else - { - beginInsertRows(QModelIndex(), at, at); - } -} -void BaseAbstractCommonModel::notifyObjectAdded() -{ - if (m_orientation == Qt::Horizontal) - { - endInsertColumns(); - } - else - { - endInsertRows(); - } -} -void BaseAbstractCommonModel::notifyAboutToRemoveObject(const int at) -{ - if (m_orientation == Qt::Horizontal) - { - beginRemoveColumns(QModelIndex(), at, at); - } - else - { - beginRemoveRows(QModelIndex(), at, at); - } -} -void BaseAbstractCommonModel::notifyObjectRemoved() -{ - if (m_orientation == Qt::Horizontal) - { - endRemoveColumns(); - } - else - { - endRemoveRows(); - } -} - -void BaseAbstractCommonModel::notifyBeginReset() -{ - beginResetModel(); -} -void BaseAbstractCommonModel::notifyEndReset() -{ - endResetModel(); -} diff --git a/api/logic/AbstractCommonModel.h b/api/logic/AbstractCommonModel.h deleted file mode 100644 index 31b86a23..00000000 --- a/api/logic/AbstractCommonModel.h +++ /dev/null @@ -1,462 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -class BaseAbstractCommonModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent = nullptr); - - // begin QAbstractItemModel interface - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - // end QAbstractItemModel interface - - virtual int size() const = 0; - virtual int entryCount() const = 0; - - virtual QVariant formatData(const int index, int role, const QVariant &data) const { return data; } - virtual QVariant sanetizeData(const int index, int role, const QVariant &data) const { return data; } - -protected: - virtual QVariant get(const int index, const int entry, const int role) const = 0; - virtual bool set(const int index, const int entry, const int role, const QVariant &value) = 0; - virtual bool canSet(const int entry) const = 0; - virtual QString entryTitle(const int entry) const = 0; - - void notifyAboutToAddObject(const int at); - void notifyObjectAdded(); - void notifyAboutToRemoveObject(const int at); - void notifyObjectRemoved(); - void notifyBeginReset(); - void notifyEndReset(); - - const Qt::Orientation m_orientation; -}; - -template -class AbstractCommonModel : public BaseAbstractCommonModel -{ -public: - explicit AbstractCommonModel(const Qt::Orientation orientation) - : BaseAbstractCommonModel(orientation) {} - virtual ~AbstractCommonModel() {} - - int size() const override { return m_objects.size(); } - int entryCount() const override { return m_entries.size(); } - - void append(const Object &object) - { - notifyAboutToAddObject(size()); - m_objects.append(object); - notifyObjectAdded(); - } - void prepend(const Object &object) - { - notifyAboutToAddObject(0); - m_objects.prepend(object); - notifyObjectAdded(); - } - void insert(const Object &object, const int index) - { - if (index >= size()) - { - prepend(object); - } - else if (index <= 0) - { - append(object); - } - else - { - notifyAboutToAddObject(index); - m_objects.insert(index, object); - notifyObjectAdded(); - } - } - void remove(const int index) - { - notifyAboutToRemoveObject(index); - m_objects.removeAt(index); - notifyObjectRemoved(); - } - Object get(const int index) const - { - return m_objects.at(index); - } - -private: - friend class CommonModel; - QVariant get(const int index, const int entry, const int role) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return QVariant(); - } - return m_entries[entry].second.value(role)->get(m_objects.at(index)); - } - bool set(const int index, const int entry, const int role, const QVariant &value) override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(role); - if (!e->canSet()) - { - return false; - } - e->set(m_objects[index], value); - return true; - } - bool canSet(const int entry) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(Qt::EditRole); - return e->canSet(); - } - - QString entryTitle(const int entry) const override - { - return m_entries.at(entry).first; - } - -private: - struct IEntry - { - virtual ~IEntry() {} - virtual void set(Object &object, const QVariant &value) = 0; - virtual QVariant get(const Object &object) const = 0; - virtual bool canSet() const = 0; - }; - template - struct VariableEntry : public IEntry - { - typedef T (Object::*Member); - - explicit VariableEntry(Member member) - : m_member(member) {} - - void set(Object &object, const QVariant &value) override - { - object.*m_member = value.value(); - } - QVariant get(const Object &object) const override - { - return QVariant::fromValue(object.*m_member); - } - bool canSet() const override { return true; } - - private: - Member m_member; - }; - template - struct FunctionEntry : public IEntry - { - typedef T (Object::*Getter)() const; - typedef void (Object::*Setter)(T); - - explicit FunctionEntry(Getter getter, Setter setter) - : m_getter(m_getter), m_setter(m_setter) {} - - void set(Object &object, const QVariant &value) override - { - object.*m_setter(value.value()); - } - QVariant get(const Object &object) const override - { - return QVariant::fromValue(object.*m_getter()); - } - bool canSet() const override { return !!m_setter; } - - private: - Getter m_getter; - Setter m_setter; - }; - - QList m_objects; - QVector>> m_entries; - - void addEntryInternal(IEntry *e, const int entry, const int role) - { - if (m_entries.size() <= entry) - { - m_entries.resize(entry + 1); - } - m_entries[entry].second.insert(role, e); - } - -protected: - template - typename std::enable_if::value && std::is_member_function_pointer::value, void>::type - addEntry(Getter getter, Setter setter, const int entry, const int role) - { - addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(Getter getter, const int entry, const int role) - { - addEntryInternal(new FunctionEntry::type>(getter, nullptr), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(T (Object::*member), const int entry, const int role) - { - addEntryInternal(new VariableEntry(member), entry, role); - } - - void setEntryTitle(const int entry, const QString &title) - { - m_entries[entry].first = title; - } -}; -template -class AbstractCommonModel : public BaseAbstractCommonModel -{ -public: - explicit AbstractCommonModel(const Qt::Orientation orientation) - : BaseAbstractCommonModel(orientation) {} - virtual ~AbstractCommonModel() - { - qDeleteAll(m_objects); - } - - int size() const override { return m_objects.size(); } - int entryCount() const override { return m_entries.size(); } - - void append(Object *object) - { - notifyAboutToAddObject(size()); - m_objects.append(object); - notifyObjectAdded(); - } - void prepend(Object *object) - { - notifyAboutToAddObject(0); - m_objects.prepend(object); - notifyObjectAdded(); - } - void insert(Object *object, const int index) - { - if (index >= size()) - { - prepend(object); - } - else if (index <= 0) - { - append(object); - } - else - { - notifyAboutToAddObject(index); - m_objects.insert(index, object); - notifyObjectAdded(); - } - } - void remove(const int index) - { - notifyAboutToRemoveObject(index); - m_objects.removeAt(index); - notifyObjectRemoved(); - } - Object *get(const int index) const - { - return m_objects.at(index); - } - int find(Object * const obj) const - { - return m_objects.indexOf(obj); - } - - QList getAll() const - { - return m_objects; - } - -private: - friend class CommonModel; - QVariant get(const int index, const int entry, const int role) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return QVariant(); - } - return m_entries[entry].second.value(role)->get(m_objects.at(index)); - } - bool set(const int index, const int entry, const int role, const QVariant &value) override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(role)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(role); - if (!e->canSet()) - { - return false; - } - e->set(m_objects[index], value); - return true; - } - bool canSet(const int entry) const override - { - if (m_entries.size() < entry || !m_entries[entry].second.contains(Qt::EditRole)) - { - return false; - } - IEntry *e = m_entries[entry].second.value(Qt::EditRole); - return e->canSet(); - } - - QString entryTitle(const int entry) const override - { - return m_entries.at(entry).first; - } - -private: - struct IEntry - { - virtual ~IEntry() {} - virtual void set(Object *object, const QVariant &value) = 0; - virtual QVariant get(Object *object) const = 0; - virtual bool canSet() const = 0; - }; - template - struct VariableEntry : public IEntry - { - typedef T (Object::*Member); - - explicit VariableEntry(Member member) - : m_member(member) {} - - void set(Object *object, const QVariant &value) override - { - object->*m_member = value.value(); - } - QVariant get(Object *object) const override - { - return QVariant::fromValue(object->*m_member); - } - bool canSet() const override { return true; } - - private: - Member m_member; - }; - template - struct FunctionEntry : public IEntry - { - typedef T (Object::*Getter)() const; - typedef void (Object::*Setter)(T); - - explicit FunctionEntry(Getter getter, Setter setter) - : m_getter(getter), m_setter(setter) {} - - void set(Object *object, const QVariant &value) override - { - (object->*m_setter)(value.value()); - } - QVariant get(Object *object) const override - { - return QVariant::fromValue((object->*m_getter)()); - } - bool canSet() const override { return !!m_setter; } - - private: - Getter m_getter; - Setter m_setter; - }; - template - struct LambdaEntry : public IEntry - { - using Getter = std::function; - - explicit LambdaEntry(Getter getter) - : m_getter(getter) {} - - void set(Object *object, const QVariant &value) override {} - QVariant get(Object *object) const override - { - return QVariant::fromValue(m_getter(object)); - } - bool canSet() const override { return false; } - - private: - Getter m_getter; - }; - - QList m_objects; - QVector>> m_entries; - - void addEntryInternal(IEntry *e, const int entry, const int role) - { - if (m_entries.size() <= entry) - { - m_entries.resize(entry + 1); - } - m_entries[entry].second.insert(role, e); - } - -protected: - template - typename std::enable_if::value && std::is_member_function_pointer::value, void>::type - addEntry(const int entry, const int role, Getter getter, Setter setter) - { - addEntryInternal(new FunctionEntry::type>(getter, setter), entry, role); - } - template - typename std::enable_if::Getter>::value, void>::type - addEntry(const int entry, const int role, typename FunctionEntry::Getter getter) - { - addEntryInternal(new FunctionEntry(getter, nullptr), entry, role); - } - template - typename std::enable_if::value, void>::type - addEntry(const int entry, const int role, T (Object::*member)) - { - addEntryInternal(new VariableEntry(member), entry, role); - } - template - void addEntry(const int entry, const int role, typename LambdaEntry::Getter lambda) - { - addEntryInternal(new LambdaEntry(lambda), entry, role); - } - - void setEntryTitle(const int entry, const QString &title) - { - m_entries[entry].first = title; - } - - void setAll(const QList objects) - { - notifyBeginReset(); - qDeleteAll(m_objects); - m_objects = objects; - notifyEndReset(); - } -}; diff --git a/api/logic/BaseConfigObject.cpp b/api/logic/BaseConfigObject.cpp deleted file mode 100644 index 3040ac2e..00000000 --- a/api/logic/BaseConfigObject.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BaseConfigObject.h" - -#include -#include -#include -#include - -#include "Exception.h" -#include "FileSystem.h" - -BaseConfigObject::BaseConfigObject(const QString &filename) - : m_filename(filename) -{ - m_saveTimer = new QTimer; - m_saveTimer->setSingleShot(true); - // cppcheck-suppress pureVirtualCall - QObject::connect(m_saveTimer, &QTimer::timeout, [this](){saveNow();}); - setSaveTimeout(250); - - m_initialReadTimer = new QTimer; - m_initialReadTimer->setSingleShot(true); - QObject::connect(m_initialReadTimer, &QTimer::timeout, [this]() - { - loadNow(); - m_initialReadTimer->deleteLater(); - m_initialReadTimer = 0; - }); - m_initialReadTimer->start(0); - - // cppcheck-suppress pureVirtualCall - m_appQuitConnection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this](){saveNow();}); -} -BaseConfigObject::~BaseConfigObject() -{ - delete m_saveTimer; - if (m_initialReadTimer) - { - delete m_initialReadTimer; - } - QObject::disconnect(m_appQuitConnection); -} - -void BaseConfigObject::setSaveTimeout(int msec) -{ - m_saveTimer->setInterval(msec); -} - -void BaseConfigObject::scheduleSave() -{ - m_saveTimer->stop(); - m_saveTimer->start(); -} -void BaseConfigObject::saveNow() -{ - if (m_saveTimer->isActive()) - { - m_saveTimer->stop(); - } - if (m_disableSaving) - { - return; - } - - try - { - FS::write(m_filename, doSave()); - } - catch (Exception & e) - { - qCritical() << e.cause(); - } -} -void BaseConfigObject::loadNow() -{ - if (m_saveTimer->isActive()) - { - saveNow(); - } - - try - { - doLoad(FS::read(m_filename)); - } - catch (Exception & e) - { - qWarning() << "Error loading" << m_filename << ":" << e.cause(); - } -} diff --git a/api/logic/BaseConfigObject.h b/api/logic/BaseConfigObject.h deleted file mode 100644 index 1c96b3d1..00000000 --- a/api/logic/BaseConfigObject.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2015 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -class QTimer; - -class BaseConfigObject -{ -public: - void setSaveTimeout(int msec); - -protected: - explicit BaseConfigObject(const QString &filename); - virtual ~BaseConfigObject(); - - // cppcheck-suppress pureVirtualCall - virtual QByteArray doSave() const = 0; - virtual void doLoad(const QByteArray &data) = 0; - - void setSavingDisabled(bool savingDisabled) { m_disableSaving = savingDisabled; } - - QString fileName() const { return m_filename; } - -public: - void scheduleSave(); - void saveNow(); - void loadNow(); - -private: - QTimer *m_saveTimer; - QTimer *m_initialReadTimer; - QString m_filename; - QMetaObject::Connection m_appQuitConnection; - bool m_disableSaving = false; -}; diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 317627d5..a7013c9d 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -16,11 +16,6 @@ set(LOGIC_SOURCES MMCZip.cpp MMCStrings.h MMCStrings.cpp - BaseConfigObject.h - BaseConfigObject.cpp - AbstractCommonModel.h - AbstractCommonModel.cpp - TypeMagic.h # Prefix tree where node names are strings between separators SeparatorPrefixTree.h @@ -47,16 +42,6 @@ set(LOGIC_SOURCES # a smart pointer wrapper intended for safer use with Qt signal/slot mechanisms QObjectPtr.h - # Resources - resources/Resource.cpp - resources/Resource.h - resources/ResourceHandler.cpp - resources/ResourceHandler.h - resources/ResourceObserver.cpp - resources/ResourceObserver.h - resources/ResourceProxyModel.h - resources/ResourceProxyModel.cpp - # Path matchers pathmatcher/FSTreeMatcher.h pathmatcher/IPathMatcher.h diff --git a/api/logic/TypeMagic.h b/api/logic/TypeMagic.h deleted file mode 100644 index fa9d12a9..00000000 --- a/api/logic/TypeMagic.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -namespace TypeMagic -{ -/** "Cleans" the given type T by stripping references (&) and cv-qualifiers (const, volatile) from it - * const int => int - * QString & => QString - * const unsigned long long & => unsigned long long - * - * Usage: - * using Cleaned = Detail::CleanType; - * static_assert(std::is_same, "Cleaned == int"); - */ -// the order of remove_cv and remove_reference matters! -template -using CleanType = typename std::remove_cv::type>::type; - -/// For functors (structs with operator()), including lambdas, which in **most** cases are functors -/// "Calls" Function or Function -template struct Function : public Function {}; -/// For function pointers (&function), including static members (&Class::member) -template struct Function : public Function {}; -/// Default specialization used by others. -template struct Function -{ - using ReturnType = Ret; - using Argument = Arg; -}; -/// For member functions. Also used by the lambda overload if the lambda captures [this] -template struct Function : public Function {}; -template struct Function : public Function {}; -/// Overload for references -template struct Function : public Function {}; -/// Overload for rvalues -template struct Function : public Function {}; -// for more info: https://functionalcpp.wordpress.com/2013/08/05/function-traits/ -} diff --git a/api/logic/resources/Resource.cpp b/api/logic/resources/Resource.cpp deleted file mode 100644 index e95675d7..00000000 --- a/api/logic/resources/Resource.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "Resource.h" - -#include - -#include "ResourceObserver.h" -#include "ResourceHandler.h" - -// definition of static members of Resource -QMap(const QString &)>> Resource::m_handlers; -QMap, std::function> Resource::m_transfomers; -QMap> Resource::m_resources; - -struct NullResourceResult {}; -Q_DECLARE_METATYPE(NullResourceResult) -class NullResourceHandler : public ResourceHandler -{ -public: - explicit NullResourceHandler() - { - setResult(QVariant::fromValue(NullResourceResult())); - } -}; - -Resource::Resource(const QString &resource) - : m_resource(resource) -{ - if (!resource.isEmpty()) - { - // a valid resource identifier has the format : - 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); - } - else - { - m_handler = std::make_shared(); - } - - Q_ASSERT(m_handler); - m_handler->init(m_handler); - m_handler->setResource(this); -} -Resource::~Resource() -{ - qDeleteAll(m_observers); -} - -Resource::Ptr Resource::create(const QString &resource, Ptr placeholder) -{ - const QString storageId = storageIdentifier(resource, placeholder); - - // do we already have a resource? even if m_resources contains it it might not be valid any longer (weak_ptr) - Resource::Ptr ptr = m_resources.contains(storageId) - ? m_resources.value(storageId).lock() - : nullptr; - // did we have one? and is it still valid? - if (!ptr) - { - /* We don't want Resource to have a public constructor, but std::make_shared needs it, - * so we create a subclass of Resource here that exposes the constructor as public. - * The alternative would be making the allocator for std::make_shared a friend, but it - * differs between different STL implementations, so that would be a pain. - */ - struct ConstructableResource : public Resource - { - explicit ConstructableResource(const QString &resource) - : Resource(resource) {} - }; - ptr = std::make_shared(resource); - ptr->m_placeholder = placeholder; - m_resources.insert(storageId, 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(); // ask the observer to poll us immediently, we might already have data - return shared_from_this(); // allow chaining -} -Resource::Ptr Resource::applyTo(QObject *target, const char *property) -{ - // the cast to ResourceObserver* is required to ensure the right overload gets choosen, - // since QObjectResourceObserver also inherits from QObject - return applyTo(static_cast(new QObjectResourceObserver(target, property))); -} - -QVariant Resource::getResourceInternal(const int typeId) const -{ - // no result (yet), but a placeholder? delegate to the placeholder. - 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); - - // do we have an explicit transformer? use it. - if (m_transfomers.contains(typePair)) - { - return m_transfomers.value(typePair)(variant); - } - else - { - // we do not have an explicit transformer, so we just pass the QVariant, which will automatically - // transform some types for us (different numbers to each other etc.) - 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); -} - -QString Resource::storageIdentifier(const QString &id, Resource::Ptr placeholder) -{ - if (placeholder) - { - return id + '#' + storageIdentifier(placeholder->m_resource, placeholder->m_placeholder); - } - else - { - return id; - } -} diff --git a/api/logic/resources/Resource.h b/api/logic/resources/Resource.h deleted file mode 100644 index 63e97b88..00000000 --- a/api/logic/resources/Resource.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "ResourceObserver.h" -#include "TypeMagic.h" - -#include "multimc_logic_export.h" - -class ResourceHandler; - -/** 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 Resource::Ptr! Copy and move constructors are disabled for a reason. - */ -class MULTIMC_LOGIC_EXPORT Resource : public std::enable_shared_from_this -{ - // only allow creation from Resource::create and disallow passing around non-pointers - explicit Resource(const QString &resource); - Resource(const Resource &) = delete; - Resource(Resource &&) = delete; -public: - using Ptr = std::shared_ptr; - - ~Resource(); - - /// The returned pointer needs to be stored until either Resource::applyTo or Resource::then is called, or it is passed as - /// a placeholder to Resource::create itself. - static Ptr create(const QString &resource, Ptr placeholder = nullptr); - - /// 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 - Ptr then(Func &&func) - { - // Arg will be the functions argument with references and cv-qualifiers (const, volatile) removed - using Arg = TypeMagic::CleanType::Argument>; - // Ret will be the functions return type - using Ret = typename TypeMagic::Function::ReturnType; - - // FunctionResourceObserver - return applyTo(new FunctionResourceObserver(std::forward(func))); - } - - /// Retrieve the currently active resource. If it's type is different from T a conversion will be attempted. - template - T getResource() const { return getResourceInternal(qMetaTypeId()).template value(); } - - /// @internal Used by ResourceObserver and ResourceProxyModel - QVariant getResourceInternal(const int typeId) const; - - /** Register a new ResourceHandler. T needs to inherit from ResourceHandler - * Usage: Resource::registerHandler("myid"); - */ - template - static void registerHandler(const QString &id) - { - m_handlers.insert(id, [](const QString &res) { return std::make_shared(res); }); - } - /** Register a new resource transformer - * Resource transformers are functions that are responsible for converting between different types, - * for example converting from a QByteArray to a QPixmap. They are registered "externally" because not - * all types might be available in this library, for example gui types like QPixmap. - * - * Usage: Resource::registerTransformer([](const InputType &type) { return OutputType(type); }); - * This assumes that OutputType has a constructor that takes InputType as an argument. More - * complicated transformers can of course also be registered. - * - * When a ResourceObserver requests a type that's different from the actual resource type, a matching - * transformer will be looked up from the list of transformers. - * @note Only one-stage transforms will be performed (you can't registerTransformers for QString => int - * and int => float and expect QString to automatically be transformed into a float. - */ - template - static void registerTransformer(Func &&func) - { - using Out = typename TypeMagic::Function::ReturnType; - using In = TypeMagic::CleanType::Argument>; - static_assert(!std::is_same::value, "It does not make sense to transform a value to itself"); - m_transfomers.insert(qMakePair(qMetaTypeId(), qMetaTypeId()), [func](const QVariant &in) - { - return QVariant::fromValue(func(in.value())); - }); - } - -private: // half private, implementation details - friend class ResourceHandler; - // the following three functions are called by ResourceHandlers - /** Notifies the observers. They will call Resource::getResourceInternal which will call ResourceHandler::result - * or delegate to it's placeholder. - */ - void reportResult(); - void reportFailure(const QString &reason); - void reportProgress(const int progress); - - friend class ResourceObserver; - /// Removes observer from the list of observers so that we don't attempt to notify something that doesn't exist - void notifyObserverDeleted(ResourceObserver *observer); - -private: // truly private - QList m_observers; - std::shared_ptr m_handler = nullptr; - Ptr m_placeholder = nullptr; - const QString m_resource; - - static QString storageIdentifier(const QString &id, Ptr placeholder = nullptr); - QString storageIdentifier() const; - - // a list of resource handler factories, registered using registerHandler - static QMap(const QString &)>> m_handlers; - // a list of resource transformers, registered using registerTransformer - static QMap, std::function> m_transfomers; - // a list of resources so that we can reuse them - static QMap> m_resources; -}; diff --git a/api/logic/resources/ResourceHandler.cpp b/api/logic/resources/ResourceHandler.cpp deleted file mode 100644 index 46a4422c..00000000 --- a/api/logic/resources/ResourceHandler.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#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); - } -} diff --git a/api/logic/resources/ResourceHandler.h b/api/logic/resources/ResourceHandler.h deleted file mode 100644 index f09d8904..00000000 --- a/api/logic/resources/ResourceHandler.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include - -#include "multimc_logic_export.h" - -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(""), where is the - * prefix of the resource ("web", "icon", etc.) - */ -class MULTIMC_LOGIC_EXPORT 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 - // we do this instead of inheriting from std::enable_shared_from_this - virtual void init(std::shared_ptr&) {} - - 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; -}; diff --git a/api/logic/resources/ResourceObserver.cpp b/api/logic/resources/ResourceObserver.cpp deleted file mode 100644 index 4f168fd2..00000000 --- a/api/logic/resources/ResourceObserver.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "ResourceObserver.h" - -#include - -#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); -} diff --git a/api/logic/resources/ResourceObserver.h b/api/logic/resources/ResourceObserver.h deleted file mode 100644 index c42e41ba..00000000 --- a/api/logic/resources/ResourceObserver.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include "multimc_logic_export.h" - -class QVariant; -class Resource; - -/// Base class for things that can use a resource -class MULTIMC_LOGIC_EXPORT 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) { m_resource = resource; } - -protected: - template - T get() const { return getInternal(qMetaTypeId()).template value(); } - QVariant getInternal(const int typeId) const; - -private: - std::shared_ptr 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 MULTIMC_LOGIC_EXPORT QObjectResourceObserver : public QObject, public ResourceObserver -{ -public: - explicit QObjectResourceObserver(QObject *target, const char *property = nullptr); - - void resourceUpdated() override; - -private: - QObject *m_target; - QMetaProperty m_property; -}; - -/** Observer for functions, lambdas etc. - * Template arguments: - * * We need Ret and Arg in order to create the std::function - * * We need Func in order to std::forward the function - */ -template -class FunctionResourceObserver : public ResourceObserver -{ - std::function m_function; -public: - template - explicit FunctionResourceObserver(T &&func) - : m_function(std::forward(func)) {} - - void resourceUpdated() override - { - m_function(get()); - } -}; diff --git a/api/logic/resources/ResourceProxyModel.cpp b/api/logic/resources/ResourceProxyModel.cpp deleted file mode 100644 index f026d9a9..00000000 --- a/api/logic/resources/ResourceProxyModel.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "ResourceProxyModel.h" - -#include - -#include "Resource.h" -#include "ResourceObserver.h" - -class ModelResourceObserver : public ResourceObserver -{ -public: - explicit ModelResourceObserver(const QModelIndex &index, const int role) - : m_index(index), m_role(role) - { - qRegisterMetaType>("QVector"); - } - - void resourceUpdated() override - { - if (m_index.isValid()) - { - // the resource changed, pretend to be the model and notify the views of the update. they will re-poll the model which will return the new resource value - QMetaObject::invokeMethod(const_cast(m_index.model()), - "dataChanged", Qt::QueuedConnection, - Q_ARG(QModelIndex, m_index), Q_ARG(QModelIndex, m_index), Q_ARG(QVector, QVector() << 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); - // valid cell that's a Qt::DecorationRole and that contains a non-empty string - if (mapped.isValid() && role == Qt::DecorationRole && !mapToSource(proxyIndex).data(role).toString().isEmpty()) - { - // do we already have a resource for this index? - if (!m_resources.contains(mapped)) - { - Resource::Ptr placeholder; - const QVariant placeholderIdentifier = mapped.data(PlaceholderRole); - if (!placeholderIdentifier.isNull() && placeholderIdentifier.type() == QVariant::String) - { - placeholder = Resource::create(placeholderIdentifier.toString()); - } - - // create the Resource and apply the observer for models - Resource::Ptr res = Resource::create(mapToSource(proxyIndex).data(role).toString(), placeholder) - ->applyTo(new ModelResourceObserver(proxyIndex, role)); - - m_resources.insert(mapped, res); - } - - return m_resources.value(mapped)->getResourceInternal(m_resultTypeId); - } - // otherwise fall back to the source model - 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 &roles) - { - // invalidate resources so that they will be re-created - if (roles.contains(Qt::DecorationRole) || roles.contains(PlaceholderRole) || roles.isEmpty()) - { - const QItemSelectionRange range(tl, br); - for (const QModelIndex &index : range.indexes()) - { - m_resources.remove(index); - } - } - }); - } - QIdentityProxyModel::setSourceModel(model); -} diff --git a/api/logic/resources/ResourceProxyModel.h b/api/logic/resources/ResourceProxyModel.h deleted file mode 100644 index 98a3dbd1..00000000 --- a/api/logic/resources/ResourceProxyModel.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -#include "multimc_logic_export.h" - -/// Convenience proxy model that transforms resource identifiers (strings) for Qt::DecorationRole into other types. -class MULTIMC_LOGIC_EXPORT ResourceProxyModel : public QIdentityProxyModel -{ - Q_OBJECT -public: - // resultTypeId is found using qMetaTypeId() - 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; - - /// Helper function, usage: m_view->setModel(ResourceProxyModel::mixin(m_model)); - template - static QAbstractItemModel *mixin(QAbstractItemModel *model) - { - ResourceProxyModel *proxy = new ResourceProxyModel(qMetaTypeId(), model); - proxy->setSourceModel(model); - return proxy; - } - -private: - // mutable because it needs to be available from the const data() - mutable QMap> m_resources; - - const int m_resultTypeId; -}; diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index f1a95a8a..15934e3e 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -86,12 +86,6 @@ 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/MainWindow.cpp b/application/MainWindow.cpp index 97c0b02a..1dcc5982 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 24e71fa0..b157c83d 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -45,9 +45,6 @@ #include "settings/Setting.h" #include "trans/TranslationDownloader.h" -#include "resources/Resource.h" -#include "handlers/IconResourceHandler.h" -#include "handlers/WebResourceHandler.h" #include "minecraft/ftb/FTBPlugin.h" @@ -347,19 +344,6 @@ void MultiMC::initIcons() { m_icons->directoryChanged(value.toString()); }); - - //FIXME: none of this should be here. - Resource::registerHandler("web"); - Resource::registerHandler("icon"); - - 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))); - }); } @@ -912,7 +896,6 @@ FAILED: void MultiMC::setIconTheme(const QString& name) { XdgIcon::setThemeName(name); - IconResourceHandler::setTheme(name); } QIcon MultiMC::getThemedIcon(const QString& name) diff --git a/application/handlers/IconResourceHandler.cpp b/application/handlers/IconResourceHandler.cpp deleted file mode 100644 index b03553fd..00000000 --- a/application/handlers/IconResourceHandler.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "IconResourceHandler.h" -#include - -#include -#include - -QList> IconResourceHandler::m_iconHandlers; - -IconResourceHandler::IconResourceHandler(const QString &key) - : m_key(key) -{ -} - -void IconResourceHandler::setTheme(const QString &theme) -{ - // notify everyone - for (auto handler : m_iconHandlers) - { - std::shared_ptr ptr = handler.lock(); - if (ptr) - { - ptr->setResult(ptr->get()); - } - } -} - -void IconResourceHandler::init(std::shared_ptr &ptr) -{ - m_iconHandlers.append(std::dynamic_pointer_cast(ptr)); - // we always have a result, so lets report it now! - setResult(get()); -} - -QVariant IconResourceHandler::get() const -{ - return XdgIcon::fromTheme(m_key); -} diff --git a/application/handlers/IconResourceHandler.h b/application/handlers/IconResourceHandler.h deleted file mode 100644 index 0cc4de4f..00000000 --- a/application/handlers/IconResourceHandler.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -class 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 &ptr) override; - static QList> m_iconHandlers; - - QString m_key; - - // the workhorse, returns QVariantMap (filename => size) for m_key/m_theme - QVariant get() const; -}; diff --git a/application/handlers/WebResourceHandler.cpp b/application/handlers/WebResourceHandler.cpp deleted file mode 100644 index 757b870a..00000000 --- a/application/handlers/WebResourceHandler.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "WebResourceHandler.h" - -#include "net/CacheDownload.h" -#include "net/HttpMetaCache.h" -#include "net/NetJob.h" -#include "FileSystem.h" -#include "Env.h" - -//FIXME: wrong. needs to be done elsewhere. -QMap WebResourceHandler::m_activeDownloads; - -WebResourceHandler::WebResourceHandler(const QString &url) - : QObject(), m_url(url) -{ - MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", url); - if (!entry->isStale()) - { - 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(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/application/handlers/WebResourceHandler.h b/application/handlers/WebResourceHandler.h deleted file mode 100644 index 54bef6a1..00000000 --- a/application/handlers/WebResourceHandler.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -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 m_activeDownloads; - - QString m_url; - - void setResultFromFile(const QString &file); -}; diff --git a/cmake/Coverage.cmake b/cmake/Coverage.cmake deleted file mode 100644 index 28efbf1c..00000000 --- a/cmake/Coverage.cmake +++ /dev/null @@ -1,13 +0,0 @@ -if(__COVERAGE_CMAKE__) - return() -endif() -set(__COVERAGE_CMAKE__ TRUE) - -if(MultiMC_CODE_COVERAGE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --coverage") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 --coverage") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 --coverage") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 --coverage") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") - set(CMAKE_BUILD_TYPE "Debug") -endif(MultiMC_CODE_COVERAGE) diff --git a/cmake/Coverity.cmake b/cmake/Coverity.cmake deleted file mode 100644 index 1fcec86f..00000000 --- a/cmake/Coverity.cmake +++ /dev/null @@ -1,35 +0,0 @@ -if(__COVERITY_CMAKE__) - return() -endif() -set(__COVERITY_CMAKE__ TRUE) - -include(GitFunctions) - -git_run(COMMAND config --get user.email DEFAULT "" OUTPUT_VAR GIT_EMAIL) -git_run(COMMAND describe DEFAULT "" OUTPUT_VAR GIT_VERSION) - -set(MultiMC_COVERITY_TOKEN "" CACHE STRING "Coverity access token") -set(MultiMC_COVERITY_EMAIL "${GIT_EMAIL}" CACHE STRING "Coverity email") - -set(MultiMC_COVERITY_TOOLS_DIR "${CMAKE_BINARY_DIR}/coverity_tools" CACHE PATH "Path to the coverity tools") - -find_program(CURL_EXECUTABLE NAMES curl PATHS /usr/bin) - -if(NOT CURL_EXECUTABLE STREQUAL "" AND NOT MultiMC_COVERITY_TOKEN STREQUAL "" AND NOT MultiMC_COVERITY_EMAIL STREQUAL "") - add_custom_target(coverity_configure - COMMAND ${MultiMC_COVERITY_TOOLS_DIR}/bin/cov-configure --comptype gcc --compiler ${CMAKE_C_COMPILER} - ) - add_custom_target(coverity_create_tarball - COMMAND ${CMAKE_COMMAND} -E echo "Cleaning..." && ${CMAKE_MAKE_PROGRAM} clean - COMMAND ${CMAKE_COMMAND} -E echo "Building..." && ${MultiMC_COVERITY_TOOLS_DIR}/bin/cov-build --dir cov-int ${CMAKE_MAKE_PROGRAM} -j3 - COMMAND ${CMAKE_COMMAND} -E echo "Creating tarball..." && ${CMAKE_COMMAND} -E tar cfz multimc_coverity.tgz cov-int/ - COMMENT "Creating coverity build..." - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - add_custom_target(coverity_upload - COMMAND ${CURL_EXECUTABLE} --form project=02JanDal/MultiMC5 --form token=${MultiMC_COVERITY_TOKEN} --form email=${MultiMC_COVERITY_EMAIL} --form file=@multimc_coverity.tgz --form version=${MultiMC_GIT_COMMIT} --form description=${GIT_VERSION} http://scan5.coverity.com/cgi-bin/upload.py - DEPENDS coverity_create_tarball - COMMENT "Uploading to coverity..." - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) -endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 409462a2..12fa4108 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,7 +20,7 @@ macro(add_unit_test name) add_test(NAME ${name} COMMAND tst_${name}) endmacro() -# Tests START # +# Tests BEGIN # add_unit_test(gradlespecifier tst_gradlespecifier.cpp) add_unit_test(userutils tst_userutils.cpp) @@ -32,7 +32,7 @@ add_unit_test(UpdateChecker tst_UpdateChecker.cpp) add_unit_test(DownloadTask tst_DownloadTask.cpp) add_unit_test(filematchers tst_filematchers.cpp) add_unit_test(ModList tst_ModList.cpp) -add_unit_test(Resource tst_Resource.cpp) +# add_unit_test(Resource tst_Resource.cpp) add_unit_test(GZip tst_GZip.cpp) add_unit_test(JavaVersion tst_JavaVersion.cpp) add_unit_test(ParseUtils tst_ParseUtils.cpp) @@ -44,62 +44,6 @@ add_unit_test(WonkoIndex tst_WonkoIndex.cpp) # Tests END # -set(COVERAGE_SOURCE_DIRS - ${MMC_SRC}/logic/* - ${MMC_SRC}/logic/auth/* - ${MMC_SRC}/logic/auth/flows/* - ${MMC_SRC}/logic/lists/* - ${MMC_SRC}/logic/net/* - ${MMC_SRC}/logic/tasks/* - ${MMC_SRC}/application/* - ${MMC_SRC}/application/dialogs/* - ${MMC_SRC}/application/widgets/* - ${MMC_SRC}/depends/settings/include/* - ${MMC_SRC}/depends/settings/src/* - ${MMC_SRC}/depends/util/include/* - ${MMC_SRC}/depends/util/src/* -) - -if(MultiMC_CODE_COVERAGE) - unset(MultiMC_RUN_TESTS) - unset(MultiMC_TEST_COVERAGE_FILES) - - foreach(test ${MultiMC_TESTS}) - add_custom_target(MultiMC_RUN_TEST_${test} - COMMAND lcov -d ${CMAKE_CURRENT_BINARY_DIR} -z -q # clean test - && lcov -d ${MMC_BIN} -z -q # clean common - && lcov -d ${MMC_BIN}/depends/settings/CMakeFiles/libSettings.dir -z -q # clean settings - && lcov -d ${MMC_BIN}/depends/utils/CMakeFiles/libUtil.dir -z -q # clean utils - && ${MMC_BIN}/${test} -o coverage_${test}.out,xml # run test - && lcov -q --checksum -b ${MMC_SRC} -d ${CMAKE_CURRENT_BINARY_DIR} -c -o coverage_${test}.info # generate for test - && lcov -q --checksum -b ${MMC_SRC} -d ${MMC_BIN} -c -o coverage_common.info # generate for common - && lcov -q --checksum -b ${MMC_SRC} -d ${MMC_BIN}/depends/settings/CMakeFiles/libSettings.dir -c -o coverage_settings.info # generate for settings - && lcov -q --checksum -b ${MMC_SRC} -d ${MMC_BIN}/depends/util/CMakeFiles/libUtil.dir -c -o coverage_utils.info # generate for utils - && lcov -q --checksum -b ${MMC_SRC} -d . - -a coverage_${test}.info -a coverage_common.info -a coverage_settings.info -a coverage_utils.info - -o coverage_${test}-combined.info # combine test and common - && lcov -q --checksum -b ${MMC_SRC} --list-full-path --extract coverage_${test}-combined.info ${COVERAGE_SOURCE_DIRS} -o coverage_${test}-stripped.info # strip - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - DEPENDS ${test} - COMMENT "Running ${test}..." - ) - list(APPEND MultiMC_TEST_COVERAGE_FILES coverage_${test}-stripped.info) - list(APPEND MultiMC_RUN_TESTS MultiMC_RUN_TEST_${test}) - endforeach(test) - - add_custom_target(MultiMC_GENERATE_COVERAGE - DEPENDS ${MultiMC_RUN_TESTS} - COMMENT "Generating coverage files..." - ) - add_custom_target(MultiMC_GENERATE_COVERAGE_HTML - COMMAND genhtml -t "MultiMC 5 Test Coverage" --num-spaces 4 --demangle-cpp --legend -o ${MMC_SRC}/html/coverage ${MultiMC_TEST_COVERAGE_FILES} - DEPENDS MultiMC_GENERATE_COVERAGE - COMMENT "Generating test coverage html..." - ) - add_custom_target(MultiMC_RUN_TESTS DEPENDS MultiMC_GENERATE_COVERAGE_HTML) -endif(MultiMC_CODE_COVERAGE) - set(MultiMC_TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data") set(MultiMC_TEST_DATA_PATH_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/data") diff --git a/tests/tst_Resource.cpp b/tests/tst_Resource.cpp deleted file mode 100644 index 4bf41a03..00000000 --- a/tests/tst_Resource.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include "TestUtil.h" - -#include "resources/Resource.h" -#include "resources/ResourceHandler.h" -#include "resources/ResourceObserver.h" - -class DummyStringResourceHandler : public ResourceHandler -{ -public: - explicit DummyStringResourceHandler(const QString &key) - : m_key(key) {} - - void init(std::shared_ptr &) override - { - setResult(m_key); - } - - QString m_key; -}; -class DummyObserver : public ResourceObserver -{ -public: - void resourceUpdated() override - { - values += get(); - } - - QStringList values; -}; -class DummyObserverObject : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString property MEMBER property) - -public: - explicit DummyObserverObject(QObject *parent = nullptr) : QObject(parent) {} - - QString property; -}; - -class ResourceTest : public QObject -{ - Q_OBJECT - private - slots: - void initTestCase() - { - Resource::registerHandler("dummy"); - } - void cleanupTestCase() - { - } - - void test_Then() - { - QString val; - Resource::create("dummy:test_Then") - ->then([&val](const QString &key) { val = key; }); - QCOMPARE(val, QStringLiteral("test_Then")); - } - void test_Object() - { - DummyObserver *observer = new DummyObserver; - Resource::create("dummy:test_Object")->applyTo(observer); - QCOMPARE(observer->values, QStringList() << "test_Object"); - } - void test_QObjectProperty() - { - DummyObserverObject *object = new DummyObserverObject; - Resource::create("dummy:test_QObjectProperty")->applyTo(object); - QCOMPARE(object->property, QStringLiteral("test_QObjectProperty")); - } - - void test_DontRequestPlaceholder() - { - // since dummy:asdf immediently gives a value we should not get the placeholder - Resource::create("dummy:asdf", Resource::create("dummy:fdsa")) - ->then([](const QString &key) { QCOMPARE(key, QStringLiteral("asdf")); }); - } - - void test_MergedResources() - { - auto r1 = Resource::create("dummy:asdf"); - auto r2 = Resource::create("dummy:asdf"); - auto r3 = Resource::create("dummy:fdsa"); - auto r4 = Resource::create("dummy:asdf"); - - QCOMPARE(r1, r2); - QCOMPARE(r1, r4); - QVERIFY(r1 != r3); - QVERIFY(r2 != r3); - QVERIFY(r4 != r3); - } - - void test_MergedResourceWithPlaceholder() - { - auto p1 = Resource::create("dummy:placeA"); - auto p2 = Resource::create("dummy:placeB"); - - auto r1 = Resource::create("dummy:asdf"); - auto r2 = Resource::create("dummy:asdf", p1); - auto r3 = Resource::create("dummy:asdf", p2); - auto r4 = Resource::create("dummy:asdf", p1); - - QCOMPARE(r2, r4); - QVERIFY(r1 != r2); - QVERIFY(r1 != r3); - QVERIFY(r1 != r4); - QVERIFY(r2 != r3); - } -}; - -QTEST_GUILESS_MAIN(ResourceTest) - -#include "tst_Resource.moc" diff --git a/wonkoclient/WonkoClient.cpp b/wonkoclient/WonkoClient.cpp index ca22d407..dd0dfae5 100644 --- a/wonkoclient/WonkoClient.cpp +++ b/wonkoclient/WonkoClient.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include "WonkoClient.h" WonkoClient &WonkoClient::getInstance() { -- cgit