Warning, file /network/telepathy-logger-qt/tools/qt-client-gen.py was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #!/usr/bin/python 0002 # 0003 # Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk> 0004 # Copyright (C) 2008 Nokia Corporation 0005 # 0006 # This library is free software; you can redistribute it and/or 0007 # modify it under the terms of the GNU Lesser General Public 0008 # License as published by the Free Software Foundation; either 0009 # version 2.1 of the License, or (at your option) any later version. 0010 # 0011 # This library is distributed in the hope that it will be useful, 0012 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 # Lesser General Public License for more details. 0015 # 0016 # You should have received a copy of the GNU Lesser General Public 0017 # License along with this library; if not, write to the Free Software 0018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 0019 0020 from sys import argv 0021 import xml.dom.minidom 0022 import codecs 0023 from getopt import gnu_getopt 0024 0025 from libtpcodegen import NS_TP, get_descendant_text, get_by_path 0026 from libqtcodegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt_name, qt_identifier_escape, RefRegistry 0027 0028 class Generator(object): 0029 def __init__(self, opts): 0030 try: 0031 self.group = opts.get('--group', '') 0032 self.headerfile = opts['--headerfile'] 0033 self.implfile = opts['--implfile'] 0034 self.namespace = opts['--namespace'] 0035 self.typesnamespace = opts['--typesnamespace'] 0036 self.realinclude = opts['--realinclude'] 0037 self.prettyinclude = opts.get('--prettyinclude') 0038 self.extraincludes = opts.get('--extraincludes', None) 0039 self.mainiface = opts.get('--mainiface', None) 0040 self.must_define = opts.get('--must-define', None) 0041 self.dbus_proxy = opts.get('--dbus-proxy', 0042 'Tp::DBusProxy') 0043 self.visibility = opts.get('--visibility', '') 0044 ifacedom = xml.dom.minidom.parse(opts['--ifacexml']) 0045 specdom = xml.dom.minidom.parse(opts['--specxml']) 0046 except KeyError, k: 0047 assert False, 'Missing required parameter %s' % k.args[0] 0048 0049 self.hs = [] 0050 self.bs = [] 0051 self.ifacenodes = ifacedom.getElementsByTagName('node') 0052 self.spec, = get_by_path(specdom, "spec") 0053 self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace) 0054 self.externals = gather_externals(self.spec) 0055 self.refs = RefRegistry(self.spec) 0056 0057 def __call__(self): 0058 # Output info header and includes 0059 self.h("""\ 0060 /* 0061 * This file contains D-Bus client proxy classes generated by qt-client-gen.py. 0062 * 0063 * This file can be distributed under the same terms as the specification from 0064 * which it was generated. 0065 */ 0066 """) 0067 0068 if self.must_define: 0069 self.h('\n') 0070 self.h('#ifndef %s\n' % self.must_define) 0071 self.h('#error %s\n' % self.must_define) 0072 self.h('#endif\n') 0073 0074 self.h('\n') 0075 0076 if self.extraincludes: 0077 for include in self.extraincludes.split(','): 0078 self.h('#include %s\n' % include) 0079 0080 self.h(""" 0081 #include <QtGlobal> 0082 0083 #include <QString> 0084 #include <QObject> 0085 #include <QVariant> 0086 0087 #include <QDBusPendingReply> 0088 0089 #include <TelepathyQt/AbstractInterface> 0090 #include <TelepathyQt/DBusProxy> 0091 #include <TelepathyQt/Global> 0092 0093 namespace Tp 0094 { 0095 class PendingVariant; 0096 class PendingOperation; 0097 } 0098 0099 """) 0100 0101 if self.must_define: 0102 self.b("""#define %s\n""" % (self.must_define)) 0103 0104 self.b("""#include "%s" 0105 0106 """ % self.realinclude) 0107 0108 # Begin namespace 0109 for ns in self.namespace.split('::'): 0110 self.hb("""\ 0111 namespace %s 0112 { 0113 """ % ns) 0114 0115 # Output interface proxies 0116 def ifacenodecmp(x, y): 0117 xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' for node in x, y] 0118 0119 if xname == self.mainiface: 0120 return -1 0121 elif yname == self.mainiface: 0122 return 1 0123 else: 0124 return cmp(xname, yname) 0125 0126 self.ifacenodes.sort(cmp=ifacenodecmp) 0127 for ifacenode in self.ifacenodes: 0128 self.do_ifacenode(ifacenode) 0129 0130 # End namespace 0131 self.hb(''.join(['}\n' for ns in self.namespace.split('::')])) 0132 0133 # Add metatype declaration - otherwise QTBUG #2151 might be triggered 0134 for ifacenode in self.ifacenodes: 0135 classname = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' 0136 self.h("Q_DECLARE_METATYPE(" + self.namespace + "::" + classname + "*)\n") 0137 0138 # Write output to files 0139 (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs)) 0140 (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs)) 0141 0142 def do_ifacenode(self, ifacenode): 0143 # Extract info 0144 name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' 0145 iface, = get_by_path(ifacenode, 'interface') 0146 dbusname = iface.getAttribute('name') 0147 0148 # Begin class, constructors 0149 self.h(""" 0150 /** 0151 * \\class %(name)s 0152 %(headercmd)s\ 0153 %(groupcmd)s\ 0154 * 0155 * Proxy class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s". 0156 */ 0157 class %(visibility)s %(name)s : public Tp::AbstractInterface 0158 { 0159 Q_OBJECT 0160 0161 public: 0162 /** 0163 * Returns the name of the interface "%(dbusname)s", which this class 0164 * represents. 0165 * 0166 * \\return The D-Bus interface name. 0167 */ 0168 static inline QLatin1String staticInterfaceName() 0169 { 0170 return QLatin1String("%(dbusname)s"); 0171 } 0172 0173 /** 0174 * Creates a %(name)s associated with the given object on the session bus. 0175 * 0176 * \\param busName Name of the service the object is on. 0177 * \\param objectPath Path to the object on the service. 0178 * \\param parent Passed to the parent class constructor. 0179 */ 0180 %(name)s( 0181 const QString& busName, 0182 const QString& objectPath, 0183 QObject* parent = 0 0184 ); 0185 0186 /** 0187 * Creates a %(name)s associated with the given object on the given bus. 0188 * 0189 * \\param connection The bus via which the object can be reached. 0190 * \\param busName Name of the service the object is on. 0191 * \\param objectPath Path to the object on the service. 0192 * \\param parent Passed to the parent class constructor. 0193 */ 0194 %(name)s( 0195 const QDBusConnection& connection, 0196 const QString& busName, 0197 const QString& objectPath, 0198 QObject* parent = 0 0199 ); 0200 """ % {'name' : name, 0201 'headercmd' : get_headerfile_cmd(self.realinclude, self.prettyinclude), 0202 'groupcmd' : self.group and (' * \\ingroup %s\n' % self.group), 0203 'dbusname' : dbusname, 0204 'visibility': self.visibility, 0205 }) 0206 0207 self.b(""" 0208 %(name)s::%(name)s(const QString& busName, const QString& objectPath, QObject *parent) 0209 : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), QDBusConnection::sessionBus(), parent) 0210 { 0211 } 0212 0213 %(name)s::%(name)s(const QDBusConnection& connection, const QString& busName, const QString& objectPath, QObject *parent) 0214 : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), connection, parent) 0215 { 0216 } 0217 """ % {'name' : name}) 0218 0219 # Construct from DBusProxy subclass 0220 self.h(""" 0221 /** 0222 * Creates a %(name)s associated with the same object as the given proxy. 0223 * 0224 * \\param proxy The proxy to use. It will also be the QObject::parent() 0225 * for this object. 0226 */ 0227 %(name)s(%(dbus_proxy)s *proxy); 0228 """ % {'name' : name, 0229 'dbus_proxy' : self.dbus_proxy}) 0230 0231 self.b(""" 0232 %(name)s::%(name)s(%(dbus_proxy)s *proxy) 0233 : Tp::AbstractInterface(proxy, staticInterfaceName()) 0234 { 0235 } 0236 """ % {'name' : name, 0237 'dbus_proxy' : self.dbus_proxy}) 0238 0239 # Main interface 0240 mainiface = self.mainiface or 'Tp::AbstractInterface' 0241 0242 if mainiface != self.namespace + '::' + name: 0243 self.h(""" 0244 /** 0245 * Creates a %(name)s associated with the same object as the given proxy. 0246 * Additionally, the created proxy will have the same parent as the given 0247 * proxy. 0248 * 0249 * \\param mainInterface The proxy to use. 0250 */ 0251 explicit %(name)s(const %(mainiface)s& mainInterface); 0252 0253 /** 0254 * Creates a %(name)s associated with the same object as the given proxy. 0255 * However, a different parent object can be specified. 0256 * 0257 * \\param mainInterface The proxy to use. 0258 * \\param parent Passed to the parent class constructor. 0259 */ 0260 %(name)s(const %(mainiface)s& mainInterface, QObject* parent); 0261 """ % {'name' : name, 0262 'mainiface' : mainiface}) 0263 0264 self.b(""" 0265 %(name)s::%(name)s(const %(mainiface)s& mainInterface) 0266 : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), mainInterface.parent()) 0267 { 0268 } 0269 0270 %(name)s::%(name)s(const %(mainiface)s& mainInterface, QObject *parent) 0271 : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), parent) 0272 { 0273 } 0274 """ % {'name' : name, 0275 'mainiface' : mainiface}) 0276 0277 # Properties 0278 has_props = False 0279 for prop in get_by_path(iface, 'property'): 0280 # Skip tp:properties 0281 if not prop.namespaceURI: 0282 self.do_prop(prop) 0283 has_props = True 0284 0285 self.h(""" 0286 /** 0287 * Request all of the DBus properties on the interface. 0288 * 0289 * \\return A pending variant map which will emit finished when the properties have 0290 * been retrieved. 0291 */ 0292 Tp::PendingVariantMap *requestAllProperties() const 0293 { 0294 return internalRequestAllProperties(); 0295 } 0296 """) 0297 0298 # Methods 0299 methods = get_by_path(iface, 'method') 0300 0301 if methods: 0302 self.h(""" 0303 public Q_SLOTS:\ 0304 """) 0305 0306 for method in methods: 0307 self.do_method(method) 0308 0309 # Signals 0310 signals = get_by_path(iface, 'signal') 0311 0312 if signals: 0313 self.h(""" 0314 Q_SIGNALS:\ 0315 """) 0316 0317 for signal in signals: 0318 self.do_signal(signal) 0319 0320 # invalidated handler (already a slot in the superclass) 0321 # we can't just use disconnect(this, NULL, NULL, NULL) because 0322 # (a) that would disconnect QObject::destroyed() and other non-D-Bus 0323 # signals, and (b) QtDBus doesn't support that usage anyway (it needs 0324 # specific signals in order to remove its signal match rules) 0325 self.h(""" 0326 protected: 0327 virtual void invalidate(Tp::DBusProxy *, const QString &, const QString &); 0328 """) 0329 0330 self.b(""" 0331 void %(name)s::invalidate(Tp::DBusProxy *proxy, 0332 const QString &error, const QString &message) 0333 { 0334 """ % {'name' : name}) 0335 0336 for signal in signals: 0337 self.do_signal_disconnect(signal) 0338 0339 self.b(""" 0340 Tp::AbstractInterface::invalidate(proxy, error, message); 0341 } 0342 """) 0343 0344 # Close class 0345 self.h("""\ 0346 }; 0347 """) 0348 0349 def do_prop(self, prop): 0350 name = prop.getAttribute('name') 0351 access = prop.getAttribute('access') 0352 gettername = name 0353 settername = None 0354 docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '*/') 0355 0356 sig = prop.getAttribute('type') 0357 tptype = prop.getAttributeNS(NS_TP, 'type') 0358 binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace) 0359 0360 if 'write' in access: 0361 settername = 'set' + name 0362 0363 if 'read' in access: 0364 self.h(""" 0365 /** 0366 * Asynchronous getter for the remote object property \\c %(name)s of type \\c %(val)s. 0367 * 0368 %(docstring)s\ 0369 * 0370 * \\return A pending variant which will emit finished when the property has been 0371 * retrieved. 0372 */ 0373 inline Tp::PendingVariant *%(gettername)s() const 0374 { 0375 return internalRequestProperty(QLatin1String("%(name)s")); 0376 } 0377 """ % {'name' : name, 0378 'docstring' : docstring, 0379 'val' : binding.val, 0380 'gettername' : 'requestProperty' + name}) 0381 0382 if 'write' in access: 0383 self.h(""" 0384 /** 0385 * Asynchronous setter for the remote object property \\c %(name)s of type \\c %(type)s. 0386 * 0387 %(docstring)s\ 0388 * 0389 * \\return A pending operation which will emit finished when the property has been 0390 * set. 0391 */ 0392 inline Tp::PendingOperation *%(settername)s(%(type)s newValue) 0393 { 0394 return internalSetProperty(QLatin1String("%(name)s"), QVariant::fromValue(newValue)); 0395 } 0396 """ % {'name' : name, 0397 'docstring' : docstring, 0398 'type' : binding.val, 0399 'name' : name, 0400 'settername' : 'setProperty' + name}) 0401 0402 def do_method(self, method): 0403 name = method.getAttribute('name') 0404 args = get_by_path(method, 'arg') 0405 argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, 0406 self.externals, self.typesnamespace, self.refs, ' * ') 0407 0408 inargs = [] 0409 outargs = [] 0410 0411 for i in xrange(len(args)): 0412 if args[i].getAttribute('direction') == 'out': 0413 outargs.append(i) 0414 else: 0415 inargs.append(i) 0416 assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name) 0417 0418 rettypes = ', '.join([argbindings[i].val for i in outargs]) 0419 params = ', '.join([argbindings[i].inarg + ' ' + argnames[i] for i in inargs]) 0420 if params: 0421 params += ', int timeout = -1' 0422 else: 0423 params = 'int timeout = -1' 0424 0425 self.h(""" 0426 /** 0427 * Begins a call to the D-Bus method \\c %s on the remote object. 0428 %s\ 0429 * 0430 * Note that \\a timeout is ignored as of now. It will be used once 0431 * http://bugreports.qt.nokia.com/browse/QTBUG-11775 is fixed. 0432 * 0433 """ % (name, format_docstring(method, self.refs, ' * '))) 0434 0435 for i in inargs: 0436 if argdocstrings[i]: 0437 self.h("""\ 0438 * 0439 * \\param %s 0440 %s\ 0441 """ % (argnames[i], argdocstrings[i])) 0442 0443 self.h("""\ 0444 * \\param timeout The timeout in milliseconds. 0445 """) 0446 0447 for i in outargs: 0448 if argdocstrings[i]: 0449 self.h("""\ 0450 * 0451 * \\return 0452 %s\ 0453 """ % argdocstrings[i]) 0454 0455 self.h("""\ 0456 */ 0457 inline QDBusPendingReply<%(rettypes)s> %(name)s(%(params)s) 0458 { 0459 if (!invalidationReason().isEmpty()) { 0460 return QDBusPendingReply<%(rettypes)s>(QDBusMessage::createError( 0461 invalidationReason(), 0462 invalidationMessage() 0463 )); 0464 } 0465 """ % {'rettypes' : rettypes, 0466 'name' : name, 0467 'params' : params}) 0468 0469 if inargs: 0470 self.h(""" 0471 QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(), 0472 this->staticInterfaceName(), QLatin1String("%s")); 0473 callMessage << %s; 0474 return this->connection().asyncCall(callMessage, timeout); 0475 } 0476 """ % (name, ' << '.join(['QVariant::fromValue(%s)' % argnames[i] for i in inargs]))) 0477 else: 0478 self.h(""" 0479 QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(), 0480 this->staticInterfaceName(), QLatin1String("%s")); 0481 return this->connection().asyncCall(callMessage, timeout); 0482 } 0483 """ % name) 0484 0485 def do_signal(self, signal): 0486 name = signal.getAttribute('name') 0487 argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal, 0488 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') 0489 0490 self.h(""" 0491 /** 0492 * Represents the signal \\c %s on the remote object. 0493 %s\ 0494 """ % (name, format_docstring(signal, self.refs, ' * '))) 0495 0496 for i in xrange(len(argnames)): 0497 assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) 0498 if argdocstrings[i]: 0499 self.h("""\ 0500 * 0501 * \\param %s 0502 %s\ 0503 """ % (argnames[i], argdocstrings[i])) 0504 0505 self.h("""\ 0506 */ 0507 void %s(%s); 0508 """ % (name, ', '.join(['%s %s' % (binding.inarg, name) for binding, name in zip(argbindings, argnames)]))) 0509 0510 def do_signal_disconnect(self, signal): 0511 name = signal.getAttribute('name') 0512 _, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'), 0513 self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') 0514 0515 self.b("""\ 0516 disconnect(this, SIGNAL(%s(%s)), NULL, NULL); 0517 """ % (name, ', '.join([binding.inarg for binding in argbindings]))) 0518 0519 def h(self, str): 0520 self.hs.append(str) 0521 0522 def b(self, str): 0523 self.bs.append(str) 0524 0525 def hb(self, str): 0526 self.h(str) 0527 self.b(str) 0528 0529 0530 if __name__ == '__main__': 0531 options, argv = gnu_getopt(argv[1:], '', 0532 ['group=', 0533 'namespace=', 0534 'typesnamespace=', 0535 'headerfile=', 0536 'implfile=', 0537 'ifacexml=', 0538 'specxml=', 0539 'realinclude=', 0540 'prettyinclude=', 0541 'extraincludes=', 0542 'mainiface=', 0543 'must-define=', 0544 'dbus-proxy=', 0545 'visibility=']) 0546 0547 Generator(dict(options))()