diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 90825e2392b2d70e43c7a25b8a3752299a933894 (patch) | |
tree | e33aa27f02b74604afbfd0ea4f1cfca8833d882a /python/pykde/extensions | |
download | tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'python/pykde/extensions')
-rw-r--r-- | python/pykde/extensions/dcopexport.py | 196 | ||||
-rw-r--r-- | python/pykde/extensions/dcopext.py | 721 |
2 files changed, 917 insertions, 0 deletions
diff --git a/python/pykde/extensions/dcopexport.py b/python/pykde/extensions/dcopexport.py new file mode 100644 index 00000000..d724adef --- /dev/null +++ b/python/pykde/extensions/dcopexport.py @@ -0,0 +1,196 @@ +""" +Copyright 2004 Jim Bublitz + +Terms and Conditions + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Except as contained in this notice, the name of the copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from the +copyright holder. +""" + +""" +This is a re-implementation in Python of pcop.cpp written by Torben Weis +and Julian Rockey, modified for Python and PyKDE. + +To "DCOP-enable" an application, subclass DCOPExObj (be sure to call the +base class' __init__ method) and use 'addMethod' to identify the methods +which will be exposed via DCOP along with names of the Python methods that +implement the exposed methods. + +A DCOP client application when doing DCOPCLient.call (...) will end up +running the 'process' method which demarshalls the arguments, calls the +specified Python method with the arg values passed in, and marshalls the +return value to be returned to the caller. + +DCOPExMeth is basically a data structure to hold the parsed method info +(name, arg list, return type, signature) + +This module requires the dcopext module, but only for the numericTypes and +stringTypes lists +""" + + +from dcop import DCOPObject, DCOPClient +from kdecore import dcop_add, dcop_next +from qt import QString, QCString, QDataStream, IO_ReadOnly, IO_WriteOnly + +numericTypes = ["char", "bool", "short", "int", "long", "uchar", "ushort", "uint", "ulong", + "unsigned char", "unsigned short", "unsigned int", "unsigned long", + "Q_INT32", "pid_t", "float", "double"] +stringTypes = ["QString", "QCString"] + +class DCOPExObj (DCOPObject): + def __init__ (self, objid = None): + if isinstance (objid, str): + DCOPObject.__init__ (self, objid) + else: + DCOPObject.__init__ (self) + + self.methods = {} + + def process (self, meth, data, replyType, replyData): + # normalize the method signature received + meth = str (DCOPClient.normalizeFunctionSignature (meth)).replace (">", "> ") + + # see if this method is available from us via DCOP + # if we don't have it, maybe DCOPObject already provides it (eg - qt object) + if not self.matchMethod (meth): + return DCOPObject.process(self, meth, data, replyType, replyData); + + # demarshall the arg list for the actual method call and call the method + s = QDataStream (data, IO_ReadOnly) + arglist = [] + count = len (self.method.argtypes) + if count == 0: + result = self.method.pymethod () + else: + for i in range (len (self.method.argtypes)): + arglist.append (dcop_next (s, QCString (self.method.argtypes [i]))) + + result = self.method.pymethod (*arglist) + + # marshall the result as 'replyData' + if self.method.rtype != "void": + s = QDataStream (replyData, IO_WriteOnly) + if self.method.rtype in numericTypes: + dcop_add (s, result, self.method.rtype) + elif self.method.rtype in stringTypes and isinstance (result, str): + dcop_add (s, eval ("%s('''%s''')" % (self.method.rtype, result))) + elif self.method.rtype.startswith ("QMap") or self.method.rtype.startswith ("QValueList"): + dcop_add (params, args [i], self.argtypes [i]) + else: + dcop_add (s, result) + + # use append because we want to return the replyType reference, + # not a new QCString + replyType.append (self.method.rtype) + + # success + return True + + def addMethod (self, signature, pymethod): + """ + add a method to the dict - makes it available to DCOP + signature - a string representing the C++ form of the method declaration + with arg names removed (eg + pymethod - the Python method corresponding to the method in signature + + example: + def someMethod (a, b): + return str (a + b) + + signature = "QString someMethod (int, int)" + pymethod = someMethod + self.addMethod (signature, pymethod) + + note that in this case you could add a second entry: + + self.addMethod ("QString someMethod (float, float)", someMethod) + + pymethod can also be a class method, for example - self.someMethod or + someClass.someMethod. In the second case, someClass has to be an instance + of a class (perhaps SomeClass), not the class itself. + + self.methods is a dict holding all of the methods exposed, indexed by + method signature. In the example above, the signature would be: + + someMethod(QString,QString) + + or everything but the return type, which is stored in the dict entry. + The dict entry is a DCOPExMeth instance. + """ + method = DCOPExMeth (signature, pymethod) + if method.sig: + self.methods [method.sig] = method + return method.sig != None + + def matchMethod (self, meth): + # find the method in the dict if it's there + self.method = None + if meth in self.methods: + self.method = self.methods [meth] + return self.method != None + + def functions (self): + # build the list of methods exposed for 'remoteFunctions' calls + # from the entries in the self.methods dict + funcs = DCOPObject.functions (self) + for func in self.methods.keys (): + funcs.append (" ".join ([self.methods [func].rtype, func])) + return funcs; + +class DCOPExMeth: + """ + Encapsulates all of the method data - signature, arg list, return type + and corresponding Python method to be called + """ + def __init__ (self, method, pymethod): + self.pymethod = pymethod + if not self.parseMethod (method): + self.fcnname = self.sig = self.rtype = self.argtypes = None + + def parseMethod (self, method): + # strip whitespace + method = str (DCOPClient.normalizeFunctionSignature (method)).replace (">", "> ") + + # the return type (rtype) and signature (sig) + self.rtype, tail = method.split (" ", 1) + self.sig = tail + if not tail: + return False + self.rtype = self.rtype.strip () + + i = tail.find ("(") + if i < 1: + return False + + # the name of the method + self.fcnname = tail [:i].strip () + "(" + + # the list of arg types + self.argtypes = [] + args = tail [i + 1 : -1].split (",") + if args and args != [""]: + for arg in args: + self.argtypes.append (arg.strip ()) + + return True diff --git a/python/pykde/extensions/dcopext.py b/python/pykde/extensions/dcopext.py new file mode 100644 index 00000000..539c4d6c --- /dev/null +++ b/python/pykde/extensions/dcopext.py @@ -0,0 +1,721 @@ +#!/usr/bin/env python +# -*- coding: ISO-8859-1 -*- + +""" +Copyright 2004 Jim Bublitz (original author) + 2006 Mathias Panzenböck (panzi) <grosser.meister.morti@gmx.net> + +Terms and Conditions + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Except as contained in this notice, the name of the copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from the +copyright holder. +""" + +import re +from dcop import DCOPClient +from qt import QString, QCString, QByteArray, QDataStream, IO_ReadOnly, IO_WriteOnly +from kdecore import dcop_add, dcop_next + +# XXX: 64 bit integers might be handeld wrong! pythons int is AFAIK 32 bit, +# but pythons long is a arbitrary-precision integer. how to handle that? +# +# I think 64 bit types would be: +# long long, unsigned long long, long long int, unsigned long long int, +# Q_LLONG, Q_ULLONG, Q_INT64, Q_UINT64 +# +# and on some (most?) systems: +# QtOffset + +# add complex? complex is c99, not c++ +# but python has a complex type +POD = set(['char','short','int','long','float','double']) +typedefIntTypes = set(["uchar", "ushort", "uint", "ulong", + "Q_INT8", "Q_INT16", "Q_INT32", "Q_LONG", + "Q_UINT8", "Q_UINT16", "Q_UINT32", "Q_ULONG", + "sitze_t", "ssize_t", "int8_t", "int16_t", "int32_t", + "uint8_t", "uint16_t", "uint32_t", "pid_t", "uid_t", + "off_t"]) +# XXX string and std::string too? +stringTypes = set(["QString", "QCString"]) +pythonStringTypes = set([QString, QCString, str]) +stringTypesDict = {"QString":QString,"QCString":QCString,"str":str,"unicode":unicode} + +VOID = 0 +BOOLEAN = 1 # XXX bool is not supported by dcop_add, but maybe some time... +INTEGER = 2 +FLOAT = 3 +STRING = 4 +CLASS = 5 + +""" +(Most of this code is adapted from pydcop in kde-bindings, written by +Torben Weis and Julian Rockey) + +The three classes below (DCOPApp, DCOPObj and DCOPMeth) +allow transparent Python calls to DCOP methods. For example: + + d = DCOPApp ("kicker", dcop) + +(where "kicker" is the complete name of an application and 'dcop' is +the dcopClient instance owned by the KApplication creating the DCOPApp +instance) creates a DCOPApp instance. All of the classes in this +file "borrow" a DCOPClient instance from the calling application. + + d.objects + +will return a list of the DCOP objects the application supplies. + + o = d.object ("Panel") + +will return a DCOPObj corresponding to applications "Panel" DCOP object. + +Similarly: + + o.methods + +will return a list of the methods the object supplies and + + m = o.method ("panelSize") + +will return a DCOPMeth corresponding to Panel's panelSize() method. +The m instance also holds the methods return type, list of argument types +(argtypes) and argument names (argnames). + + m.valid + +is a boolean which indicates if the method encapsulated by m is a valid +method for the application/object specified. + +However it isn't necessary to explicitly create the DCOPObj and DCOPMeth. + + d.Panel.panelSize.valid + +for example, will also indicate if the method is valid without creating the +intermediate 'o' and 'm' instances explicitly. + + d = DCOPApp ("kicker", dcop) + ok, res = d.Panel.panelSize () + +is all the code necessary to perform the indicated DCOP call and return the +value the call returns. In this case, panelSize takes no arguments and +returns an int. 'ok' returns the status of the DCOP call (success = True, +failure = False). + + ok = d.Panel.addURLButton (QString ("http://www.kde.org")) + +would call addURLButton with the required argument, and return nothing but the DCOP call +status(since its return type is 'void'). + +Note that to instantiate a DCOPObj directly, you need to have a valid DCOPApp +to pass to DCOPObj's __init__ method. Similarly, DCOPMeth requires a valid DCOPOBject. +For example: + + d = DCOPApp ("kicker", dcop) + o = DCOPObj (d, "Panel") + m = DCOPMeth (o, "panelSize") + +or + + m = DCOPMeth (DCOPObj (DCOPApp ("kicker", dcop), "Panel"), "panelSize") + +""" + +# support stuff: +def _xiter(*seqences): + iters = [iter(seq) for seq in seqences] + + try: + while True: + yield [it.next() for it in iters] + + except StopIteration: + pass + +def isStringType(s): + for stringType in pythonStringTypes: + if isinstance(s,stringType): + return True + return False + +# method syntax: +# -------------- +# method ::= rtype identifier( args ) +# rtype ::= "void" | type +# identifier ::= [_a-zA-Z][_a-zA-Z0-9]* +# args ::= ( arg ("," arg)* )? +# arg ::= type identifier? +# type ::= namespace typespec | POD +# POD ::= ( "unsigned" | "signed" )? identifier +# namespace ::= (identifier "::")* | "::" +# typespec ::= identifier ( "<" tpyelist ">" )? +# typelist ::= (type | int) ("," (type | int) )* +# int ::= "0x" [0-9a-fA-F]+ | [0-9]+ + +class MethodParser(object): + ident_r = re.compile("[_a-zA-Z][_a-zA-Z0-9]*") + num_r = re.compile("0x[0-0a-fA-F]+|[0-9]+") + + def __init__(self,method): + self.method = str(method) + self.rtype = None + self.name = None + self.args = [] + + self.parseMethod() + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self.method)) + + def getDecl(self): + return ''.join([self.name, '(', ','.join(argtp for (argtp, kind), argname in self.args), ')']) + + def parseMethod(self): + i = self.parseRtype(self.method,0) + i, self.name = self.parseIdentifier(self.method,i) + i = self.parseArgs(self.method,i) + + if i != len(self.method): + raise SyntaxError, "invalid function definition: %s" % self.method + + @staticmethod + def skipws(s,i): + while s[i:i+1].isspace(): + i += 1 + return i + + def parseArg(self,s,i): + i, tp = self.parseType(s,i) + name = self.parseIdentifier(s,i) + + if name: + i, name = name + else: + name = None + + return i, (tp, name) + + def parseIdentifier(self,s,i): + i = MethodParser.skipws(s,i) + m = MethodParser.ident_r.match(s,i) + + if m: + return m.end(), s[i:m.end()] + else: + return False + + def parseInteger(self,s,i): + i = MethodParser.skipws(s,i) + m = MethodParser.num_r.match(s,i) + + if m: + return m.end(), s[i:m.end()] + else: + return False + + def parseArgs(self,s,i): + i = MethodParser.skipws(s,i) + + if s[i:i+1] == '(': + i += 1 + i = MethodParser.skipws(s,i) + + while i < len(s) and s[i:i+1] != ')': + i, arg = self.parseArg(s,i) + i = MethodParser.skipws(s,i) + + self.args.append(arg) + + if s[i:i+1] == ',': + i += 1 + + else: + break + + if s[i:i+1] == ')': + i += 1 + else: + raise SyntaxError, "missing ')'." + else: + raise SyntaxError, "missing '('." + + return i + + def parseType(self,s,i): + num = self.parseNumberType(s,i) + + if num: + return num + + i, ns = self.parseNamespace(s,i) + i, tp = self.parseTypespec(s,i) + + tp = ns + tp + + if tp in stringTypes: + return i, (tp, STRING) + + else: + return i, (tp, CLASS) + + def parseTypespec(self,s,i): + i, tp = self.parseIdentifier(s,i) + i, tplst = self.parseTypelist(s,i) + + return i, tp + tplst + + def parseTypelist(self,s,i): + L = [] + newi = MethodParser.skipws(s,i) + + if s[newi:newi+1] == '<': + i = newi + 1 + i = MethodParser.skipws(s,i) + + L.append('<') + + while i < len(s) and s[i:i+1] != '>': + # template-parameter can be integers!! + + num = self.parseInteger(s,i) + + if num: + i, tp = num + + else: + i, (tp, kind) = self.parseType(s,i) + + i = MethodParser.skipws(s,i) + + L.append(tp) + + if s[i:i+1] == ',': + i += 1 + L.append(',') + + else: + break + + + if s[i:i+1] == '>': + i += 1 + L.append('>') + + else: + raise SyntaxError, "missing '>'." + + return i, ''.join(L) + + def parseNumberType(self,s,i): + i, tp = self.parseIdentifier(s,i) + L = [] + + if tp == 'bool': + return i, (tp, BOOLEAN) + + elif tp in typedefIntTypes: + return i, (tp, INTEGER) + + elif tp in ('signed','unsigned'): + L.append(tp) + next = self.parseIdentifier(s,i) + + if next and next[1] in POD: + i, tp = next + + else: + # type can be fully quallyfied here! + return i, (tp, INTEGER) + + if tp in POD: + L.append(tp) + + else: + # else no number-type at all! + + return False + + # long + # long int + # long long + # long long int + # long double + # short + # short int + + if tp == 'short': + # short + + next = self.parseIdentifier(s,i) + + if next and next[1] == 'int': + # short int + + i, tp = next + L.append(tp) + + elif tp == 'long': + # long + + next = self.parseIdentifier(s,i) + + if next: + if next[1] in ('int', 'double'): + # long int + # long double + + i, tp = next + L.append(tp) + + elif next[1] == 'long': + # long long + # XXX: this is 64bit! how should I handle this? + + i, tp = next + L.append(tp) + + next = self.parseIdentifier(s,i) + + if next and next[1] == 'int': + # long long int + + i, tp = next + L.append(tp) + + if tp in ('float', 'double'): + return i, (' '.join(L), FLOAT) + + else: + return i, (' '.join(L), INTEGER) + + # + # :: + # foo:: + # ::foo:: + # foo::bar:: + # ::foo::bar:: + # ... + def parseNamespace(self,s,i): + L = [] + i = MethodParser.skipws(s,i) + + if s[i:i+2] == "::": + i += 2 + L.append("::") + + while i < len(s): + ns = self.parseIdentifier(s,i) + + if not ns: + break + + newi, ns = ns + newi = MethodParser.skipws(s,newi) + + if s[newi:newi+2] != "::": + break + + i = newi + 2 + + L.append( ns ) + L.append( "::" ) + + return i, ''.join(L) + + + def parseRtype(self,s,i): + tp = self.parseIdentifier(s,i) + + if tp and tp[1] == 'void': + i, tp = tp + self.rtype = (tp,VOID) + + else: + i, self.rtype = self.parseType(s,i) + + return i + +def DCOPAppsIter(client): + for app in client.registeredApplications(): + yield str(app) + +class DCOPApp(object): + """ + An object corresponding to an application with a DCOP interface + + Can return a list of the DCOP objects the application exposes, + or create and return an instance of a specific DCOP object. + """ + def __init__ (self, name, client): + self.appname = name + self.appclient = client + + def __getattr__ (self, item ): + if item == "objects": + objs, ok = self.appclient.remoteObjects(self.appname) + + if ok: + return objs + else: + return None + + return DCOPObj(self, item) + + def __iter__(self): + objs, ok = self.appclient.remoteObjects(self.appname) + + if ok: + for obj in objs: + yield str(obj) + + # sometimes a object-name is not a valid python identifier. + # in that case you can use dcopapp['non-valid::object/name'] + def __getitem__(self,name): + return DCOPObj(self, name) + + def object (self, object): + return DCOPObj (self, object) + + def __repr__(self): + return '%s(%s,%s)' % (self.__class__.__name__,repr(self.appname),repr(self.appclient)) + + def __str__(self): + return repr(self) + +class DCOPObj(object): + """ + An object corresponding to a specific DCOP object owned by a + specific application with a DCOP interface + + Can return a list of the DCOP methods the object exposes, + or create and return an instance of a specific DCOP method. + """ + + def __init__ (self, *args): + if isStringType(args[0]): + self.appname = args [0] + self.objclient = args [1] + self.objname = args [2] + else: + self.appname = args [0].appname + self.objname = args [1] + self.objclient = args [0].appclient + + self.objmethods = self.getMethods() + + def __repr__( self ): + return "%s(%s,%s)" % (self.__class__.__name__,repr(self.appname), repr(self.objname)) + + def __str__( self ): + return repr(self) + + def __getattr__( self, item ): + if item == "methods": + return self.objmethods + + return DCOPMeth(self, item) + + def __getitem__(self,name): + return DCOPMeth(self, name) + + def getMethods(self): + flist, ok = self.objclient.remoteFunctions(self.appname, self.objname) + + if ok: + return flist + else: + return None + + def __iter__(self): + flist, ok = self.objclient.remoteFunctions(self.appname, self.objname) + + if ok: + for meth in flist: + yield str(meth) + + def getMethodNames(self): + return [MethodParser(meth).name for meth in self.objmethods] + + def getParsedMethods(self): + return [MethodParser(meth) for meth in self.objmethods] + + def method(self, method): + return DCOPMeth(self, method) + +class DCOPMeth(object): + """ + An object corresponding to a specific DCOP method owned by a + specific DCOP object. + """ + def __init__(self, dcopObj, name): + self.argtypes = [] + self.argnames = [] + self.fcnname = [] + self.rtype = [] + self.appname = dcopObj.appname + self.objname = dcopObj.objname + self.methname = name + self.client = dcopObj.objclient + self.methods = [str(meth) for meth in dcopObj.objmethods] + self.valid = self.findMethod() +# +# if not self.valid: +# self.fcnname = self.rtype = self.argtypes = self.argnames = None + + def __repr__( self ): + return "%s(%s,%s,%s)" % (self.__class__.__name__,repr(self.appname),repr(self.objname),repr(self.methname)) + + def __str__(self): + return repr(self) + + def __call__(self, *args): + return self.dcop_call(args) + + def __iter__(self): + return iter(self.fcnname) + + def dcop_call(self, args): + # method valid? + if not self.valid: + return False, None + + found = self.getMatchingMethod(args) + + if found is None: + return False, None + + meth, argtypes = found + + ok, replyType, replyData = self.client.call(self.appname, self.objname, meth, self.__marshall(args,argtypes)) + + if ok: + return ok, self.__unmarshall(replyData, replyType) + else: + return ok, None + + def getMatchingMethod(self,args): + count = len(args) + + for funct, argtypes in _xiter(self.fcnname, self.argtypes): + if len(argtypes) == count: + match = True + + for (wanttp, wantkind), have in _xiter(argtypes,args): + if wantkind == BOOLEAN: + if not isinstance(have, bool): + match = False + break + + elif wantkind == INTEGER: + if not isinstance(have, int): + match = False + break + + elif wantkind == FLOAT: + if not isinstance(have, float): + match = False + break + + elif wantkind == STRING: + if not isStringType(have): + match = False + break + + elif wanttp != have.__class__.__name__: + match = False + break + + if match: + return funct, argtypes + return None + + def findMethod(self): + has = False + + for meth in self.methods: + fun = MethodParser(meth) + + if fun.name == self.methname: + self.argtypes.append([argtp for argtp, argname in fun.args]) + self.argnames.append([argname for argtp, argname in fun.args]) + self.rtype.append(fun.rtype) + self.fcnname.append(fun.getDecl()) + + has = True + + return has + + def __marshall(self, args, argtypes): + data = QByteArray() + if argtypes == []: + return data + + params = QDataStream (data, IO_WriteOnly) + + for arg, (argtype, argkind) in _xiter(args, argtypes): + if argkind == BOOLEAN: + # XXX for now, let bools be handelt like int + dcop_add(params, int(arg), 'int') + + elif argkind in (INTEGER, FLOAT): + dcop_add(params, arg, argtype) + + elif argkind == STRING: + # convert it to the right string type: + if argtype != arg.__class__.__name__: + arg = stringTypesDict[argtype](arg) + + dcop_add(params, arg) + + elif argtype.startswith("QMap") or argtype.startswith("QValueList"): + dcop_add(params, arg, argtype) + + # XXX: + # Is 'isinstance(arg, eval(argtype))' really good? + # What if 'argtype' is located in some modul? Like 'qt.QString'. + # Then this will fail (but it should not!). + # And the worst thing: the eval() will raise a NameError! + # + # On the other hand 'arg.__class__.__name__ == argtype' has the + # disadvantage that it can't be a derived class! + # + # Would no check at all be better?? + # + # But I doubt a derived class would be ok anyway. I have to check + # this in the DCOP-docu, but I think a derived class would not be + # correctly unmarshalled, because a derived class could be marshalled + # in a total different way to it's super-class. + elif arg.__class__.__name__ == argtype: + dcop_add(params, arg) + + else: + raise TypeError, "expected type %s, got type %s." % (argtype, arg.__class__.__name__) + + return data + + def __unmarshall(self, data, type_): + s = QDataStream(data, IO_ReadOnly) + + if str(type_) in stringTypes: + return str(dcop_next(s, type_)) + else: + return dcop_next(s, type_) |