Commits

Henning Schröder committed e488b02

added support for newInstance

Comments (0)

Files changed (1)

+# -*- coding: utf-8 -*-
 import sys
+from PyQt4.QtCore import QMetaMethod, pyqtSlot, QObject
 from PyQt4.QtGui import QApplication, QPushButton
 
 
 
-class QtMethodCall(object):
+class QtMethodCall(QObject):
     
-    def __init__(self, obj, method):
-        self._obj = obj
-        self._method = method
+
+    def __init__(self, obj, methods):
+        QObject.__init__(self)
+        self.obj = obj
+        self.methods = methods
         
+        
+    def __repr__(self):
+        return "<instance method %r of %r>" % (self.methods.values()[0].name, self.obj)
+
+    
+    def _matching_method_for_signature(self, arg_types):
+        for i, (signature, method) in enumerate(self.methods.items()):
+            pass
+        return method
+
+
     def __call__(self, *args, **kwargs):
+        print "called", args, self.obj, self.methods
         if kwargs:
-            raise TypeError
-        method = getattr(self._obj, self._method.name)
-        return method(*args)
+            raise TypeError("Keyword arguments are not supported currently")
+        arg_types = [type(a) for a in args]
+        method = self._matching_method_for_signature(arg_types)
+        call = getattr(self.obj._qt, method.name)
+        return call(*args)
+
+
+    @pyqtSlot()
+    def _parameterless_callback(self):
+        print "'>>called", self
+        return self()
+
+
 
 
 class QtMethod(object):
         self.param_names = self._mm.parameterNames()
         self.param_types = self._mm.parameterTypes()
         self.return_type = self._mm.typeName()
+        self.method_type = self._mm.methodType()
+
     
     def __repr__(self):
         return "%s %s(%s)" % (
               self.return_type or "void", self.name, self.signature)
 
+              
+
+
+class QtMethodSignal(object):
+    
+
+    def __init__(self, obj, signal, signature=None):
+        self.obj = obj
+        self.signal = signal
+        self.signature = signature
+
+        
+    def __repr__(self):
+        return "<Signal %r of %r>" % (self.signal, self.obj)
+
+
+    def connect(self, callback):
+        signal = getattr(self.obj._qt, self.signal.name)
+        if isinstance(callback, QtMethodCall) and not self.signature:
+            print "connect", signal, callback
+            # cannot guess empty signature  with __call__(*args,**kwargs)
+            signal.connect(callback._parameterless_callback)
+            return
+    
+        if self.signature:
+            signal[self.signature].connect(callback)
+        else:
+            signal.connect(callback)
+
+
+    def __getitem__(self, *args):
+        return self.__class__(self.obj, self.signal, signature=args)
+
+
 
 
 class QtMethodDispatcher(object):
     def __init__(self, name, methods):
         self.name = name
         self.methods = methods
+
         
+    def __repr__(self):
+        return "<QtMethod %r>" % self.name
+
+
     def __get__(self, obj, cls):
+        print "* get", self
         if obj is None:
             return self
-        print "get", self.name
-        for signature, method in self.methods.items():
-            return QtMethodCall(obj, method)
+        signal = None
+        for method in self.methods.values():
+            if method.method_type == QMetaMethod.Signal:
+                signal = QtMethodSignal(obj, method)
+                break
+        # calls to the same method will be cached inside the object
+        if signal:
+            setattr(obj, self.name, signal)
+            return signal
+        else:
+            call = QtMethodCall(obj, self.methods)
+            setattr(obj, self.name, call)
+            return call
 
-    
+
+
+
 class QtProperty(object):
 
 
     def __init__(self, meta_property):
         self._mp = meta_property
-        self.name = self._mp.name()
+        self.name = self._mp.name().capitalize()
         self.type = self._mp.type()
 
         
             obj = obj._qt
         self._mp.write(obj, value)
 
-        
+
+
+
 class PyQtClass(object):
     
-    def __init__(self, instance):
+
+    def __init__(self, *args, **kwargs):
+        if args and len(args) == 1 and isinstance(args, QObject):
+            instance = args[0]
+        else:
+            instance = self.__metaobject.newInstance(*args, **kwargs)
         self._qt = instance
+        self._slots = []
 
-    #def __members__(self):
-    #    return []
+
     def __repr__(self):
         return repr(self._qt)
 
             
     def __getattr__(self, name):
-        try:
-            return getattr(self._qt, name)
-        except AttributeError:
-            return self._qt.property(name)
+        pnames = [unicode(n) for n in self._qt.dynamicPropertyNames()]
+        if name.lower() in pnames:
+            return self._qt.property(name.lower()).toPyObject()
+        raise AttributeError("%s has not attribute %r" % (self, name))
+
         
 
-def create_proxy_class(meta_object):
+def create_proxy_class(meta_object, bases=(PyQtClass,), attrs=None):
     mo = meta_object
     properties = {}
     for pi in range(mo.propertyCount()):
         meta_method = mo.method(mi)
         m = QtMethod(meta_method)
         methods.setdefault(m.name, {})[m.signature] = m
-    attrs = {}
+    if attrs is None:
+        attrs = {}
     for k, v in properties.items():
         attrs[k] = v
+    attrs["__properties"] = properties
     for k, v in methods.items():
         attrs[k] = QtMethodDispatcher(k, v)
+    attrs["__methods"] = methods
+    attrs["__metaobject"] = meta_object
     class_name = mo.className()
-    bases = (PyQtClass,)
     return type(class_name, bases, attrs)
 
 
+
+# cache classes
+_qt_classes = {}
+
+
+def class_from_metaobject(meta_object):
+    class_name = meta_object.className()
+    cls = _qt_classes.get(class_name, None)
+    if not cls:
+        cls = create_proxy_class(meta_object)
+        _qt_classes[class_name] = cls
+    return cls
+
+
 def wrap_qt_instance(instance):
-    cls = create_proxy_class(instance.metaObject())
+    cls = class_from_metaobject(instance.metaObject())
     return cls(instance)
 
 
 
-a = QApplication(sys.argv)
-b = QPushButton(None)
-p = wrap_qt_instance(b)
-p.text = "Foo"
-p.show()
 
-if 0:
-    #b.setText("Hello, world!")
-    b.clicked.connect(b.close)
-    b.show()
-    a.exec_()
+
+
+if __name__ == "__main__":
+    a = QApplication(sys.argv)
+    ap = wrap_qt_instance(a)
+    
+    def on_click():
+        print "clicked!"
+        ap.quit()
+
+
+    b = QPushButton(None)
+    p = wrap_qt_instance(b)
+    p.Text = "Click to close!"
+    print p.clicked.connect(on_click)
+
+    print p.show
+    print p.show