1 /*
2 objectbroker.cpp
3
4 This file is part of GammaRay, the Qt application inspection and
5 manipulation tool.
6
7 Copyright (C) 2013-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8 Author: Volker Krause <volker.krause@kdab.com>
9
10 Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11 accordance with GammaRay Commercial License Agreement provided with the Software.
12
13 Contact info@kdab.com if any conditions of this licensing are not clear to you.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation, either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 */
28
29 #include "objectbroker.h"
30 #include "endpoint.h"
31 #include "modelevent.h"
32
33 #include <kde/klinkitemselectionmodel.h>
34
35 #include <QHash>
36 #include <QString>
37 #include <QAbstractItemModel>
38 #include <QItemSelectionModel>
39 #include <QAbstractProxyModel>
40 #include <QCoreApplication>
41 #include <QVector>
42
43 namespace GammaRay {
44 struct ObjectlBrokerData {
45 ObjectlBrokerData() = default;
46 QHash<QString, QObject *> objects;
47 QHash<QString, QAbstractItemModel *> models;
48 QHash<QAbstractItemModel *, QItemSelectionModel *> selectionModels;
49 QHash<QByteArray, ObjectBroker::ClientObjectFactoryCallback> clientObjectFactories;
50 ObjectBroker::ModelFactoryCallback modelCallback = nullptr;
51 ObjectBroker::selectionModelFactoryCallback selectionCallback = nullptr;
52 QVector<QObject *> ownedObjects;
53 };
54
Q_GLOBAL_STATIC(ObjectlBrokerData,s_objectBroker)55 Q_GLOBAL_STATIC(ObjectlBrokerData, s_objectBroker)
56
57 void ObjectBroker::registerObject(const QString &name, QObject *object)
58 {
59 Q_ASSERT(!name.isEmpty());
60 Q_ASSERT(object->objectName().isEmpty());
61 object->setObjectName(name);
62
63 Q_ASSERT(!s_objectBroker()->objects.contains(name));
64 s_objectBroker()->objects.insert(name, object);
65
66 Q_ASSERT(Endpoint::instance());
67 Endpoint::instance()->registerObject(name, object);
68 }
69
hasObject(const QString & name)70 bool ObjectBroker::hasObject(const QString &name)
71 {
72 return s_objectBroker()->objects.contains(name);
73 }
74
objectInternal(const QString & name,const QByteArray & type)75 QObject *ObjectBroker::objectInternal(const QString &name, const QByteArray &type)
76 {
77 auto it = s_objectBroker()->objects.constFind(name);
78 if (it != s_objectBroker()->objects.constEnd())
79 return it.value();
80
81 // Below here only valid for clients!
82 // Remote/probe side should have registered the object directly
83 QObject *obj = nullptr;
84
85 if (!type.isEmpty()) {
86 Q_ASSERT(s_objectBroker()->clientObjectFactories.contains(type));
87 obj = s_objectBroker()->clientObjectFactories.value(type)(name, qApp);
88 } else {
89 // fallback
90 obj = new QObject(qApp);
91 registerObject(name, obj);
92 }
93 s_objectBroker()->ownedObjects.push_back(obj);
94
95 Q_ASSERT(obj);
96 // ensure it was registered
97 Q_ASSERT_X(s_objectBroker()->objects.value(name, nullptr) == obj, Q_FUNC_INFO,
98 qPrintable(QStringLiteral("Object %1 was not registered in the broker.").arg(name)));
99
100 return obj;
101 }
102
registerClientObjectFactoryCallbackInternal(const QByteArray & type,ObjectBroker::ClientObjectFactoryCallback callback)103 void ObjectBroker::registerClientObjectFactoryCallbackInternal(const QByteArray &type,
104 ObjectBroker::ClientObjectFactoryCallback callback)
105 {
106 Q_ASSERT(!type.isEmpty());
107 s_objectBroker()->clientObjectFactories[type] = callback;
108 }
109
registerModelInternal(const QString & name,QAbstractItemModel * model)110 void ObjectBroker::registerModelInternal(const QString &name, QAbstractItemModel *model)
111 {
112 Q_ASSERT(!s_objectBroker()->models.contains(name));
113 model->setObjectName(name);
114 s_objectBroker()->models.insert(name, model);
115 }
116
model(const QString & name)117 QAbstractItemModel *ObjectBroker::model(const QString &name)
118 {
119 ModelEvent event(true);
120 auto it = s_objectBroker()->models.constFind(name);
121 if (it != s_objectBroker()->models.constEnd()) {
122 QCoreApplication::sendEvent(it.value(), &event);
123 return it.value();
124 }
125
126 if (s_objectBroker()->modelCallback) {
127 QAbstractItemModel *model = s_objectBroker()->modelCallback(name);
128 if (model) {
129 model->setObjectName(name);
130 s_objectBroker()->models.insert(name, model);
131 s_objectBroker()->ownedObjects.push_back(model);
132 QCoreApplication::sendEvent(model, &event);
133 return model;
134 }
135 }
136 return nullptr;
137 }
138
setModelFactoryCallback(ObjectBroker::ModelFactoryCallback callback)139 void ObjectBroker::setModelFactoryCallback(ObjectBroker::ModelFactoryCallback callback)
140 {
141 s_objectBroker()->modelCallback = callback;
142 }
143
registerSelectionModel(QItemSelectionModel * selectionModel)144 void ObjectBroker::registerSelectionModel(QItemSelectionModel *selectionModel)
145 {
146 Q_ASSERT(!s_objectBroker()->selectionModels.contains(const_cast<QAbstractItemModel *>(
147 selectionModel->model())));
148 s_objectBroker()->selectionModels.insert(
149 const_cast<QAbstractItemModel *>(selectionModel->model()), selectionModel);
150 }
151
unregisterSelectionModel(QItemSelectionModel * selectionModel)152 void ObjectBroker::unregisterSelectionModel(QItemSelectionModel *selectionModel)
153 {
154 Q_ASSERT(s_objectBroker()->selectionModels.contains(const_cast<QAbstractItemModel *>(
155 selectionModel->model())));
156 s_objectBroker()->selectionModels.remove(
157 const_cast<QAbstractItemModel *>(selectionModel->model()));
158 }
159
hasSelectionModel(QAbstractItemModel * model)160 bool ObjectBroker::hasSelectionModel(QAbstractItemModel *model)
161 {
162 return s_objectBroker()->selectionModels.contains(model);
163 }
164
sourceModelForProxy(QAbstractItemModel * model)165 static QAbstractItemModel *sourceModelForProxy(QAbstractItemModel *model)
166 {
167 // stop once we found a registered model, this is what network communication is based on
168 if (s_objectBroker()->models.values().contains(model))
169 return model;
170
171 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(model);
172 if (!proxy)
173 return model;
174 return sourceModelForProxy(proxy->sourceModel());
175 }
176
selectionModel(QAbstractItemModel * model)177 QItemSelectionModel *ObjectBroker::selectionModel(QAbstractItemModel *model)
178 {
179 auto it = s_objectBroker()->selectionModels.constFind(model);
180 if (it != s_objectBroker()->selectionModels.constEnd())
181 return it.value();
182
183 if (s_objectBroker()->selectionCallback) {
184 QAbstractItemModel *sourceModel = sourceModelForProxy(model);
185
186 QItemSelectionModel *selectionModel = nullptr;
187 if (sourceModel == model) {
188 selectionModel = s_objectBroker()->selectionCallback(sourceModel);
189 s_objectBroker()->ownedObjects.push_back(selectionModel);
190 } else {
191 QItemSelectionModel *sourceSelectionModel = ObjectBroker::selectionModel(sourceModel);
192 selectionModel = new KLinkItemSelectionModel(model, sourceSelectionModel, model);
193 }
194
195 if (selectionModel) {
196 registerSelectionModel(selectionModel);
197 return selectionModel;
198 }
199 }
200 return nullptr;
201 }
202
setSelectionModelFactoryCallback(ObjectBroker::selectionModelFactoryCallback callback)203 void ObjectBroker::setSelectionModelFactoryCallback(
204 ObjectBroker::selectionModelFactoryCallback callback)
205 {
206 s_objectBroker()->selectionCallback = callback;
207 }
208
clear()209 void ObjectBroker::clear()
210 {
211 auto *ob = s_objectBroker();
212 qDeleteAll(ob->ownedObjects);
213 ob->ownedObjects.clear();
214 ob->objects.clear();
215 ob->models.clear();
216 ob->selectionModels.clear();
217 }
218 }
219