00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qdbusmodel.h"
00025
00026 #include <QtCore/qvector.h>
00027 #include <QtXml/QtXml>
00028
00029 struct QDBusItem
00030 {
00031 inline QDBusItem(QDBusModel::Type aType, const QString &aName, QDBusItem *aParent = 0)
00032 : type(aType), parent(aParent), isPrefetched(type != QDBusModel::PathItem), name(aName)
00033 {}
00034 inline ~QDBusItem()
00035 {
00036 qDeleteAll(children);
00037 }
00038
00039 QString path() const
00040 {
00041 Q_ASSERT(type == QDBusModel::PathItem);
00042
00043 QString s;
00044 const QDBusItem *item = this;
00045 while (item) {
00046 s.prepend(item->name);
00047 item = item->parent;
00048 }
00049 if (s.length() > 1)
00050 s.chop(1);
00051 return s;
00052 }
00053
00054 QDBusModel::Type type;
00055 QDBusItem *parent;
00056 QVector<QDBusItem *> children;
00057 bool isPrefetched;
00058 QString name;
00059 QString caption;
00060 };
00061
00062 QDomDocument QDBusModel::introspect(const QString &path)
00063 {
00064 QDomDocument doc;
00065
00066 QDBusInterface iface(service, path, "org.freedesktop.DBus.Introspectable", c);
00067 if (!iface.isValid()) {
00068 QDBusError err(iface.lastError());
00069 emit busError(QString("Cannot introspect object %1 at %2:\n %3 (%4)\n").arg(path).arg(
00070 service).arg(err.name()).arg(err.message()));
00071 return doc;
00072 }
00073
00074 QDBusReply<QString> xml = iface.call("Introspect");
00075
00076 if (!xml.isValid()) {
00077 QDBusError err(xml.error());
00078 if (err.isValid()) {
00079 emit busError(QString("Call to object %1 at %2:\n %3 (%4) failed\n").arg(
00080 path).arg(service).arg(err.name()).arg(err.message()));
00081 } else {
00082 emit busError(QString("Invalid XML received from object %1 at %2\n").arg(
00083 path).arg(service));
00084 }
00085 return doc;
00086 }
00087
00088 doc.setContent(xml);
00089 return doc;
00090 }
00091
00092 void QDBusModel::addMethods(QDBusItem *parent, const QDomElement &iface)
00093 {
00094 Q_ASSERT(parent);
00095
00096 QDomElement child = iface.firstChildElement();
00097 while (!child.isNull()) {
00098 QDBusItem *item = 0;
00099 if (child.tagName() == QLatin1String("method")) {
00100 item = new QDBusItem(QDBusModel::MethodItem,
00101 child.attribute("name"), parent);
00102 item->caption = "Method: " + item->name;
00103 } else if (child.tagName() == QLatin1String("signal")) {
00104 item = new QDBusItem(QDBusModel::SignalItem,
00105 child.attribute("name"), parent);
00106 item->caption = "Signal: " + item->name;
00107 } else if (child.tagName() == QLatin1String("property")) {
00108 item = new QDBusItem(QDBusModel::PropertyItem,
00109 child.attribute("name"), parent);
00110 item->caption = "Property: " + item->name;
00111 } else {
00112 qDebug() << "addMethods: unknown tag:" << child.tagName();
00113 }
00114 if (item)
00115 parent->children.append(item);
00116
00117 child = child.nextSiblingElement();
00118 }
00119 }
00120
00121 void QDBusModel::addPath(QDBusItem *parent)
00122 {
00123 Q_ASSERT(parent);
00124
00125 QString path = parent->path();
00126
00127 QDomDocument doc = introspect(path);
00128 QDomElement node = doc.documentElement();
00129 QDomElement child = node.firstChildElement();
00130 while (!child.isNull()) {
00131 if (child.tagName() == QLatin1String("node")) {
00132 QDBusItem *item = new QDBusItem(QDBusModel::PathItem,
00133 child.attribute("name") + QLatin1Char('/'), parent);
00134 parent->children.append(item);
00135
00136 addMethods(item, child);
00137 } else if (child.tagName() == QLatin1String("interface")) {
00138 QDBusItem *item = new QDBusItem(QDBusModel::InterfaceItem,
00139 child.attribute("name"), parent);
00140 parent->children.append(item);
00141
00142 addMethods(item, child);
00143 } else {
00144 qDebug() << "addPath: Unknown tag name:" << child.tagName();
00145 }
00146 child = child.nextSiblingElement();
00147 }
00148
00149 parent->isPrefetched = true;
00150 }
00151
00152 QDBusModel::QDBusModel(const QString &aService, const QDBusConnection &connection)
00153 : service(aService), c(connection), root(0)
00154 {
00155 root = new QDBusItem(QDBusModel::PathItem, QLatin1String("/"));
00156 }
00157
00158 QDBusModel::~QDBusModel()
00159 {
00160 delete root;
00161 }
00162
00163 QModelIndex QDBusModel::index(int row, int column, const QModelIndex &parent) const
00164 {
00165 const QDBusItem *item = static_cast<QDBusItem *>(parent.internalPointer());
00166 if (!item)
00167 item = root;
00168
00169 if (column != 0 || row < 0 || row >= item->children.count())
00170 return QModelIndex();
00171
00172 return createIndex(row, 0, item->children.at(row));
00173 }
00174
00175 QModelIndex QDBusModel::parent(const QModelIndex &child) const
00176 {
00177 QDBusItem *item = static_cast<QDBusItem *>(child.internalPointer());
00178 if (!item || !item->parent || !item->parent->parent)
00179 return QModelIndex();
00180
00181 return createIndex(item->parent->parent->children.indexOf(item->parent), 0, item->parent);
00182 }
00183
00184 int QDBusModel::rowCount(const QModelIndex &parent) const
00185 {
00186 QDBusItem *item = static_cast<QDBusItem *>(parent.internalPointer());
00187 if (!item)
00188 item = root;
00189 if (!item->isPrefetched)
00190 const_cast<QDBusModel *>(this)->addPath(item);
00191
00192 return item->children.count();
00193 }
00194
00195 int QDBusModel::columnCount(const QModelIndex &) const
00196 {
00197 return 1;
00198 }
00199
00200 QVariant QDBusModel::data(const QModelIndex &index, int role) const
00201 {
00202 const QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00203 if (!item)
00204 return QVariant();
00205
00206 if (role != Qt::DisplayRole)
00207 return QVariant();
00208
00209 return item->caption.isEmpty() ? item->name : item->caption;
00210 }
00211
00212 QVariant QDBusModel::headerData(int section, Qt::Orientation orientation, int role) const
00213 {
00214 if (role != Qt::DisplayRole || orientation == Qt::Vertical || section != 0)
00215 return QVariant();
00216
00217 return QLatin1String("Methods");
00218 }
00219
00220 QDBusModel::Type QDBusModel::itemType(const QModelIndex &index) const
00221 {
00222 const QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00223 return item ? item->type : PathItem;
00224 }
00225
00226 void QDBusModel::refresh(const QModelIndex &aIndex)
00227 {
00228 QModelIndex index = aIndex;
00229 while (index.isValid() && static_cast<QDBusItem *>(index.internalPointer())->type != PathItem) {
00230 index = index.parent();
00231 }
00232
00233 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00234 if (!item)
00235 item = root;
00236
00237 if (!item->children.isEmpty()) {
00238 beginRemoveRows(index, 0, item->children.count() - 1);
00239 qDeleteAll(item->children);
00240 item->children.clear();
00241 endRemoveRows();
00242 }
00243
00244 addPath(item);
00245 if (!item->children.isEmpty()) {
00246 beginInsertRows(index, 0, item->children.count() - 1);
00247 endInsertRows();
00248 }
00249 }
00250
00251 QString QDBusModel::dBusPath(const QModelIndex &aIndex) const
00252 {
00253 QModelIndex index = aIndex;
00254 while (index.isValid() && static_cast<QDBusItem *>(index.internalPointer())->type != PathItem) {
00255 index = index.parent();
00256 }
00257
00258 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00259 if (!item)
00260 item = root;
00261
00262 return item->path();
00263 }
00264
00265 QString QDBusModel::dBusInterface(const QModelIndex &index) const
00266 {
00267 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00268 if (!item)
00269 return QString();
00270 if (item->type == InterfaceItem)
00271 return item->name;
00272 if (item->parent && item->parent->type == InterfaceItem)
00273 return item->parent->name;
00274 return QString();
00275 }
00276
00277 QString QDBusModel::dBusMethodName(const QModelIndex &index) const
00278 {
00279 QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer());
00280 return item ? item->name : QString();
00281 }
00282