File indexing completed on 2024-04-21 05:01:51

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