diff d2/qt/core/QMetaObject.d @ 344:96a75b1e5b26

project structure changes
author Max Samukha <maxter@spambox.com>
date Fri, 14 May 2010 12:14:37 +0300
parents qt/core/QMetaObject.d@5896535a03cd
children 31520b2c0b3c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/d2/qt/core/QMetaObject.d	Fri May 14 12:14:37 2010 +0300
@@ -0,0 +1,390 @@
+module qt.core.QMetaObject;
+
+import qt.QGlobal;
+import qt.core.QObject;
+import qtd.QtdObject;
+
+import std.algorithm;
+import std.string;
+import std.stdio;
+
+class Meta
+{
+    string name;
+}
+
+class MetaType : Meta
+{
+    this()
+    {
+    }
+}
+
+class MetaVariable : Meta
+{
+    MetaType type;
+}
+
+class MetaCallable : Meta { }
+
+class MetaMethod : Meta { }
+
+class QMetaArgument : MetaVariable { }
+
+class QMetaMethod : MetaMethod
+{
+//    QMetaArgument[] arguments;
+    string signature;
+    int indexOfMethod;
+    
+    this(string signature_, int indexOfMethod_)
+    {
+        signature = signature_;
+        indexOfMethod = indexOfMethod_;
+    }
+    
+    string args() const
+    {
+        int openBracket = indexOf(signature, '(');
+        if(signature.length - openBracket - 2 > 0)
+            return signature[openBracket + 1 .. $-1];
+        else
+            return "";
+    }
+    
+    string name() const
+    {
+        int openBracket = indexOf(signature, '(');
+        return signature[0..openBracket];
+    }
+}
+
+class QMetaSignal : QMetaMethod
+{
+    this(string signature_, int indexOfMethod_)
+    {
+        super(signature_, indexOfMethod_);
+    }
+}
+
+class QMetaSlot : QMetaMethod
+{
+    this(string signature_, int indexOfMethod_)
+    {
+        super(signature_, indexOfMethod_);
+    }
+}
+
+class MetaObject : MetaType
+{
+    MetaObject _base;
+}
+
+struct QMetaObjectNative
+{
+    QMetaObjectNative *superdata;
+    immutable(char) *stringdata;
+    const(uint) *data;
+    void *extradata;
+}
+
+class QMetaException : Exception { this(string msg) { super(msg); } }
+
+final class QMetaObject
+{
+    enum Call
+    {
+        InvokeMetaMethod,
+        ReadProperty,
+        WriteProperty,
+        ResetProperty,
+        QueryPropertyDesignable,
+        QueryPropertyScriptable,
+        QueryPropertyStored,
+        QueryPropertyEditable,
+        QueryPropertyUser,
+        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;
+    }
+    
+    // NOTE: construction is split between this non-templated constructor and 'construct' function below.
+    this(QMetaObjectNative* nativeId, QMetaObject base)
+    {
+        _nativeId = nativeId;
+        if (base)
+        {
+            base.addDerived(this);
+            _base = base;
+        }
+    }
+    
+    // TODO: remove when D acquires templated constructors       
+    void construct(T : QObject, Concrete = T)()
+    {
+        _classInfo = T.classinfo;        
+
+        _createWrapper = function QObject(void* nativeId) {
+                // COMPILER BUG: cast is should not be needed
+                auto obj = new Concrete(nativeId, cast(QtdObjectFlags)(QtdObjectFlags.nativeOwnership | QtdObjectFlags.dynamicEntity));
+                // TODO: Probably this should be a virtual call from T's constructor
+                T.__createEntity(nativeId, cast(void*)obj);
+                return obj;
+            };
+    }
+    
+    /++
+    +/
+    QMetaObject base()
+    {
+        return _base;
+    }
+    
+    /++
+    +/
+    QMetaObjectNative* nativeId()
+    {
+        return _nativeId;
+    }
+
+    /++
+    +/
+    ClassInfo classInfo()
+    {
+        return _classInfo;
+    }
+    
+    const (QMetaMethod[]) methods()
+    {
+        return _methods;
+    }
+    
+    void addMethod(QMetaMethod method_)
+    {
+        _methods ~= method_;
+    }
+    
+    QMetaMethod lookUpMethod(string slot)
+    {
+        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;
+    }
+
+    QMetaMethod[] lookUpMethodOverloads(string methodName)
+    {
+        typeof(return) result;
+        foreach (method; _methods)
+            if (method.name == methodName)
+                result ~= method;
+        if (_base)
+            result ~= _base.lookUpMethodOverloads(methodName);
+        return result;
+    }
+
+    QMetaSignal[] lookUpSignalOverloads(string signalName)
+    {
+        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;
+    }
+    
+    private QMetaObject lookupDerived(void*[] moIds)
+    {
+        assert (moIds.length >= 1);
+                
+        for (auto mo = _firstDerived; mo !is null; mo = mo._next)
+        {
+            if (mo._nativeId == moIds[0])
+            {
+                if (moIds.length == 1) // exact match found
+                    return mo;
+                else // look deeper
+                    return mo.lookupDerived(moIds[1..$]);
+            }
+        }
+        
+        // no initialized wrapper that matches the native object.
+        // use the base class wrapper
+        return this;
+    }
+    
+    QObject getObject(void* nativeObjId)
+    {
+        QObject result;
+        
+        if (nativeObjId)
+        {
+            result = cast(QObject)qtd_get_d_qobject(nativeObjId);            
+            if (!result)
+            {
+                auto moId = qtd_QObject_metaObject(nativeObjId);
+                if (_nativeId == moId)
+                     result = _createWrapper(nativeObjId);
+                else
+                {
+                    // get native metaobjects for the entire derivation lattice
+                    // up to, but not including, the current metaobject.
+                    size_t moCount = 1;
+                    
+                    for (void* tmp = moId;;)
+                    {
+                        tmp = qtd_QMetaObject_superClass(tmp);                        
+                        assert(tmp);
+                        if (tmp == _nativeId)                        
+                            break;
+                        moCount++;
+                    }
+                   
+                    void*[] moIds = (cast(void**)alloca(moCount * (void*).sizeof))[0..moCount];
+
+                    moIds[--moCount] = moId;
+                    while (moCount > 0)
+                        moIds[--moCount] = moId = qtd_QMetaObject_superClass(moId);
+                                    
+                    result = lookupDerived(moIds)._createWrapper(nativeObjId);
+                }
+            }
+        }
+
+        return result;
+    }
+    
+    static void activate(QObject sender, QMetaObject m, int local_signal_index, void **argv)
+    {
+        qtd_QMetaObject_activate_3(sender.__nativeId, m.nativeId, local_signal_index, argv);
+    }
+    
+    static void activate(QObject sender, QMetaObject m, int from_local_signal_index, int to_local_signal_index, void **argv)
+    {
+        qtd_QMetaObject_activate_4(sender.__nativeId, m.nativeId, from_local_signal_index, to_local_signal_index, argv);
+    }
+
+    static bool connect(const QObject sender, int signal_index,
+                        const QObject receiver, int method_index,
+                        int type = 0, int *types = null)
+    {
+        return qtd_QMetaObject_connect(sender.__nativeId, signal_index, receiver.__nativeId, method_index, type, types);
+    }
+    
+    int indexOfMethod_Cpp(string method)
+    {
+        return qtd_QMetaObject_indexOfMethod(_nativeId, toStringz(method));
+    }
+    
+    int methodCount()
+    {
+        return qtd_QMetaObject_methodCount(_nativeId);
+    }
+    
+    static void connectImpl(QObject sender, string signalString, QObject receiver, string methodString, int type)
+    {
+        QMetaSignal[] signals;
+        QMetaMethod[] methods;
+        QMetaSignal signal;
+        QMetaMethod method;
+
+        if(indexOf(signalString, '(') > 0)
+            signal = sender.metaObject.lookUpSignal(signalString);
+        else
+            signals = sender.metaObject.lookUpSignalOverloads(signalString); // parameters not specified. Looking for a match
+
+        if(indexOf(methodString, '(') > 0) 
+            method = receiver.metaObject.lookUpMethod(methodString);
+        else
+            methods = receiver.metaObject.lookUpMethodOverloads(methodString); // parameters not specified. Looking for a match
+
+        if(!signal && !method)
+        {
+            Top:
+            foreach(sig; signals)
+                foreach(meth; methods)
+                    if(startsWith(sig.args, meth.args))
+                    {
+                        signal = sig;
+                        method = meth;
+                        break Top;
+                    }
+        }
+        else if (!signal)
+        {
+            foreach(sig; signals)
+                if(startsWith(sig.args, method.args))
+                {
+                    signal = sig;
+                    break;
+                }
+        }
+        else if (!method)
+        {
+            foreach(meth; methods)
+                if(startsWith(signal.args, meth.args))
+                {
+                    method = meth;
+                    break;
+                }
+        } 
+        
+        bool success = false;
+
+        if(!signal && !method)
+        {
+            success = false;
+        }
+        else
+        {
+            int signalIndex = signal.indexOfMethod;
+            int methodIndex = method.indexOfMethod;
+            success = QMetaObject.connect(sender, signalIndex, receiver, methodIndex, type);
+        }
+        
+        if(!success)
+            throw new QMetaException("QMetaObject: Signal " ~ signalString ~ " and slot " ~ methodString ~ " cannot be found");
+    }
+}
+
+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);
+extern(C) bool qtd_QMetaObject_connect(const void* sender, int signal_index,
+                                       const void* receiver, int method_index,
+                                       int type, int *types);
+                                       
+extern(C) int qtd_QMetaObject_indexOfMethod(void *nativeId, const(char) *method);
+extern(C) int qtd_QMetaObject_methodCount(void *nativeId);
+
+extern(C) void* qtd_QMetaObject_superClass(void* nativeId);