1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
/*
bindingaggregator.cpp
This file is part of GammaRay, the Qt application inspection and manipulation tool.
SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-License-Identifier: GPL-2.0-or-later
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
// Own
#include "bindingaggregator.h"
#include <core/abstractbindingprovider.h>
#include <core/bindingnode.h>
#include <core/objectdataprovider.h>
#include <core/probe.h>
#include <core/problemcollector.h>
#include <core/propertycontroller.h>
#include <common/objectbroker.h>
// Qt
#include <QMetaProperty>
#include <QMetaObject>
#include <QMutexLocker>
using namespace GammaRay;
Q_GLOBAL_STATIC(std::vector<std::unique_ptr<AbstractBindingProvider>>, s_providers)
void BindingAggregator::registerBindingProvider(std::unique_ptr<AbstractBindingProvider> provider)
{
s_providers()->push_back(std::move(provider));
}
bool GammaRay::BindingAggregator::providerAvailableFor(QObject *object)
{
return std::find_if(s_providers()->begin(), s_providers()->end(),
[object](const std::unique_ptr<AbstractBindingProvider> &provider) {
return provider->canProvideBindingsFor(object);
})
!= s_providers()->end();
}
std::vector<std::unique_ptr<BindingNode>> BindingAggregator::findDependenciesFor(BindingNode *node)
{
std::vector<std::unique_ptr<BindingNode>> allDependencies;
if (node->isPartOfBindingLoop())
return allDependencies;
for (const auto &provider : *s_providers()) {
auto providerDependencies = provider->findDependenciesFor(node);
for (auto &&providerDependency : providerDependencies) {
providerDependency->dependencies() = findDependenciesFor(providerDependency.get());
allDependencies.push_back(std::move(providerDependency));
}
}
std::sort(
allDependencies.begin(),
allDependencies.end(),
[](const std::unique_ptr<BindingNode> &a, const std::unique_ptr<BindingNode> &b) {
return a->object() < b->object() || (a->object() == b->object() && a->propertyIndex() < b->propertyIndex());
});
return allDependencies;
}
std::vector<std::unique_ptr<BindingNode>> BindingAggregator::bindingTreeForObject(QObject *obj)
{
std::vector<std::unique_ptr<BindingNode>> bindings;
if (obj) {
for (auto providerIt = s_providers()->begin(); providerIt != s_providers()->cend(); ++providerIt) {
auto newBindings = (*providerIt)->findBindingsFor(obj);
for (auto &&newBinding : newBindings) {
BindingNode *node = newBinding.get();
if (std::find_if(bindings.begin(), bindings.end(),
[node](const std::unique_ptr<BindingNode> &other) { return *node == *other; })
!= bindings.end()) {
continue; // apparently this is a duplicate.
}
node->dependencies() = findDependenciesFor(node);
bindings.push_back(std::move(newBinding));
}
}
}
return bindings;
}
void BindingAggregator::scanForBindingLoops()
{
const QVector<QObject *> &allObjects = Probe::instance()->allQObjects();
QMutexLocker lock(Probe::objectLock());
for (QObject *obj : allObjects) {
if (!Probe::instance()->isValidObject(obj))
continue;
auto bindings = bindingTreeForObject(obj);
for (auto &&bindingNode : bindings) {
if (bindingNode->isPartOfBindingLoop()) {
Problem p;
p.severity = Problem::Error;
p.description = QStringLiteral("Object %1 / Property %2 has a binding loop.").arg(ObjectDataProvider::typeName(bindingNode->object()), bindingNode->canonicalName());
p.object = ObjectId(bindingNode->object());
p.locations.push_back(bindingNode->sourceLocation());
p.problemId = QStringLiteral("com.kdab.GammaRay.ObjectInspector.BindingLoopScan:%1.%2").arg(reinterpret_cast<quintptr>(bindingNode->object())).arg(bindingNode->propertyIndex()); // no multi arg, both are ints
p.findingCategory = Problem::Scan;
ProblemCollector::addProblem(p);
}
}
}
}
|