1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDBus module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <QtCore/qmetaobject.h>
43 #include <QtCore/qstringlist.h>
45 #include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT
46 #include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
47 #include "qdbusconnection_p.h" // for the flags
48 #include "qdbusmetatype_p.h"
49 #include "qdbusmetatype.h"
50 #include "qdbusutil_p.h"
54 extern QDBUS_EXPORT QString
qDBusGenerateMetaObjectXml(QString interface
, const QMetaObject
*mo
,
55 const QMetaObject
*base
, int flags
);
57 static inline QString
typeNameToXml(const char *typeName
)
59 // ### copied from qtextdocument.cpp
60 // ### move this into QtCore at some point
61 QString plain
= QLatin1String(typeName
);
63 rich
.reserve(int(plain
.length() * 1.1));
64 for (int i
= 0; i
< plain
.length(); ++i
) {
65 if (plain
.at(i
) == QLatin1Char('<'))
66 rich
+= QLatin1String("<");
67 else if (plain
.at(i
) == QLatin1Char('>'))
68 rich
+= QLatin1String(">");
69 else if (plain
.at(i
) == QLatin1Char('&'))
70 rich
+= QLatin1String("&");
77 // implement the D-Bus org.freedesktop.DBus.Introspectable interface
78 // we do that by analysing the metaObject of all the adaptor interfaces
80 static QString
generateInterfaceXml(const QMetaObject
*mo
, int flags
, int methodOffset
, int propOffset
)
84 // start with properties:
85 if (flags
& (QDBusConnection::ExportScriptableProperties
|
86 QDBusConnection::ExportNonScriptableProperties
)) {
87 for (int i
= propOffset
; i
< mo
->propertyCount(); ++i
) {
88 static const char *accessvalues
[] = {0, "read", "write", "readwrite"};
90 QMetaProperty mp
= mo
->property(i
);
92 if (!((mp
.isScriptable() && (flags
& QDBusConnection::ExportScriptableProperties
)) ||
93 (!mp
.isScriptable() && (flags
& QDBusConnection::ExportNonScriptableProperties
))))
102 int typeId
= qDBusNameToTypeId(mp
.typeName());
105 const char *signature
= QDBusMetaType::typeToSignature(typeId
);
109 retval
+= QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
110 .arg(QLatin1String(mp
.name()))
111 .arg(QLatin1String(signature
))
112 .arg(QLatin1String(accessvalues
[access
]));
114 if (QDBusMetaType::signatureToType(signature
) == QVariant::Invalid
) {
115 const char *typeName
= QVariant::typeToName(QVariant::Type(typeId
));
116 retval
+= QString::fromLatin1(">\n <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
117 .arg(typeNameToXml(typeName
));
119 retval
+= QLatin1String("/>\n");
125 for (int i
= methodOffset
; i
< mo
->methodCount(); ++i
) {
126 QMetaMethod mm
= mo
->method(i
);
127 QByteArray signature
= mm
.signature();
128 int paren
= signature
.indexOf('(');
131 if (mm
.methodType() == QMetaMethod::Signal
)
134 else if (mm
.methodType() == QMetaMethod::Slot
&& mm
.access() == QMetaMethod::Public
)
137 continue; // neither signal nor public slot
139 if (isSignal
&& !(flags
& (QDBusConnection::ExportScriptableSignals
|
140 QDBusConnection::ExportNonScriptableSignals
)))
141 continue; // we're not exporting any signals
142 if (!isSignal
&& !(flags
& (QDBusConnection::ExportScriptableSlots
|
143 QDBusConnection::ExportNonScriptableSlots
)))
144 continue; // we're not exporting any slots
146 QString xml
= QString::fromLatin1(" <%1 name=\"%2\">\n")
147 .arg(isSignal
? QLatin1String("signal") : QLatin1String("method"))
148 .arg(QLatin1String(signature
.left(paren
)));
150 // check the return type first
151 int typeId
= qDBusNameToTypeId(mm
.typeName());
153 const char *typeName
= QDBusMetaType::typeToSignature(typeId
);
155 xml
+= QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n")
156 .arg(typeNameToXml(typeName
));
158 // do we need to describe this argument?
159 if (QDBusMetaType::signatureToType(typeName
) == QVariant::Invalid
)
160 xml
+= QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n")
161 .arg(typeNameToXml(mm
.typeName()));
165 else if (*mm
.typeName())
166 continue; // wasn't a valid type
168 QList
<QByteArray
> names
= mm
.parameterNames();
170 int inputCount
= qDBusParametersForMethod(mm
, types
);
171 if (inputCount
== -1)
172 continue; // invalid form
173 if (isSignal
&& inputCount
+ 1 != types
.count())
174 continue; // signal with output arguments?
175 if (isSignal
&& types
.at(inputCount
) == QDBusMetaTypeId::message
)
176 continue; // signal with QDBusMessage argument?
177 if (isSignal
&& mm
.attributes() & QMetaMethod::Cloned
)
178 continue; // cloned signal?
181 bool isScriptable
= mm
.attributes() & QMetaMethod::Scriptable
;
182 for (j
= 1; j
< types
.count(); ++j
) {
183 // input parameter for a slot or output for a signal
184 if (types
.at(j
) == QDBusMetaTypeId::message
) {
190 if (!names
.at(j
- 1).isEmpty())
191 name
= QString::fromLatin1("name=\"%1\" ").arg(QLatin1String(names
.at(j
- 1)));
193 bool isOutput
= isSignal
|| j
> inputCount
;
195 const char *signature
= QDBusMetaType::typeToSignature(types
.at(j
));
196 xml
+= QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
198 .arg(QLatin1String(signature
))
199 .arg(isOutput
? QLatin1String("out") : QLatin1String("in"));
201 // do we need to describe this argument?
202 if (QDBusMetaType::signatureToType(signature
) == QVariant::Invalid
) {
203 const char *typeName
= QVariant::typeToName( QVariant::Type(types
.at(j
)) );
204 xml
+= QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
205 .arg(isOutput
? QLatin1String("Out") : QLatin1String("In"))
206 .arg(isOutput
&& !isSignal
? j
- inputCount
: j
- 1)
207 .arg(typeNameToXml(typeName
));
213 wantedMask
= isSignal
? QDBusConnection::ExportScriptableSignals
214 : QDBusConnection::ExportScriptableSlots
;
216 wantedMask
= isSignal
? QDBusConnection::ExportNonScriptableSignals
217 : QDBusConnection::ExportNonScriptableSlots
;
218 if ((flags
& wantedMask
) != wantedMask
)
221 if (qDBusCheckAsyncTag(mm
.tag()))
222 // add the no-reply annotation
223 xml
+= QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT
"\""
224 " value=\"true\"/>\n");
227 retval
+= QString::fromLatin1(" </%1>\n")
228 .arg(isSignal
? QLatin1String("signal") : QLatin1String("method"));
234 QString
qDBusGenerateMetaObjectXml(QString interface
, const QMetaObject
*mo
,
235 const QMetaObject
*base
, int flags
)
237 if (interface
.isEmpty())
238 // generate the interface name from the meta object
239 interface
= qDBusInterfaceFromMetaObject(mo
);
242 int idx
= mo
->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION
);
243 if (idx
>= mo
->classInfoOffset())
244 return QString::fromUtf8(mo
->classInfo(idx
).value());
246 xml
= generateInterfaceXml(mo
, flags
, base
->methodCount(), base
->propertyCount());
249 return QString(); // don't add an empty interface
250 return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
251 .arg(interface
, xml
);
254 QString
qDBusGenerateMetaObjectXml(QString interface
, const QMetaObject
*mo
, const QMetaObject
*base
,
257 if (interface
.isEmpty()) {
258 // generate the interface name from the meta object
259 int idx
= mo
->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE
);
260 if (idx
>= mo
->classInfoOffset()) {
261 interface
= QLatin1String(mo
->classInfo(idx
).value());
263 interface
= QLatin1String(mo
->className());
264 interface
.replace(QLatin1String("::"), QLatin1String("."));
266 if (interface
.startsWith(QLatin1String("QDBus"))) {
267 interface
.prepend(QLatin1String("com.trolltech.QtDBus."));
268 } else if (interface
.startsWith(QLatin1Char('Q')) &&
269 interface
.length() >= 2 && interface
.at(1).isUpper()) {
271 interface
.prepend(QLatin1String("com.trolltech.Qt."));
272 } else if (!QCoreApplication::instance()||
273 QCoreApplication::instance()->applicationName().isEmpty()) {
274 interface
.prepend(QLatin1String("local."));
276 interface
.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
277 QStringList domainName
=
278 QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
279 QString::SkipEmptyParts
);
280 if (domainName
.isEmpty())
281 interface
.prepend(QLatin1String("local."));
283 for (int i
= 0; i
< domainName
.count(); ++i
)
284 interface
.prepend(QLatin1Char('.')).prepend(domainName
.at(i
));
290 int idx
= mo
->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION
);
291 if (idx
>= mo
->classInfoOffset())
292 return QString::fromUtf8(mo
->classInfo(idx
).value());
294 xml
= generateInterfaceXml(mo
, flags
, base
->methodCount(), base
->propertyCount());
297 return QString(); // don't add an empty interface
298 return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
299 .arg(interface
, xml
);