summaryrefslogtreecommitdiffstats
path: root/python/pykde/extensions/dcopexport.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/pykde/extensions/dcopexport.py')
-rw-r--r--python/pykde/extensions/dcopexport.py196
1 files changed, 196 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