NOISSUE delete dead code
This commit is contained in:
parent
eb747e08b7
commit
69f3ab019d
@ -1,3 +0,0 @@
|
|||||||
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.
|
|
@ -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<int>() << 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();
|
|
||||||
}
|
|
@ -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 <QAbstractListModel>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
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<typename Object>
|
|
||||||
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<typename T>
|
|
||||||
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<T>();
|
|
||||||
}
|
|
||||||
QVariant get(const Object &object) const override
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<T>(object.*m_member);
|
|
||||||
}
|
|
||||||
bool canSet() const override { return true; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Member m_member;
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
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<T>());
|
|
||||||
}
|
|
||||||
QVariant get(const Object &object) const override
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<T>(object.*m_getter());
|
|
||||||
}
|
|
||||||
bool canSet() const override { return !!m_setter; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Getter m_getter;
|
|
||||||
Setter m_setter;
|
|
||||||
};
|
|
||||||
|
|
||||||
QList<Object> m_objects;
|
|
||||||
QVector<QPair<QString, QMap<int, IEntry *>>> 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 Getter, typename Setter>
|
|
||||||
typename std::enable_if<std::is_member_function_pointer<Getter>::value && std::is_member_function_pointer<Getter>::value, void>::type
|
|
||||||
addEntry(Getter getter, Setter setter, const int entry, const int role)
|
|
||||||
{
|
|
||||||
addEntryInternal(new FunctionEntry<typename std::result_of<Getter>::type>(getter, setter), entry, role);
|
|
||||||
}
|
|
||||||
template<typename Getter>
|
|
||||||
typename std::enable_if<std::is_member_function_pointer<Getter>::value, void>::type
|
|
||||||
addEntry(Getter getter, const int entry, const int role)
|
|
||||||
{
|
|
||||||
addEntryInternal(new FunctionEntry<typename std::result_of<Getter>::type>(getter, nullptr), entry, role);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if<!std::is_member_function_pointer<T (Object::*)>::value, void>::type
|
|
||||||
addEntry(T (Object::*member), const int entry, const int role)
|
|
||||||
{
|
|
||||||
addEntryInternal(new VariableEntry<T>(member), entry, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setEntryTitle(const int entry, const QString &title)
|
|
||||||
{
|
|
||||||
m_entries[entry].first = title;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename Object>
|
|
||||||
class AbstractCommonModel<Object *> : 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<Object *> 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<typename T>
|
|
||||||
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<T>();
|
|
||||||
}
|
|
||||||
QVariant get(Object *object) const override
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<T>(object->*m_member);
|
|
||||||
}
|
|
||||||
bool canSet() const override { return true; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Member m_member;
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
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<T>());
|
|
||||||
}
|
|
||||||
QVariant get(Object *object) const override
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<T>((object->*m_getter)());
|
|
||||||
}
|
|
||||||
bool canSet() const override { return !!m_setter; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Getter m_getter;
|
|
||||||
Setter m_setter;
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct LambdaEntry : public IEntry
|
|
||||||
{
|
|
||||||
using Getter = std::function<T(Object *)>;
|
|
||||||
|
|
||||||
explicit LambdaEntry(Getter getter)
|
|
||||||
: m_getter(getter) {}
|
|
||||||
|
|
||||||
void set(Object *object, const QVariant &value) override {}
|
|
||||||
QVariant get(Object *object) const override
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<T>(m_getter(object));
|
|
||||||
}
|
|
||||||
bool canSet() const override { return false; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Getter m_getter;
|
|
||||||
};
|
|
||||||
|
|
||||||
QList<Object *> m_objects;
|
|
||||||
QVector<QPair<QString, QMap<int, IEntry *>>> 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 Getter, typename Setter>
|
|
||||||
typename std::enable_if<std::is_member_function_pointer<Getter>::value && std::is_member_function_pointer<Getter>::value, void>::type
|
|
||||||
addEntry(const int entry, const int role, Getter getter, Setter setter)
|
|
||||||
{
|
|
||||||
addEntryInternal(new FunctionEntry<typename std::result_of<Getter>::type>(getter, setter), entry, role);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if<std::is_member_function_pointer<typename FunctionEntry<T>::Getter>::value, void>::type
|
|
||||||
addEntry(const int entry, const int role, typename FunctionEntry<T>::Getter getter)
|
|
||||||
{
|
|
||||||
addEntryInternal(new FunctionEntry<T>(getter, nullptr), entry, role);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if<!std::is_member_function_pointer<T (Object::*)>::value, void>::type
|
|
||||||
addEntry(const int entry, const int role, T (Object::*member))
|
|
||||||
{
|
|
||||||
addEntryInternal(new VariableEntry<T>(member), entry, role);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
void addEntry(const int entry, const int role, typename LambdaEntry<T>::Getter lambda)
|
|
||||||
{
|
|
||||||
addEntryInternal(new LambdaEntry<T>(lambda), entry, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setEntryTitle(const int entry, const QString &title)
|
|
||||||
{
|
|
||||||
m_entries[entry].first = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAll(const QList<Object *> objects)
|
|
||||||
{
|
|
||||||
notifyBeginReset();
|
|
||||||
qDeleteAll(m_objects);
|
|
||||||
m_objects = objects;
|
|
||||||
notifyEndReset();
|
|
||||||
}
|
|
||||||
};
|
|
@ -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 <QTimer>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <QObject>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
@ -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<const int>;
|
|
||||||
* static_assert(std::is_same<Cleaned, int>, "Cleaned == int");
|
|
||||||
*/
|
|
||||||
// the order of remove_cv and remove_reference matters!
|
|
||||||
template <typename T>
|
|
||||||
using CleanType = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
|
||||||
|
|
||||||
/// For functors (structs with operator()), including lambdas, which in **most** cases are functors
|
|
||||||
/// "Calls" Function<Ret(*)(Arg)> or Function<Ret(C::*)(Arg)>
|
|
||||||
template <typename T> struct Function : public Function<decltype(&T::operator())> {};
|
|
||||||
/// For function pointers (&function), including static members (&Class::member)
|
|
||||||
template <typename Ret, typename Arg> struct Function<Ret(*)(Arg)> : public Function<Ret(Arg)> {};
|
|
||||||
/// Default specialization used by others.
|
|
||||||
template <typename Ret, typename Arg> struct Function<Ret(Arg)>
|
|
||||||
{
|
|
||||||
using ReturnType = Ret;
|
|
||||||
using Argument = Arg;
|
|
||||||
};
|
|
||||||
/// For member functions. Also used by the lambda overload if the lambda captures [this]
|
|
||||||
template <class C, typename Ret, typename Arg> struct Function<Ret(C::*)(Arg)> : public Function<Ret(Arg)> {};
|
|
||||||
template <class C, typename Ret, typename Arg> struct Function<Ret(C::*)(Arg) const> : public Function<Ret(Arg)> {};
|
|
||||||
/// Overload for references
|
|
||||||
template <typename F> struct Function<F&> : public Function<F> {};
|
|
||||||
/// Overload for rvalues
|
|
||||||
template <typename F> struct Function<F&&> : public Function<F> {};
|
|
||||||
// for more info: https://functionalcpp.wordpress.com/2013/08/05/function-traits/
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
#include "IconResourceHandler.h"
|
|
||||||
#include <xdgicon.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
QList<std::weak_ptr<IconResourceHandler>> 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<IconResourceHandler> ptr = handler.lock();
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
ptr->setResult(ptr->get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IconResourceHandler::init(std::shared_ptr<ResourceHandler> &ptr)
|
|
||||||
{
|
|
||||||
m_iconHandlers.append(std::dynamic_pointer_cast<IconResourceHandler>(ptr));
|
|
||||||
// we always have a result, so lets report it now!
|
|
||||||
setResult(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant IconResourceHandler::get() const
|
|
||||||
{
|
|
||||||
return XdgIcon::fromTheme(m_key);
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <resources/ResourceHandler.h>
|
|
||||||
|
|
||||||
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<ResourceHandler> &ptr) override;
|
|
||||||
static QList<std::weak_ptr<IconResourceHandler>> m_iconHandlers;
|
|
||||||
|
|
||||||
QString m_key;
|
|
||||||
|
|
||||||
// the workhorse, returns QVariantMap (filename => size) for m_key/m_theme
|
|
||||||
QVariant get() const;
|
|
||||||
};
|
|
@ -1,68 +0,0 @@
|
|||||||
#include "WebResourceHandler.h"
|
|
||||||
|
|
||||||
#include "net/Download.h"
|
|
||||||
#include "net/HttpMetaCache.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
//FIXME: wrong. needs to be done elsewhere.
|
|
||||||
QMap<QString, NetJob *> 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(Download::make(QUrl(url), entry));
|
|
||||||
connect(job, &NetJob::succeeded, this, &WebResourceHandler::succeeded);
|
|
||||||
connect(job, &NetJob::failed, this, [job, this]() {setFailure(job->failReason());});
|
|
||||||
connect(job, &NetJob::progress, this, &WebResourceHandler::progress);
|
|
||||||
connect(job, &NetJob::finished, job, [job](){m_activeDownloads.remove(m_activeDownloads.key(job));job->deleteLater();});
|
|
||||||
m_activeDownloads.insert(url, job);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebResourceHandler::succeeded()
|
|
||||||
{
|
|
||||||
MetaEntryPtr entry = ENV.metacache()->resolveEntry("icons", m_url);
|
|
||||||
setResultFromFile(entry->getFullPath());
|
|
||||||
m_activeDownloads.remove(m_activeDownloads.key(qobject_cast<NetJob *>(sender())));
|
|
||||||
}
|
|
||||||
void WebResourceHandler::progress(qint64 current, qint64 total)
|
|
||||||
{
|
|
||||||
if (total == 0)
|
|
||||||
{
|
|
||||||
setProgress(101);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setProgress(current / total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebResourceHandler::setResultFromFile(const QString &file)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
setResult(FS::read(file));
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
setFailure(e.cause());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <resources/ResourceHandler.h>
|
|
||||||
|
|
||||||
class NetJob;
|
|
||||||
|
|
||||||
class WebResourceHandler : public QObject, public ResourceHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit WebResourceHandler(const QString &url);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void succeeded();
|
|
||||||
void progress(qint64 current, qint64 total);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static QMap<QString, NetJob *> m_activeDownloads;
|
|
||||||
|
|
||||||
QString m_url;
|
|
||||||
|
|
||||||
void setResultFromFile(const QString &file);
|
|
||||||
};
|
|
@ -1,155 +0,0 @@
|
|||||||
#include "Resource.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "ResourceObserver.h"
|
|
||||||
#include "ResourceHandler.h"
|
|
||||||
|
|
||||||
// definition of static members of Resource
|
|
||||||
QMap<QString, std::function<std::shared_ptr<ResourceHandler>(const QString &)>> Resource::m_handlers;
|
|
||||||
QMap<QPair<int, int>, std::function<QVariant(QVariant)>> Resource::m_transfomers;
|
|
||||||
QMap<QString, std::weak_ptr<Resource>> Resource::m_resources;
|
|
||||||
|
|
||||||
struct NullResourceResult {};
|
|
||||||
Q_DECLARE_METATYPE(NullResourceResult)
|
|
||||||
class NullResourceHandler : public ResourceHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit NullResourceHandler()
|
|
||||||
{
|
|
||||||
setResult(QVariant::fromValue<NullResourceResult>(NullResourceResult()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Resource::Resource(const QString &resource)
|
|
||||||
: m_resource(resource)
|
|
||||||
{
|
|
||||||
if (!resource.isEmpty())
|
|
||||||
{
|
|
||||||
// a valid resource identifier has the format <id>:<data>
|
|
||||||
Q_ASSERT(resource.contains(':'));
|
|
||||||
// "parse" the resource identifier into id and data
|
|
||||||
const QString resourceId = resource.left(resource.indexOf(':'));
|
|
||||||
const QString resourceData = resource.mid(resource.indexOf(':') + 1);
|
|
||||||
|
|
||||||
// create and set up the handler
|
|
||||||
Q_ASSERT(m_handlers.contains(resourceId));
|
|
||||||
m_handler = m_handlers.value(resourceId)(resourceData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_handler = std::make_shared<NullResourceHandler>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<ConstructableResource>(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<ResourceObserver *>(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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QVariant>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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<Resource>
|
|
||||||
{
|
|
||||||
// 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>;
|
|
||||||
|
|
||||||
~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<typename Func>
|
|
||||||
Ptr then(Func &&func)
|
|
||||||
{
|
|
||||||
// Arg will be the functions argument with references and cv-qualifiers (const, volatile) removed
|
|
||||||
using Arg = TypeMagic::CleanType<typename TypeMagic::Function<Func>::Argument>;
|
|
||||||
// Ret will be the functions return type
|
|
||||||
using Ret = typename TypeMagic::Function<Func>::ReturnType;
|
|
||||||
|
|
||||||
// FunctionResourceObserver<ReturnType, ArgumentType, FunctionSignature>
|
|
||||||
return applyTo(new FunctionResourceObserver<Ret, Arg, Func>(std::forward<Func>(func)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the currently active resource. If it's type is different from T a conversion will be attempted.
|
|
||||||
template<typename T>
|
|
||||||
T getResource() const { return getResourceInternal(qMetaTypeId<T>()).template value<T>(); }
|
|
||||||
|
|
||||||
/// @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<MyResourceHandler>("myid");
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
static void registerHandler(const QString &id)
|
|
||||||
{
|
|
||||||
m_handlers.insert(id, [](const QString &res) { return std::make_shared<T>(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<typename Func>
|
|
||||||
static void registerTransformer(Func &&func)
|
|
||||||
{
|
|
||||||
using Out = typename TypeMagic::Function<Func>::ReturnType;
|
|
||||||
using In = TypeMagic::CleanType<typename TypeMagic::Function<Func>::Argument>;
|
|
||||||
static_assert(!std::is_same<Out, In>::value, "It does not make sense to transform a value to itself");
|
|
||||||
m_transfomers.insert(qMakePair(qMetaTypeId<In>(), qMetaTypeId<Out>()), [func](const QVariant &in)
|
|
||||||
{
|
|
||||||
return QVariant::fromValue<Out>(func(in.value<In>()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private: // 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<ResourceObserver *> m_observers;
|
|
||||||
std::shared_ptr<ResourceHandler> 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<QString, std::function<std::shared_ptr<ResourceHandler>(const QString &)>> m_handlers;
|
|
||||||
// a list of resource transformers, registered using registerTransformer
|
|
||||||
static QMap<QPair<int, int>, std::function<QVariant(QVariant)>> m_transfomers;
|
|
||||||
// a list of resources so that we can reuse them
|
|
||||||
static QMap<QString, std::weak_ptr<Resource>> m_resources;
|
|
||||||
};
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QVariant>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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<MyResourceHandler>("<id>"), where <id> 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<ResourceHandler>&) {}
|
|
||||||
|
|
||||||
QVariant result() const { return m_result; }
|
|
||||||
|
|
||||||
protected: // use these methods to notify the resource of changes
|
|
||||||
void setResult(const QVariant &result);
|
|
||||||
void setFailure(const QString &reason);
|
|
||||||
void setProgress(const int progress);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVariant m_result;
|
|
||||||
Resource *m_resource = nullptr;
|
|
||||||
};
|
|
@ -1,55 +0,0 @@
|
|||||||
#include "ResourceObserver.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "Resource.h"
|
|
||||||
|
|
||||||
static const char *defaultPropertyForTarget(QObject *target)
|
|
||||||
{
|
|
||||||
if (target->inherits("QLabel"))
|
|
||||||
{
|
|
||||||
return "pixmap";
|
|
||||||
}
|
|
||||||
else if (target->inherits("QAction") ||
|
|
||||||
target->inherits("QMenu") ||
|
|
||||||
target->inherits("QAbstractButton"))
|
|
||||||
{
|
|
||||||
return "icon";
|
|
||||||
}
|
|
||||||
// for unit tests
|
|
||||||
else if (target->inherits("DummyObserverObject"))
|
|
||||||
{
|
|
||||||
return "property";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Q_ASSERT_X(false, "ResourceObserver.cpp: defaultPropertyForTarget", "Unrecognized QObject subclass");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QObjectResourceObserver::QObjectResourceObserver(QObject *target, const char *property)
|
|
||||||
: QObject(target), m_target(target)
|
|
||||||
{
|
|
||||||
const QMetaObject *mo = m_target->metaObject();
|
|
||||||
m_property = mo->property(mo->indexOfProperty(
|
|
||||||
property ?
|
|
||||||
property
|
|
||||||
: defaultPropertyForTarget(target)));
|
|
||||||
}
|
|
||||||
void QObjectResourceObserver::resourceUpdated()
|
|
||||||
{
|
|
||||||
m_property.write(m_target, getInternal(m_property.type()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ResourceObserver::~ResourceObserver()
|
|
||||||
{
|
|
||||||
m_resource->notifyObserverDeleted(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ResourceObserver::getInternal(const int typeId) const
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_resource);
|
|
||||||
return m_resource->getResourceInternal(typeId);
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMetaProperty>
|
|
||||||
#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> resource) { m_resource = resource; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
template<typename T>
|
|
||||||
T get() const { return getInternal(qMetaTypeId<T>()).template value<T>(); }
|
|
||||||
QVariant getInternal(const int typeId) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Resource> m_resource;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Observer for QObject properties
|
|
||||||
*
|
|
||||||
* Give it a target and the name of a property, and that property will be set when the resource changes.
|
|
||||||
*
|
|
||||||
* If no name is given an attempt to find a default property for some common classes is done.
|
|
||||||
*/
|
|
||||||
class 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 <typename Ret, typename Arg, typename Func>
|
|
||||||
class FunctionResourceObserver : public ResourceObserver
|
|
||||||
{
|
|
||||||
std::function<Ret(Arg)> m_function;
|
|
||||||
public:
|
|
||||||
template <typename T>
|
|
||||||
explicit FunctionResourceObserver(T &&func)
|
|
||||||
: m_function(std::forward<Func>(func)) {}
|
|
||||||
|
|
||||||
void resourceUpdated() override
|
|
||||||
{
|
|
||||||
m_function(get<Arg>());
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,89 +0,0 @@
|
|||||||
#include "ResourceProxyModel.h"
|
|
||||||
|
|
||||||
#include <QItemSelectionRange>
|
|
||||||
|
|
||||||
#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<int>>("QVector<int>");
|
|
||||||
}
|
|
||||||
|
|
||||||
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<QAbstractItemModel *>(m_index.model()),
|
|
||||||
"dataChanged", Qt::QueuedConnection,
|
|
||||||
Q_ARG(QModelIndex, m_index), Q_ARG(QModelIndex, m_index), Q_ARG(QVector<int>, QVector<int>() << m_role));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPersistentModelIndex m_index;
|
|
||||||
int m_role;
|
|
||||||
};
|
|
||||||
|
|
||||||
ResourceProxyModel::ResourceProxyModel(const int resultTypeId, QObject *parent)
|
|
||||||
: QIdentityProxyModel(parent), m_resultTypeId(resultTypeId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ResourceProxyModel::data(const QModelIndex &proxyIndex, int role) const
|
|
||||||
{
|
|
||||||
const QModelIndex mapped = mapToSource(proxyIndex);
|
|
||||||
// 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<int> &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);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QIdentityProxyModel>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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<T>()
|
|
||||||
explicit ResourceProxyModel(const int resultTypeId, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
// provide this role from your model if you want to show a placeholder
|
|
||||||
PlaceholderRole = Qt::UserRole + 0xabc // some random offset to not collide with other stuff
|
|
||||||
};
|
|
||||||
|
|
||||||
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
|
||||||
void setSourceModel(QAbstractItemModel *model) override;
|
|
||||||
|
|
||||||
/// Helper function, usage: m_view->setModel(ResourceProxyModel::mixin<QIcon>(m_model));
|
|
||||||
template <typename T>
|
|
||||||
static QAbstractItemModel *mixin(QAbstractItemModel *model)
|
|
||||||
{
|
|
||||||
ResourceProxyModel *proxy = new ResourceProxyModel(qMetaTypeId<T>(), model);
|
|
||||||
proxy->setSourceModel(model);
|
|
||||||
return proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// mutable because it needs to be available from the const data()
|
|
||||||
mutable QMap<QPersistentModelIndex, std::shared_ptr<class Resource>> m_resources;
|
|
||||||
|
|
||||||
const int m_resultTypeId;
|
|
||||||
};
|
|
@ -1,116 +0,0 @@
|
|||||||
#include <QTest>
|
|
||||||
#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<ResourceHandler> &) override
|
|
||||||
{
|
|
||||||
setResult(m_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString m_key;
|
|
||||||
};
|
|
||||||
class DummyObserver : public ResourceObserver
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void resourceUpdated() override
|
|
||||||
{
|
|
||||||
values += get<QString>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<DummyStringResourceHandler>("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"
|
|
Loading…
Reference in New Issue
Block a user