diff options
Diffstat (limited to 'python/pykde/extensions/dcopext.py')
-rw-r--r-- | python/pykde/extensions/dcopext.py | 721 |
1 files changed, 0 insertions, 721 deletions
diff --git a/python/pykde/extensions/dcopext.py b/python/pykde/extensions/dcopext.py deleted file mode 100644 index 539c4d6c..00000000 --- a/python/pykde/extensions/dcopext.py +++ /dev/null @@ -1,721 +0,0 @@ -#!/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_) |