File indexing completed on 2024-04-28 16:13:13

0001 #!/usr/bin/python
0002 #
0003 # Copyright (C) 2012 Collabora Limited <http://www.collabora.co.uk>
0004 # Copyright (C) 2012 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 # TODO generate docstrings
0029 
0030 def to_lower_camel_case(s):
0031     if len(s) <= 1:
0032         return s.lower()
0033 
0034     i = 0
0035     for c in s:
0036         if c == '_':
0037             break
0038         i += 1
0039 
0040     ret = s
0041     if i == len(s):
0042         return s.lower()
0043     else:
0044         ret = s[0:i].lower() + s[i:]
0045     ret = ret.replace('_', '')
0046     return ret
0047 
0048 class Generator(object):
0049     def __init__(self, opts):
0050         try:
0051             self.group = opts.get('--group', '')
0052             self.headerfile = opts['--headerfile']
0053             self.implfile = opts['--implfile']
0054             self.namespace = opts['--namespace']
0055             self.typesnamespace = opts['--typesnamespace']
0056             self.realinclude = opts.get('--realinclude', None)
0057             self.mocinclude = opts.get('--mocinclude', None)
0058             self.prettyinclude = opts.get('--prettyinclude')
0059             self.extraincludes = opts.get('--extraincludes', None)
0060             self.must_define = opts.get('--must-define', None)
0061             self.visibility = opts.get('--visibility', '')
0062             ifacedom = xml.dom.minidom.parse(opts['--ifacexml'])
0063             specdom = xml.dom.minidom.parse(opts['--specxml'])
0064         except KeyError, k:
0065             assert False, 'Missing required parameter %s' % k.args[0]
0066 
0067         if not self.realinclude:
0068             self.realinclude = self.headerfile
0069 
0070         self.hs = []
0071         self.bs = []
0072         self.ifacenodes = ifacedom.getElementsByTagName('node')
0073         self.spec, = get_by_path(specdom, "spec")
0074         self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace)
0075         self.externals = gather_externals(self.spec)
0076         self.refs = RefRegistry(self.spec)
0077 
0078     def __call__(self):
0079         # Output info header and includes
0080         self.h("""\
0081 /*
0082  * This file contains D-Bus adaptor classes generated by qt-svc-gen.py.
0083  *
0084  * This file can be distributed under the same terms as the specification from
0085  * which it was generated.
0086  */
0087 """)
0088 
0089         if self.must_define:
0090             self.h('\n')
0091             self.h('#ifndef %s\n' % self.must_define)
0092             self.h('#error %s\n' % self.must_define)
0093             self.h('#endif\n')
0094 
0095         self.h('\n')
0096 
0097         if self.extraincludes:
0098             for include in self.extraincludes.split(','):
0099                 self.h('#include %s\n' % include)
0100 
0101         self.h("""\
0102 #include <TelepathyQt/AbstractAdaptor>
0103 #include <TelepathyQt/Global>
0104 #include <TelepathyQt/Types>
0105 
0106 #include <QObject>
0107 #include <QtDBus>
0108 
0109 """)
0110 
0111         if self.must_define:
0112             self.b("""#define %s\n""" % (self.must_define))
0113 
0114         self.b("""#include "%s"
0115 
0116 """ % self.realinclude)
0117 
0118         if self.mocinclude:
0119             self.b("""#include "%s"
0120 
0121 """ % self.mocinclude)
0122 
0123             self.b("""\
0124 #include <TelepathyQt/Constants>
0125 #include <TelepathyQt/MethodInvocationContext>
0126 
0127 """)
0128 
0129         # Begin namespace
0130         for ns in self.namespace.split('::'):
0131             self.hb("""\
0132 namespace %s
0133 {
0134 """ % ns)
0135 
0136         # Output interface proxies
0137         def ifacenodecmp(x, y):
0138             xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor' for node in x, y]
0139 
0140             return cmp(xname, yname)
0141 
0142         self.ifacenodes.sort(cmp=ifacenodecmp)
0143         for ifacenode in self.ifacenodes:
0144             self.do_ifacenode(ifacenode)
0145 
0146         # End namespace
0147         self.hb(''.join(['\n}' for ns in self.namespace.split('::')]))
0148 
0149         # Write output to files
0150         (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs))
0151         (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs))
0152 
0153     def do_ifacenode(self, ifacenode):
0154         # Extract info
0155         name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor'
0156         iface, = get_by_path(ifacenode, 'interface')
0157         dbusname = iface.getAttribute('name')
0158         props = get_by_path(iface, 'property')
0159         methods = get_by_path(iface, 'method')
0160         signals = get_by_path(iface, 'signal')
0161 
0162         # Begin class, constructors
0163         self.h("""
0164 /**
0165  * \\class %(name)s
0166 %(headercmd)s\
0167 %(groupcmd)s\
0168  *
0169  * Adaptor class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s".
0170  */
0171 class %(visibility)s %(name)s : public Tp::AbstractAdaptor
0172 {
0173     Q_OBJECT
0174     Q_CLASSINFO("D-Bus Interface", "%(dbusname)s")
0175     Q_CLASSINFO("D-Bus Introspection", ""
0176 "  <interface name=\\"%(dbusname)s\\">\\n"
0177 """ % {'name': name,
0178        'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude),
0179        'groupcmd': self.group and (' * \\ingroup %s\n' % self.group),
0180        'dbusname': dbusname,
0181        'visibility': self.visibility,
0182        })
0183 
0184         self.do_introspection(props, methods, signals)
0185 
0186         self.h("""\
0187 "  </interface>\\n"
0188 "")
0189 """)
0190 
0191         self.do_qprops(props)
0192 
0193         self.h("""
0194 public:
0195     %(name)s(const QDBusConnection& dbusConnection, QObject* adaptee, QObject* parent);
0196     virtual ~%(name)s();
0197 
0198 """ % {'name': name})
0199 
0200         self.do_mic_typedefs(methods)
0201 
0202         self.b("""
0203 %(name)s::%(name)s(const QDBusConnection& bus, QObject* adaptee, QObject* parent)
0204     : Tp::AbstractAdaptor(bus, adaptee, parent)
0205 {
0206 """ % {'name': name})
0207 
0208         self.do_signals_connect(signals)
0209 
0210         self.b("""\
0211 }
0212 
0213 %(name)s::~%(name)s()
0214 {
0215 }
0216 """ % {'name': name})
0217 
0218         # Properties
0219         has_props = False
0220         if props:
0221             self.h("""
0222 public: // PROPERTIES
0223 """)
0224 
0225             for prop in props:
0226                 # Skip tp:properties
0227                 if not prop.namespaceURI:
0228                     self.do_prop(name, prop)
0229                     has_props = True
0230 
0231         # Methods
0232         if methods:
0233             self.h("""
0234 public Q_SLOTS: // METHODS
0235 """)
0236 
0237             for method in methods:
0238                 self.do_method(name, method)
0239 
0240         # Signals
0241         if signals:
0242             self.h("""
0243 Q_SIGNALS: // SIGNALS
0244 """)
0245 
0246             for signal in signals:
0247                 self.do_signal(signal)
0248 
0249         # Close class
0250         self.h("""\
0251 };
0252 """)
0253 
0254     def do_introspection(self, props, methods, signals):
0255         self.do_prop_introspection(props)
0256         self.do_method_introspection(methods)
0257         self.do_signal_introspection(signals)
0258 
0259     def do_prop_introspection(self, props):
0260         for prop in props:
0261             if prop.namespaceURI:
0262                 continue
0263 
0264             name = prop.getAttribute('name')
0265             access = prop.getAttribute('access')
0266             sig = prop.getAttribute('type')
0267             tptype = prop.getAttributeNS(NS_TP, 'type')
0268             binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
0269 
0270             if not binding.custom_type:
0271                 self.h("""\
0272 "    <property access=\\"%(access)s\\" type=\\"%(sig)s\\" name=\\"%(name)s\\"/>\\n"
0273 """ % {'access': access,
0274        'sig': sig,
0275        'name': name,
0276        })
0277             else:
0278                 self.h("""\
0279 "    <property access=\\"%(access)s\\" type=\\"%(sig)s\\" name=\\"%(name)s\\">\\n"
0280 "      <annotation value=\\"%(type)s\\" name=\\"com.trolltech.QtDBus.QtTypeName\\"/>\\n"
0281 "    </property>\\n"
0282 """ % {'access': access,
0283        'sig': sig,
0284        'name': name,
0285        'type': binding.val,
0286        })
0287 
0288     def do_method_introspection(self, methods):
0289         for method in methods:
0290             name = method.getAttribute('name')
0291             args = get_by_path(method, 'arg')
0292             argnames, argdocstrings, argbindings = extract_arg_or_member_info(args,
0293                 self.custom_lists, self.externals, self.typesnamespace, self.refs, '     *     ')
0294 
0295             if not argnames:
0296                 self.h("""\
0297 "    <method name=\\"%(name)s\\"/>\\n"
0298 """ % {'name': name})
0299             else:
0300                 self.h("""\
0301 "    <method name=\\"%(name)s\\">\\n"
0302 """ % {'name': name})
0303 
0304                 outindex = 0
0305                 inindex = 0
0306                 for i in xrange(len(argnames)):
0307                     assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
0308 
0309                     argbinding = argbindings[i]
0310                     argname = argnames[i]
0311                     argsig = args[i].getAttribute('type')
0312                     argdirection = args[i].getAttribute('direction')
0313 
0314                     # QtDBus requires annotating a{sv}
0315                     if argsig == 'a{sv}':
0316                         argbinding.custom_type = True
0317 
0318                     if not argbinding.custom_type:
0319                         self.h("""\
0320 "      <arg direction=\\"%(direction)s\\" type=\\"%(sig)s\\" name=\\"%(name)s\\"/>\\n"
0321 """ % {'direction': argdirection,
0322        'sig': argsig,
0323        'name': argname})
0324                     else:
0325                         self.h("""\
0326 "      <arg direction=\\"%(direction)s\\" type=\\"%(sig)s\\" name=\\"%(name)s\\">\\n"
0327 "        <annotation value=\\"%(type)s\\" name=\\"com.trolltech.QtDBus.QtTypeName.%(index)s\\"/>\\n"
0328 "      </arg>\\n"
0329 """ % {'direction': argdirection,
0330        'sig': argsig,
0331        'name': argname,
0332        'type': argbinding.val,
0333        'index': 'In' + str(inindex) if argdirection == 'in' else 'Out' + str(outindex),
0334        })
0335 
0336                     if argdirection == 'out':
0337                         outindex += 1
0338                     else:
0339                         inindex += 1
0340 
0341                 self.h("""\
0342 "    </method>\\n"
0343 """)
0344 
0345     def do_signal_introspection(self, signals):
0346         for signal in signals:
0347             name = signal.getAttribute('name')
0348             args = get_by_path(signal, 'arg')
0349             argnames, argdocstrings, argbindings = extract_arg_or_member_info(args,
0350                 self.custom_lists, self.externals, self.typesnamespace, self.refs, '     *     ')
0351 
0352             if not argnames:
0353                 self.h("""\
0354 "    <signal name=\\"%(name)s\\"/>\\n"
0355 """ % {'name': name})
0356             else:
0357                 self.h("""\
0358 "    <signal name=\\"%(name)s\\">\\n"
0359 """ % {'name': name})
0360 
0361                 for i in xrange(len(argnames)):
0362                     assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
0363 
0364                     argbinding = argbindings[i]
0365                     argname = argnames[i]
0366                     argsig = args[i].getAttribute('type')
0367 
0368                     if not argbinding.custom_type:
0369                         self.h("""\
0370 "      <arg type=\\"%(sig)s\\" name=\\"%(name)s\\"/>\\n"
0371 """ % {'sig': argsig,
0372        'name': argname})
0373                     else:
0374                         self.h("""\
0375 "      <arg type=\\"%(sig)s\\" name=\\"%(name)s\\">\\n"
0376 "        <annotation value=\\"%(type)s\\" name=\\"com.trolltech.QtDBus.QtTypeName.In%(index)d\\"/>\\n"
0377 "      </arg>\\n"
0378 """ % {'sig': argsig,
0379        'name': argname,
0380        'type': argbinding.val,
0381        'index': i,
0382        })
0383 
0384                 self.h("""\
0385 "    </signal>\\n"
0386 """)
0387 
0388     def do_mic_typedefs(self, methods):
0389         for method in methods:
0390             name = method.getAttribute('name')
0391             args = get_by_path(method, 'arg')
0392             argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
0393                     self.externals, self.typesnamespace, self.refs, '     *     ')
0394 
0395             outargs = []
0396             for i in xrange(len(args)):
0397                 if args[i].getAttribute('direction') == 'out':
0398                     outargs.append(i)
0399 
0400             if outargs:
0401                 outargtypes = ', '.join([argbindings[i].val for i in outargs])
0402             else:
0403                 outargtypes = ''
0404 
0405             self.h("""\
0406     typedef Tp::MethodInvocationContextPtr< %(outargtypes)s > %(name)sContextPtr;
0407 """ % {'name': name,
0408        'outargtypes': outargtypes,
0409        })
0410 
0411     def do_qprops(self, props):
0412         for prop in props:
0413             # Skip tp:properties
0414             if not prop.namespaceURI:
0415                 self.do_qprop(prop)
0416 
0417     def do_qprop(self, prop):
0418         name = prop.getAttribute('name')
0419         access = prop.getAttribute('access')
0420         gettername = name
0421         settername = None
0422         if 'write' in access:
0423             settername = 'Set' + name
0424 
0425         sig = prop.getAttribute('type')
0426         tptype = prop.getAttributeNS(NS_TP, 'type')
0427         binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
0428 
0429         self.h("""\
0430     Q_PROPERTY(%(type)s %(name)s %(getter)s %(setter)s)
0431 """ % {'type': binding.val,
0432        'name': name,
0433        'getter': 'READ ' + gettername if ('read' in access) else '',
0434        'setter': 'WRITE ' + settername if ('write' in access) else '',
0435        })
0436 
0437     def do_prop(self, ifacename, prop):
0438         name = prop.getAttribute('name')
0439         adaptee_name = to_lower_camel_case(prop.getAttribute('tp:name-for-bindings'))
0440         access = prop.getAttribute('access')
0441         gettername = name
0442         settername = None
0443         if 'write' in access:
0444             settername = 'Set' + name
0445         docstring = format_docstring(prop, self.refs, '     * ').replace('*/', '&#42;&#47;')
0446 
0447         sig = prop.getAttribute('type')
0448         tptype = prop.getAttributeNS(NS_TP, 'type')
0449         binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
0450 
0451         if 'read' in access:
0452             self.h("""\
0453     /**
0454      * Return the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s.
0455      *
0456      * Adaptees should export this property as a Qt property named
0457      * '%(adaptee_name)s' with type %(type)s.
0458      *
0459 %(docstring)s\
0460      *
0461      * \\return The value of exported property \\c %(name)s.
0462      */
0463     %(type)s %(gettername)s() const;
0464 """ % {'name': name,
0465        'adaptee_name': adaptee_name,
0466        'docstring': docstring,
0467        'type': binding.val,
0468        'gettername': gettername,
0469        })
0470 
0471             self.b("""
0472 %(type)s %(ifacename)s::%(gettername)s() const
0473 {
0474     return qvariant_cast< %(type)s >(adaptee()->property("%(adaptee_name)s"));
0475 }
0476 """ % {'type': binding.val,
0477        'ifacename': ifacename,
0478        'gettername': gettername,
0479        'adaptee_name': adaptee_name,
0480        })
0481 
0482         if 'write' in access:
0483             self.h("""\
0484     /**
0485      * Set the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s.
0486      *
0487      * Adaptees should export this property as a writable Qt property named
0488      * '%(adaptee_name)s' with type %(type)s.
0489      *
0490 %(docstring)s\
0491      */
0492     void %(settername)s(const %(type)s &newValue);
0493 """ % {'name': name,
0494        'adaptee_name': adaptee_name,
0495        'docstring': docstring,
0496        'settername': settername,
0497        'type': binding.val,
0498        })
0499 
0500             self.b("""
0501 void %(ifacename)s::%(settername)s(const %(type)s &newValue)
0502 {
0503     adaptee()->setProperty("%(adaptee_name)s", qVariantFromValue(newValue));
0504 }
0505 """ % {'ifacename': ifacename,
0506        'settername': settername,
0507        'type': binding.val,
0508        'adaptee_name': adaptee_name,
0509        })
0510 
0511     def do_method(self, ifacename, method):
0512         name = method.getAttribute('name')
0513         adaptee_name = to_lower_camel_case(method.getAttribute('tp:name-for-bindings'))
0514         args = get_by_path(method, 'arg')
0515         argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
0516                 self.externals, self.typesnamespace, self.refs, '     *     ')
0517         docstring = format_docstring(method, self.refs, '     * ').replace('*/', '&#42;&#47;')
0518 
0519         inargs = []
0520         outargs = []
0521 
0522         for i in xrange(len(args)):
0523             if args[i].getAttribute('direction') == 'out':
0524                 outargs.append(i)
0525             else:
0526                 inargs.append(i)
0527                 assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name)
0528 
0529         if outargs:
0530             rettype = argbindings[outargs[0]].val
0531         else:
0532             rettype = 'void'
0533 
0534         params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs]
0535         params.append('const QDBusMessage& dbusMessage')
0536         params += [argbindings[i].outarg + ' ' + argnames[i] for i in outargs[1:]]
0537         params = ', '.join(params)
0538 
0539         if outargs:
0540             outargtypes = ', '.join([argbindings[i].val for i in outargs])
0541         else:
0542             outargtypes = ''
0543         invokemethodargs = ', '.join(['Q_ARG(' + argbindings[i].val + ', ' + argnames[i] + ')' for i in inargs])
0544 
0545         inparams = [argbindings[i].val for i in inargs]
0546         inparams.append("%s::%s::%sContextPtr" % (self.namespace, ifacename, name))
0547         normalized_adaptee_params = ','.join(inparams)
0548 
0549         adaptee_params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs]
0550         adaptee_params.append('const %(namespace)s::%(ifacename)s::%(name)sContextPtr &context' %
0551             {'namespace': self.namespace,
0552              'ifacename': ifacename,
0553              'name': name})
0554         adaptee_params = ', '.join(adaptee_params)
0555 
0556         self.h("""\
0557     /**
0558      * Begins a call to the exported D-Bus method \\c %(name)s on this object.
0559      *
0560      * Adaptees should export this method as a Qt slot with the following signature:
0561      * void %(adaptee_name)s(%(adaptee_params)s);
0562      *
0563      * Implementations should call MethodInvocationContext::setFinished (or setFinishedWithError
0564      * accordingly) on the received \\a context object once the method has finished processing.
0565      *
0566 %(docstring)s\
0567      *
0568 """ % {'name': name,
0569         'adaptee_name': adaptee_name,
0570         'adaptee_params': adaptee_params,
0571         'rettype': rettype,
0572         'docstring': docstring
0573         })
0574 
0575         for i in inargs:
0576             if argdocstrings[i]:
0577                 self.h("""\
0578      * \\param %s
0579 %s\
0580 """ % (argnames[i], argdocstrings[i]))
0581 
0582         for i in outargs[1:]:
0583             if argdocstrings[i]:
0584                 self.h("""\
0585      * \\param %s Output parameter
0586 %s\
0587 """ % (argnames[i], argdocstrings[i]))
0588 
0589         if outargs:
0590                 self.h("""\
0591      * \\return
0592 %s\
0593 """ % argdocstrings[outargs[0]])
0594 
0595         self.h("""\
0596      */
0597     %(rettype)s %(name)s(%(params)s);
0598 """ % {'rettype': rettype,
0599        'name': name,
0600        'params': params
0601        })
0602 
0603         self.b("""
0604 %(rettype)s %(ifacename)s::%(name)s(%(params)s)
0605 {
0606     if (!adaptee()->metaObject()->indexOfMethod("%(adaptee_name)s(%(normalized_adaptee_params)s)") == -1) {
0607         dbusConnection().send(dbusMessage.createErrorReply(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")));
0608 """ % {'rettype': rettype,
0609        'ifacename': ifacename,
0610        'name': name,
0611        'adaptee_name': adaptee_name,
0612        'normalized_adaptee_params': normalized_adaptee_params,
0613        'params': params,
0614        })
0615 
0616         if rettype != 'void':
0617             self.b("""\
0618         return %(rettype)s();
0619 """ % {'rettype': rettype})
0620         else:
0621             self.b("""\
0622         return;
0623 """)
0624 
0625         self.b("""\
0626     }
0627 
0628     %(name)sContextPtr ctx = %(name)sContextPtr(
0629             new Tp::MethodInvocationContext< %(outargtypes)s >(dbusConnection(), dbusMessage));
0630 """ % {'name': name,
0631        'outargtypes': outargtypes,
0632        })
0633 
0634         if invokemethodargs:
0635             self.b("""\
0636     QMetaObject::invokeMethod(adaptee(), "%(adaptee_name)s",
0637         %(invokemethodargs)s,
0638         Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx));
0639 """ % {'namespace': self.namespace,
0640        'ifacename': ifacename,
0641        'name': name,
0642        'adaptee_name': adaptee_name,
0643        'invokemethodargs': invokemethodargs,
0644        })
0645         else:
0646             self.b("""\
0647     QMetaObject::invokeMethod(adaptee(), "%(lname)s",
0648         Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx));
0649 """ % {'namespace': self.namespace,
0650        'ifacename': ifacename,
0651        'name': name,
0652        'lname': (name[0].lower() + name[1:]),
0653        })
0654 
0655         if rettype != 'void':
0656             self.b("""\
0657     return %(rettype)s();
0658 """ % {'rettype': rettype})
0659 
0660         self.b("}\n")
0661 
0662     def do_signal(self, signal):
0663         name = signal.getAttribute('name')
0664         adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings'))
0665         argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal,
0666             'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, '     *     ')
0667         params = ', '.join(['%s %s' % (binding.inarg, param_name) for binding, param_name in zip(argbindings, argnames)])
0668 
0669         for i in xrange(len(argnames)):
0670             assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
0671 
0672         self.h("""\
0673     /**
0674      * Represents the exported D-Bus signal \\c %(name)s on this object.
0675      *
0676      * Adaptees should export this signal as a Qt signal with the following signature:
0677      * void %(adaptee_name)s(%(params)s);
0678      *
0679      * The adaptee signal will be automatically relayed as a D-Bus signal once emitted.
0680      *
0681 """ % {'name': name,
0682        'adaptee_name': adaptee_name,
0683        'params': params
0684        })
0685 
0686         for i in xrange(len(argnames)):
0687             assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
0688             if argdocstrings[i]:
0689                 self.h("""\
0690      * \\param %s
0691 %s\
0692 """ % (argnames[i], argdocstrings[i]))
0693 
0694         self.h("""\
0695      */
0696     void %(name)s(%(params)s);
0697 """ % {'name': name,
0698        'params': params
0699        })
0700 
0701     def do_signals_connect(self, signals):
0702         for signal in signals:
0703             name = signal.getAttribute('name')
0704             adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings'))
0705             _, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'),
0706                     self.custom_lists, self.externals, self.typesnamespace, self.refs, '     *     ')
0707 
0708             self.b("""\
0709     connect(adaptee, SIGNAL(%(adaptee_name)s(%(params)s)), SIGNAL(%(name)s(%(params)s)));
0710 """ % {'name': name,
0711        'adaptee_name': adaptee_name,
0712        'params': ', '.join([binding.inarg for binding in argbindings])
0713        })
0714 
0715     def h(self, str):
0716         self.hs.append(str)
0717 
0718     def b(self, str):
0719         self.bs.append(str)
0720 
0721     def hb(self, str):
0722         self.h(str)
0723         self.b(str)
0724 
0725 
0726 if __name__ == '__main__':
0727     options, argv = gnu_getopt(argv[1:], '',
0728             ['group=',
0729              'headerfile=',
0730              'implfile=',
0731              'namespace=',
0732              'typesnamespace=',
0733              'realinclude=',
0734              'mocinclude=',
0735              'prettyinclude=',
0736              'extraincludes=',
0737              'must-define=',
0738              'visibility=',
0739              'ifacexml=',
0740              'specxml='])
0741 
0742     Generator(dict(options))()