summaryrefslogtreecommitdiffstats
path: root/api/logic/resources/ResourceProxyModel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'api/logic/resources/ResourceProxyModel.cpp')
-rw-r--r--api/logic/resources/ResourceProxyModel.cpp89
1 files changed, 89 insertions, 0 deletions
diff --git a/api/logic/resources/ResourceProxyModel.cpp b/api/logic/resources/ResourceProxyModel.cpp
new file mode 100644
index 00000000..f026d9a9
--- /dev/null
+++ b/api/logic/resources/ResourceProxyModel.cpp
@@ -0,0 +1,89 @@
+#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);
+}