source: trunk/tools/qdbus/qdbusviewer/qdbusmodel.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 11.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdbusmodel.h"
43
44#include <QtCore/qvector.h>
45#include <QtXml/QtXml>
46
47struct QDBusItem
48{
49 inline QDBusItem(QDBusModel::Type aType, const QString &aName, QDBusItem *aParent = 0)
50 : type(aType), parent(aParent), isPrefetched(type != QDBusModel::PathItem), name(aName)
51 {}
52 inline ~QDBusItem()
53 {
54 qDeleteAll(children);
55 }
56
57 QString path() const
58 {
59 Q_ASSERT(type == QDBusModel::PathItem);
60
61 QString s;
62 const QDBusItem *item = this;
63 while (item) {
64 s.prepend(item->name);
65 item = item->parent;
66 }
67 if (s.length() > 1)
68 s.chop(1); // remove tailing slash
69 return s;
70 }
71
72 QDBusModel::Type type;
73 QDBusItem *parent;
74 QVector<QDBusItem *> children;
75 bool isPrefetched;
76 QString name;
77 QString caption;
78 QString typeSignature;
79};
80
81QDomDocument QDBusModel::introspect(const QString &path)
82{
83 QDomDocument doc;
84
85 QDBusInterface iface(service, path, QLatin1String("org.freedesktop.DBus.Introspectable"), c);
86 if (!iface.isValid()) {
87 QDBusError err(iface.lastError());
88 emit busError(QString::fromLatin1("Cannot introspect object %1 at %2:\n %3 (%4)\n").arg(path).arg(
89 service).arg(err.name()).arg(err.message()));
90 return doc;
91 }
92
93 QDBusReply<QString> xml = iface.call(QLatin1String("Introspect"));
94
95 if (!xml.isValid()) {
96 QDBusError err(xml.error());
97 if (err.isValid()) {
98 emit busError(QString::fromLatin1("Call to object %1 at %2:\n %3 (%4) failed\n").arg(
99 path).arg(service).arg(err.name()).arg(err.message()));
100 } else {
101 emit busError(QString::fromLatin1("Invalid XML received from object %1 at %2\n").arg(
102 path).arg(service));
103 }
104 return doc;
105 }
106
107 doc.setContent(xml);
108 return doc;
109}
110
111void QDBusModel::addMethods(QDBusItem *parent, const QDomElement &iface)
112{
113 Q_ASSERT(parent);
114
115 QDomElement child = iface.firstChildElement();
116 while (!child.isNull()) {
117 QDBusItem *item = 0;
118 if (child.tagName() == QLatin1String("method")) {
119 item = new QDBusItem(QDBusModel::MethodItem,
120 child.attribute(QLatin1String("name")), parent);
121 item->caption = QLatin1String("Method: ") + item->name;
122 //get "type" from <arg> where "direction" is "in"
123 QDomElement n = child.firstChildElement();
124 while (!n.isNull()) {
125 if (n.attribute(QLatin1String("direction")) == QLatin1String("in"))
126 item->typeSignature += n.attribute(QLatin1String("type"));
127 n = n.nextSiblingElement();
128 }
129 } else if (child.tagName() == QLatin1String("signal")) {
130 item = new QDBusItem(QDBusModel::SignalItem,
131 child.attribute(QLatin1String("name")), parent);
132 item->caption = QLatin1String("Signal: ") + item->name;
133 } else if (child.tagName() == QLatin1String("property")) {
134 item = new QDBusItem(QDBusModel::PropertyItem,
135 child.attribute(QLatin1String("name")), parent);
136 item->caption = QLatin1String("Property: ") + item->name;
137 } else {
138 qDebug() << "addMethods: unknown tag:" << child.tagName();
139 }
140 if (item)
141 parent->children.append(item);
142
143 child = child.nextSiblingElement();
144 }
145}
146
147void QDBusModel::addPath(QDBusItem *parent)
148{
149 Q_ASSERT(parent);
150
151 QString path = parent->path();
152
153 QDomDocument doc = introspect(path);
154 QDomElement node = doc.documentElement();
155 QDomElement child = node.firstChildElement();
156 while (!child.isNull()) {
157 if (child.tagName() == QLatin1String("node")) {
158 QDBusItem *item = new QDBusItem(QDBusModel::PathItem,
159 child.attribute(QLatin1String("name")) + QLatin1Char('/'), parent);
160 parent->children.append(item);
161
162 addMethods(item, child);
163 } else if (child.tagName() == QLatin1String("interface")) {
164 QDBusItem *item = new QDBusItem(QDBusModel::InterfaceItem,
165 child.attribute(QLatin1String("name")), parent);
166 parent->children.append(item);
167
168 addMethods(item, child);
169 } else {
170 qDebug() << "addPath: Unknown tag name:" << child.tagName();
171 }
172 child = child.nextSiblingElement();
173 }
174
175 parent->isPrefetched = true;
176}
177
178QDBusModel::QDBusModel(const QString &aService, const QDBusConnection &connection)
179 : service(aService), c(connection), root(0)
180{
181 root = new QDBusItem(QDBusModel::PathItem, QLatin1String("/"));
182}
183
184QDBusModel::~QDBusModel()
185{
186 delete root;
187}
188
189QModelIndex QDBusModel::index(int row, int column, const QModelIndex &parent) const
190{
191 const QDBusItem *item = static_cast<QDBusItem *>(parent.internalPointer());
192 if (!item)
193 item = root;
194
195 if (column != 0 || row < 0 || row >= item->children.count())
196 return QModelIndex();
197
198 return createIndex(row, 0, item->children.at(row));
199}
200
201QModelIndex QDBusModel::parent(const QModelIndex &child) const
202{
203 QDBusItem *item = static_cast<QDBusItem *>(child.internalPointer());
204 if (!item || !item->parent || !item->parent->parent)
205 return QModelIndex();
206
207 return createIndex(item->parent->parent->children.indexOf(item->parent), 0, item->parent);
208}
209
210int QDBusModel::rowCount(const QModelIndex &parent) const
211{
212 QDBusItem *item = static_cast<QDBusItem *>(parent.internalPointer());
213 if (!item)
214 item = root;
215 if (!item->isPrefetched)
216 const_cast<QDBusModel *>(this)->addPath(item);
217
218 return item->children.count();
219}
220
221int QDBusModel::columnCount(const QModelIndex &) const
222{
223 return 1;
224}
225
226QVariant QDBusModel::data(const QModelIndex &index, int role) const
227{
228 const QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
229 if (!item)
230 return QVariant();
231
232 if (role != Qt::DisplayRole)
233 return QVariant();
234
235 return item->caption.isEmpty() ? item->name : item->caption;
236}
237
238QVariant QDBusModel::headerData(int section, Qt::Orientation orientation, int role) const
239{
240 if (role != Qt::DisplayRole || orientation == Qt::Vertical || section != 0)
241 return QVariant();
242
243 return QLatin1String("Methods");
244}
245
246QDBusModel::Type QDBusModel::itemType(const QModelIndex &index) const
247{
248 const QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
249 return item ? item->type : PathItem;
250}
251
252void QDBusModel::refresh(const QModelIndex &aIndex)
253{
254 QModelIndex index = aIndex;
255 while (index.isValid() && static_cast<QDBusItem *>(index.internalPointer())->type != PathItem) {
256 index = index.parent();
257 }
258
259 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
260 if (!item)
261 item = root;
262
263 if (!item->children.isEmpty()) {
264 beginRemoveRows(index, 0, item->children.count() - 1);
265 qDeleteAll(item->children);
266 item->children.clear();
267 endRemoveRows();
268 }
269
270 addPath(item);
271 if (!item->children.isEmpty()) {
272 beginInsertRows(index, 0, item->children.count() - 1);
273 endInsertRows();
274 }
275}
276
277QString QDBusModel::dBusPath(const QModelIndex &aIndex) const
278{
279 QModelIndex index = aIndex;
280 while (index.isValid() && static_cast<QDBusItem *>(index.internalPointer())->type != PathItem) {
281 index = index.parent();
282 }
283
284 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
285 if (!item)
286 item = root;
287
288 return item->path();
289}
290
291QString QDBusModel::dBusInterface(const QModelIndex &index) const
292{
293 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
294 if (!item)
295 return QString();
296 if (item->type == InterfaceItem)
297 return item->name;
298 if (item->parent && item->parent->type == InterfaceItem)
299 return item->parent->name;
300 return QString();
301}
302
303QString QDBusModel::dBusMethodName(const QModelIndex &index) const
304{
305 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
306 return item ? item->name : QString();
307}
308
309QString QDBusModel::dBusTypeSignature(const QModelIndex &index) const
310{
311 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
312 return item ? item->typeSignature : QString();
313}
314
315QModelIndex QDBusModel::findObject(const QDBusObjectPath &objectPath)
316{
317 QStringList path = objectPath.path().split(QLatin1Char('/'), QString::SkipEmptyParts);
318
319 QDBusItem *item = root;
320 int childIdx = -1;
321 while (item && !path.isEmpty()) {
322 const QString branch = path.takeFirst() + QLatin1Char('/');
323 childIdx = -1;
324
325 // do a linear search over all the children
326 for (int i = 0; i < item->children.count(); ++i) {
327 QDBusItem *child = item->children.at(i);
328 if (child->type == PathItem && child->name == branch) {
329 item = child;
330 childIdx = i;
331
332 // prefetch the found branch
333 if (!item->isPrefetched)
334 addPath(item);
335 break;
336 }
337 }
338
339 // branch not found - bail out
340 if (childIdx == -1)
341 return QModelIndex();
342 }
343
344 // found the right item
345 if (childIdx != -1 && item && path.isEmpty())
346 return createIndex(childIdx, 0, item);
347
348 return QModelIndex();
349}
350
Note: See TracBrowser for help on using the repository browser.