source: branches/vendor/trolltech/qt/current/tools/qdbus/qdbusviewer/qdbusmodel.cpp @ 2

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

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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