diff d2/qt/core/QMetaObject.d @ 368:185df9220ea7

Fixed startsWith. Implemented meta-object members as ranges. Freed QMetaObject from stuff that belongs to MetaClass
author Max Samukha <maxter@maxter.com>
date Mon, 28 Jun 2010 21:29:32 +0300
parents f69341b40588
children 6e1857c521af
line wrap: on
line diff
--- a/d2/qt/core/QMetaObject.d	Thu Jun 24 13:47:30 2010 +0300
+++ b/d2/qt/core/QMetaObject.d	Mon Jun 28 21:29:32 2010 +0300
@@ -14,23 +14,30 @@
     std.c.stdlib;
 
 import std.string : indexOf;
+import std.algorithm : filter;
 
-class QMetaArgument : Meta
+//TODO: remove
+import std.stdio;
+
+class QMetaArgument : MetaBase
 {
 }
 
-class QMetaMethod : Meta
+class QMetaMethod : MetaBase
 {
     alias typeof(this) This;
 
 //    QMetaArgument[]  arguments;
     string signature;
-    int indexOfMethod;
+    int index;
 
-    this(string signature_, int indexOfMethod_)
+    this(string signature, int index)
     {
-        signature = signature_;
-        indexOfMethod = indexOfMethod_;
+        this.signature = signature;
+        this.index = index;
+
+        int openBracket = indexOf(signature, '(');
+        name = signature[0..openBracket];
     }
 
     string args() const
@@ -42,27 +49,22 @@
             return "";
     }
 
-    string name() const
-    {
-        int openBracket = indexOf(signature, '(');
-        return signature[0..openBracket];
-    }
-
-    // mixin(Derived) or typeof(Derived) would help a lot here
-    static create(alias method, M : This)(uint index)
+    static M create(alias method, M : This)(uint index)
     {
         alias ParameterTypeTuple!method Args;
         return new M(.signature!(Args)(methodName!(method)), index);
     }
 }
 
+/**
+ */
 class QMetaSignal : QMetaMethod
 {
     alias typeof(this) This;
 
-    this(string signature_, int indexOfMethod_)
+    this(string signature, int indexOfMethod)
     {
-        super(signature_, indexOfMethod_);
+        super(signature, indexOfMethod);
     }
 
     static This create(alias method)(uint index)
@@ -75,9 +77,9 @@
 {
     alias typeof(this) This;
 
-    this(string signature_, int indexOfMethod_)
+    this(string signature, int indexOfMethod)
     {
-        super(signature_, indexOfMethod_);
+        super(signature, indexOfMethod);
     }
 
     static This create(alias method)(uint index)
@@ -86,9 +88,31 @@
     }
 }
 
-class MetaObject : MetaType
+/**
+    Base class for QtD meta-classes.
+ */
+abstract class QtdMetaClass : MetaClass
 {
-    MetaObject _base;
+private:
+    void* nativeId_;
+
+public:
+
+    this() {}
+
+    /**
+     */
+    @property
+    void* nativeId()
+    {
+        return nativeId_;
+    }
+
+    void construct(T)()
+    {
+        super.construct!T();
+        nativeId_ = T.qtd_nativeStaticMetaObject();
+    }
 }
 
 struct QMetaObjectNative
@@ -99,13 +123,16 @@
     void *extradata;
 }
 
-class QMetaException : Exception { this(string msg) { super(msg); } }
 
-final class QMetaObject
+/**
+ */
+final class QMetaObject : QtdMetaClass
 {
     alias typeof(this) This;
 
-    private this() {}
+    private QObject function(void* nativeId) _createWrapper;
+
+    this() {}
 
     enum Call
     {
@@ -121,42 +148,11 @@
         CreateInstance
     }
 
-    private
-    {
-        QMetaObjectNative* _nativeId;
-        QMetaObject _base; // super class
-        QMetaObject _firstDerived; // head of the linked list of derived classes
-        QMetaObject _next; // next sibling on this derivation level
-        QMetaMethod[] _methods;
-        ClassInfo _classInfo;
-
-        QObject function(void* nativeId) _createWrapper;
-    }
-
-    private void addDerived(QMetaObject mo)
-    {
-        mo._next = _firstDerived;
-        _firstDerived = mo;
-    }
+    alias createImpl!This create;
 
-    // ctor
-    void construct(T : QObject)(void* nativeId)
+    void construct(T : QObject)()
     {
-        alias BaseClassesTuple!(T)[0] Base;
-        This base;
-        static if (is(Base : QObject))
-            base = Base.staticMetaObject;
-
-        _nativeId = cast(QMetaObjectNative*)nativeId;
-        T.setStaticMetaObject(this);
-
-        if (base)
-        {
-            base.addDerived(this);
-            _base = base;
-        }
-        _classInfo = T.classinfo;
-
+        super.construct!T();
 
         static if (isQtType!T)
         {
@@ -171,12 +167,13 @@
                     return obj;
                 };
 
-            T._populateMetaInfo;
+            T._populateMetaInfo(this);
         }
         // create run time meta-objects for user-defined signals and slots
         else static if (is(typeof(T.methods)))
         {
-            int index = Base.staticMetaObject().methodCount();
+            alias BaseClassesTuple!(T)[0] Base;
+            int index = meta!(Base).methodCount;
 
             static if (T.signals.length)
             {
@@ -198,101 +195,83 @@
         }
     }
 
-    // new
-    static This create(T : QObject)(void* nativeId)
+    /**
+     */
+    @property
+    override This next()
     {
-        auto m = new This();
-        m.construct!T(nativeId);
-        return m;
-    }
-
-    /++
-    +/
-    QMetaObject base()
-    {
-        return _base;
+        return static_cast!This(super.next);
     }
 
-    /++
-    +/
-    QMetaObjectNative* nativeId()
+    /**
+     */
+    @property
+    override This firstDerived()
     {
-        return _nativeId;
+        return static_cast!This(super.firstDerived);
     }
 
-    /++
-    +/
-    ClassInfo classInfo()
+    void addMethod(QMetaMethod method)
     {
-        return _classInfo;
+        members_ ~= method;
     }
 
-    const (QMetaMethod[]) methods()
+    /**
+     */
+    @property
+    override This base()
     {
-        return _methods;
-    }
-
-    void addMethod(QMetaMethod method_)
-    {
-        _methods ~= method_;
+        return super.base;
     }
 
-    QMetaMethod lookUpMethod(string slot)
+    /**
+     */
+    @property
+    QMetaObjectNative* nativeId()
     {
-        foreach (method; _methods)
-            if (method.signature == slot)
-                return method;
-        if (_base)
-            return _base.lookUpMethod(slot);
-        else
-            return null;
-    }
-
-    QMetaSignal lookUpSignal(string signal)
-    {
-        foreach (method; _methods)
-            if (method.signature == signal && cast(QMetaSignal)method)
-                return cast(QMetaSignal)method;
-        if (_base)
-            return _base.lookUpSignal(signal);
-        else
-            return null;
+        return cast(QMetaObjectNative*)super.nativeId;
     }
 
-    QMetaMethod[] lookUpMethodOverloads(string methodName)
+    M lookUpMethod(M : QMetaMethod = QMetaMethod)(string signature)
     {
-        typeof(return) result;
-        foreach (method; _methods)
-            if (method.name == methodName)
-                result ~= method;
-        if (_base)
-            result ~= _base.lookUpMethodOverloads(methodName);
-        return result;
+        foreach (method; allMembers)
+        {
+            if (auto m = cast(M)method)
+            {
+                if (m.signature == signature)
+                    return m;
+            }
+        }
+        return null;
     }
 
-    QMetaSignal[] lookUpSignalOverloads(string signalName)
+    // TODO: probably make this return a filtering range.
+    auto lookUpMethodOverloads(M : QMetaMethod = QMetaMethod)(string name)
     {
-        typeof(return) result;
-        foreach (method; _methods)
-            if (method.name == signalName && cast(QMetaSignal)method)
-                result ~= cast(QMetaSignal)method;
-        if (_base)
-            result ~= _base.lookUpSignalOverloads(signalName);
-        return result;
+        M[] methods;
+        foreach (m; allMembers)
+        {
+            if (auto method = cast(M)m)
+            {
+                if (method.name == name)
+                    methods ~= method;
+            }
+        }
+        return methods;
     }
 
-    private QMetaObject lookupDerived(void*[] moIds)
+    private QMetaObject lookUpDerived(void*[] moIds)
     {
         assert (moIds.length >= 1);
 
-        for (auto mo = _firstDerived; mo !is null; mo = mo._next)
+        for (auto mo = firstDerived; mo !is null; mo = mo.next)
         {
-            if (mo._nativeId == moIds[0])
+            if (mo.nativeId == moIds[0])
             {
                 if (moIds.length == 1) // exact match found
                     return mo;
                 else // look deeper
-                    return mo.lookupDerived(moIds[1..$]);
+                    return mo.lookUpDerived(moIds[1..$]);
             }
         }
 
@@ -311,7 +290,8 @@
             if (!result)
             {
                 auto moId = qtd_QObject_metaObject(nativeObjId);
-                if (_nativeId == moId)
+                auto nId = nativeId;
+                if (nId == moId)
                      result = _createWrapper(nativeObjId);
                 else
                 {
@@ -323,7 +303,7 @@
                     {
                         tmp = qtd_QMetaObject_superClass(tmp);
                         assert(tmp);
-                        if (tmp == _nativeId)
+                        if (tmp == nId)
                             break;
                         moCount++;
                     }
@@ -334,7 +314,7 @@
                     while (moCount > 0)
                         moIds[--moCount] = moId = qtd_QMetaObject_superClass(moId);
 
-                    result = lookupDerived(moIds)._createWrapper(nativeObjId);
+                    result = lookUpDerived(moIds)._createWrapper(nativeObjId);
                 }
             }
         }
@@ -361,12 +341,12 @@
 
     int indexOfMethod_Cpp(string method)
     {
-        return qtd_QMetaObject_indexOfMethod(_nativeId, toStringz(method));
+        return qtd_QMetaObject_indexOfMethod(nativeId, toStringz(method));
     }
 
     int methodCount()
     {
-        return qtd_QMetaObject_methodCount(_nativeId);
+        return qtd_QMetaObject_methodCount(nativeId);
     }
 
     static void connectImpl(QObject sender, string signalString, QObject receiver, string methodString, int type)
@@ -377,9 +357,9 @@
         QMetaMethod method;
 
         if(indexOf(signalString, '(') > 0)
-            signal = sender.metaObject.lookUpSignal(signalString);
+            signal = sender.metaObject.lookUpMethod!QMetaSignal(signalString);
         else
-            signals = sender.metaObject.lookUpSignalOverloads(signalString); // parameters not specified. Looking for a match
+            signals = sender.metaObject.lookUpMethodOverloads!QMetaSignal(signalString); // parameters not specified. Looking for a match
 
         if(indexOf(methodString, '(') > 0)
             method = receiver.metaObject.lookUpMethod(methodString);
@@ -390,13 +370,17 @@
         {
             Top:
             foreach(sig; signals)
+            {
                 foreach(meth; methods)
+                {
                     if(startsWith(sig.args, meth.args))
                     {
                         signal = sig;
                         method = meth;
                         break Top;
                     }
+                }
+            }
         }
         else if (!signal)
         {
@@ -425,14 +409,18 @@
         }
         else
         {
-            int signalIndex = signal.indexOfMethod;
-            int methodIndex = method.indexOfMethod;
+            int signalIndex = signal.index;
+            int methodIndex = method.index;
 
             success = QMetaObject.connect(sender, signalIndex, receiver, methodIndex, type);
         }
 
         if(!success)
-            throw new QMetaException("QMetaObject: Signal " ~ signalString ~ " cannot be connected to slot " ~ methodString);
+        {
+            throw new MetaException("QMetaObject: Failed to connect signal "
+                ~ sender.classinfo.name ~ "." ~ signalString ~ " to slot "
+                ~ receiver.classinfo.name ~ "." ~ methodString ~ ". Make sure the signal and slot exist and match.");
+        }
     }
 }
 
@@ -443,19 +431,50 @@
     mixin InnerAttribute!("Q_CLASSINFO", AttributeOptions.allowMultiple, name, value);
 }
 
+/**
+ */
+mixin template Q_PROPERTY(T, string params)
+{
+    static assert(false, "not implemented");
+}
+
 version (QtdUnittest)
 {
+    // COMPILER BUG: cannot put this inside the unittest block as static class.
+    class QMetaObject_A : QObject
+    {
+        mixin Q_CLASSINFO!("author", "Sabrina Schweinsteiger");
+        mixin Q_CLASSINFO!("url", "http://doc.moosesoft.co.uk/1.0/");
+
+        static int slot1Called;
+
+        final
+        {
+            void signal_signal1();
+            void signal_signal2(int);
+        }
+
+
+        void slot_slot1()
+        {
+            slot1Called++;
+        }
+
+        mixin Q_OBJECT;
+    }
+
     unittest
     {
-        static class Test : QObject
-        {
-            mixin Q_CLASSINFO!("author", "Sabrina Schweinsteiger");
-            mixin Q_CLASSINFO!("url", "http://doc.moosesoft.co.uk/1.0/");
+        scope a = new QMetaObject_A;
+        QObject.connect(a, "signal1", a, "slot1");
+        a.signal1();
+        assert(QMetaObject_A.slot1Called == 1);
 
-            mixin Q_OBJECT;
-        }
+        QObject.connect(a, "signal2", a, "slot1");
+        a.signal2(42);
+        assert(QMetaObject_A.slot1Called == 2);
     }
-}
+ }
 
 extern(C) void qtd_QMetaObject_activate_3(void* sender, void* m, int local_signal_index, void **argv);
 extern(C) void qtd_QMetaObject_activate_4(void *sender, void* m, int from_local_signal_index, int to_local_signal_index, void **argv);