changeset 288:f9559a957be9 signals

new signals and slots implementation
author eldar
date Sun, 08 Nov 2009 19:28:01 +0000
parents b6984b290e46
children c9d1aac290e9
files build/core.txt cpp/qt_core/QMetaObject_shell.cpp generator/abstractmetalang.cpp generator/abstractmetalang.h generator/cppheadergenerator.cpp generator/cppimplgenerator.cpp generator/dgenerator.cpp generator/dgenerator.h generator/typesystem_core-java.java generator/typesystem_core.xml generator/typesystem_gui.xml qt/core/QMetaObject.d qt/d2/qt/QtdObject.d qt/d2/qt/Signal.d qt/d2/qt/core/QModelIndex.d qt/qtd/MOC.d qt/qtd/MetaMarshall.d qt/qtd/ctfe/Format.d qt/qtd/ctfe/Integer.d qt/qtd/ctfe/String.d qt/qtd/util/Tuple.d
diffstat 21 files changed, 2577 insertions(+), 1100 deletions(-) [+]
line wrap: on
line diff
--- a/build/core.txt	Sun Nov 08 19:20:53 2009 +0000
+++ b/build/core.txt	Sun Nov 08 19:28:01 2009 +0000
@@ -17,7 +17,14 @@
     qtd/Traits
     core/QString
     core/QMetaType
-    core/QMetaObject)
+    core/QMetaObject
+    
+    qtd/MetaMarshall
+    qtd/MOC
+    qtd/util/Tuple
+    qtd/ctfe/Integer
+    qtd/ctfe/String
+    qtd/ctfe/Format)
 set (d_version_files 
     QtdObject
     Signal qtd/Str
--- a/cpp/qt_core/QMetaObject_shell.cpp	Sun Nov 08 19:20:53 2009 +0000
+++ b/cpp/qt_core/QMetaObject_shell.cpp	Sun Nov 08 19:28:01 2009 +0000
@@ -10,3 +10,30 @@
 {
     QMetaObject::activate(sender, signal_index, argv);
 }
+
+extern "C" DLL_PUBLIC void qtd_QMetaObject_activate_3(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv)
+{
+    QMetaObject::activate(sender, m, local_signal_index, argv);
+}
+
+extern "C" DLL_PUBLIC void qtd_QMetaObject_activate_4(QObject *sender, const QMetaObject *m, int from_local_signal_index, int to_local_signal_index, void **argv)
+{
+    QMetaObject::activate(sender, m, from_local_signal_index, to_local_signal_index, argv);
+}
+
+extern "C" DLL_PUBLIC bool qtd_QMetaObject_connect(const QObject *sender, int signal_index,
+                                                   const QObject *receiver, int method_index,
+                                                   int type, int *types)
+{
+    return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
+}
+
+extern "C" DLL_PUBLIC int qtd_QMetaObject_indexOfMethod(void *nativeId, const char *method)
+{
+    return ((QMetaObject*)nativeId)->indexOfMethod(method);
+}
+
+extern "C" DLL_PUBLIC int qtd_QMetaObject_methodCount(void *nativeId)
+{
+    return ((QMetaObject*)nativeId)->methodCount();
+}
--- a/generator/abstractmetalang.cpp	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/abstractmetalang.cpp	Sun Nov 08 19:28:01 2009 +0000
@@ -42,6 +42,7 @@
 #include "abstractmetalang.h"
 #include "reporthandler.h"
 #include "jumptable.h"
+#include <iostream>
 
 /*******************************************************************************
  * AbstractMetaType
@@ -668,15 +669,15 @@
     return QString();
 }
 
-QString AbstractMetaFunction::minimalSignature() const
+QString AbstractMetaFunction::minimalSignature(int reduce) const
 {
-    if (!m_cached_minimal_signature.isEmpty())
+    if (!m_cached_minimal_signature.isEmpty() && !reduce)
         return m_cached_minimal_signature;
 
     QString minimalSignature = originalName() + "(";
     AbstractMetaArgumentList arguments = this->arguments();
-
-    for (int i=0; i<arguments.count(); ++i) {
+    int argsCount = arguments.count() - reduce;
+    for (int i=0; i<argsCount; ++i) {
         AbstractMetaType *t = arguments.at(i)->type();
 
         if (i > 0)
@@ -689,7 +690,8 @@
         minimalSignature += "const";
 
     minimalSignature = QMetaObject::normalizedSignature(minimalSignature.toLocal8Bit().constData());
-    m_cached_minimal_signature = minimalSignature;
+    if(!reduce)
+        m_cached_minimal_signature = minimalSignature;
 
     return minimalSignature;
 }
--- a/generator/abstractmetalang.h	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/abstractmetalang.h	Sun Nov 08 19:28:01 2009 +0000
@@ -440,7 +440,7 @@
 
     QString modifiedName() const;
 
-    QString minimalSignature() const;
+    QString minimalSignature(int reduce = 0) const;
     QStringList possibleIntrospectionCompatibleSignatures() const;
 
     QString marshalledName(bool classIsOwner = true) const;
--- a/generator/cppheadergenerator.cpp	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/cppheadergenerator.cpp	Sun Nov 08 19:28:01 2009 +0000
@@ -197,6 +197,8 @@
 //        << "  void *qt_metacast(const char *);" << endl
 //        << "  QT_TR_FUNCTIONS" << end
       << "  virtual int qt_metacall(QMetaObject::Call, int, void **);" << endl
+      << "  int __override_qt_metacall(QMetaObject::Call _c, int _id, void **_a);" << endl
+
       << "private:" << endl;
     }
 
--- a/generator/cppimplgenerator.cpp	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/cppimplgenerator.cpp	Sun Nov 08 19:28:01 2009 +0000
@@ -592,9 +592,10 @@
     if (!java_class->isQObject())
         writeFinalDestructor(s, java_class);
 
-    if (java_class->isQObject())
+    if (java_class->isQObject()) {
+        writeQObjectEntity(s, java_class);
         writeSignalsHandling(s, java_class);
-
+    }
     if (shellClass) {
         foreach (AbstractMetaFunction *function, java_class->functions()) {
             if (function->isConstructor() && !function->isPrivate())
@@ -1217,22 +1218,21 @@
       << "{" << endl
       << "public:" << endl
       << "    Q_OBJECT_CHECK" << endl
-      << "    virtual int qt_metacall(QMetaObject::Call, int, void **);" << endl << endl
+      << "//    virtual int qt_metacall(QMetaObject::Call, int, void **);" << endl << endl
 
       << "    " << entityName << "(QObject *qObject, void *dId) : QObject(), QtD_QObjectEntity(qObject, dId) {}" << endl
       << "};" << endl << endl;
 
-    // QObject_Link::qt_metacall()
+/*    // QObject_Link::qt_metacall()
     s << "int " << entityName << "::qt_metacall(QMetaObject::Call _c, int _id, void **_a)" << endl
       << "{" << endl      
       << "    _id = QObject::qt_metacall(_c, _id, _a);" << endl
       << "    if (_id < 0 || _c != QMetaObject::InvokeMetaMethod)" << endl
       << "        return _id;" << endl
-//      << "    Q_ASSERT(_id < 2);" << endl      
       << "    emit_callbacks_" << java_class->name() << "[_id](dId, _a);" << endl      
       << "    return -1;" << endl
       << "}" << endl << endl;
-
+*/
     s << "extern \"C\" DLL_PUBLIC void qtd_" << className << "_createEntity(void *nativeId, void* dId)" << endl
       << "{" << endl
       << "    new " << entityName << "((QObject*)nativeId, dId);" << endl
@@ -1282,16 +1282,34 @@
       << "  return " << java_class->qualifiedCppName() << "::qt_metacast(_clname);" << endl
       << "}" << endl << endl;
 */
-    
+/*
     s << "int " << shellClassName(java_class) << "::qt_metacall(QMetaObject::Call _c, int _id, void **_a)" << endl
-      << "{" << endl;
-
-    s << "    _id = " << java_class->qualifiedCppName() << "::qt_metacall(_c, _id, _a);" << endl    
+      << "{" << endl
+      << "    _id = " << java_class->qualifiedCppName() << "::qt_metacall(_c, _id, _a);" << endl
       << "    if (_id < 0 || _c != QMetaObject::InvokeMetaMethod)" << endl
       << "        return _id;" << endl      
       << "    emit_callbacks_" << java_class->name() << "[_id](this->dId, _a);" << endl      
       << "    return -1;" << endl
       << "}" << endl << endl;
+      */
+
+    s << "extern \"C\" int qtd_" << java_class->name() << "_qt_metacall_dispatch(void *d_entity, QMetaObject::Call _c, int _id, void **_a);" << endl << endl
+
+      << "int " << shellClassName(java_class) << "::qt_metacall(QMetaObject::Call _c, int _id, void **_a)" << endl
+      << "{" << endl
+      << "    return qtd_" << java_class->name() << "_qt_metacall_dispatch(this->dId, _c, _id, _a);" << endl
+      << "}" << endl << endl
+
+      << "int " << shellClassName(java_class) << "::__override_qt_metacall(QMetaObject::Call _c, int _id, void **_a)" << endl
+      << "{" << endl
+      << "    return " << java_class->qualifiedCppName() << "::qt_metacall(_c, _id, _a);"
+      << "}" << endl << endl
+
+      << "extern \"C\" DLL_PUBLIC int qtd_" << java_class->name() << "_qt_metacall(void* __this_nativeId, QMetaObject::Call _c, int _id, void **_a)"
+      << "{" << endl
+      << "    " << shellClassName(java_class) << " *__qt_this = (" << shellClassName(java_class) << " *) __this_nativeId;" << endl
+      << "    return __qt_this->__override_qt_metacall(_c, _id, _a);" << endl
+      << "}" << endl << endl;
 }
 
 void CppImplGenerator::writeSignalEmitter(QTextStream &s, const AbstractMetaClass *d_class, AbstractMetaFunction *function)
@@ -1341,6 +1359,8 @@
 
 void CppImplGenerator::writeSignalsHandling(QTextStream &s, const AbstractMetaClass *java_class)
 {
+    return; // #TODO probably don't need this function at all
+
     s << "extern \"C\" typedef void (*EmitCallback)(void*, void**);" << endl;
     AbstractMetaFunctionList signal_funcs = signalFunctions(java_class);
 
@@ -1369,8 +1389,6 @@
         }
         s << endl << "};" << endl << endl;
     }
-
-    writeQObjectEntity(s, java_class);
 }
 
 
--- a/generator/dgenerator.cpp	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/dgenerator.cpp	Sun Nov 08 19:28:01 2009 +0000
@@ -63,7 +63,7 @@
       m_recursive(0),
       m_isRecursive(false)
 {
-    excludedTypes << "long long" << "bool" << "int" << "QString" << "char" << "WId"
+    excludedTypes << "qint64" << "bool" << "int" << "QString" << "char" << "WId"
                   << "unsigned char" << "uint" << "double" << "short" << "float"
                   << "signed char" << "unsigned short" << "QBool" << "unsigned int"
                   << "Qt::HANDLE" << "QChar" << "java.lang.JObjectWrapper" << "void"
@@ -126,7 +126,7 @@
     QString constPrefix, constPostfix;
     if (d_type && d_type->isConstant() && dVersion == 2) {
         constPrefix = "const(";
-        constPostfix = ") ";
+        constPostfix = ")";
     }
 
     if (!d_type) {
@@ -230,7 +230,7 @@
     QString arg;
 
     AbstractMetaType *type = d_argument->type();
-    // if argument is "QString &" ref attribute needed
+    // qtd2 if argument is "QString &" ref attribute needed FIXME maybe we need this not only for QString, but for other Value types??
     if (type->typeEntry()->isValue() && type->isNativePointer() && type->typeEntry()->name() == "QString")
         arg = "ref ";
 
@@ -983,10 +983,7 @@
     if (!(d_function->isEmptyFunction() || d_function->isNormal() || d_function->isSignal()))
         option = Option(option | SkipReturnType);
     writeFunctionAttributes(s, d_function, included_attributes, excluded_attributes, option);
-/*
-    if(d_function->isSignal())
-        functionName += "_emit";
-*/
+
     s << functionName << "(";
     writeFunctionArguments(s, d_function, argument_count, option);
     s << ")";
@@ -1713,6 +1710,8 @@
 
     QString attr;
 
+//    return; // #TODO Don't need handlers for now. Restore in conversion functions later
+
     s << "// signal handlers" << endl;
     foreach(AbstractMetaFunction *signal, signal_funcs) {
         QString sigExternName = signalExternName(d_class, signal);
@@ -1771,7 +1770,7 @@
                 s << endl;
             }
 //            s << INDENT << "Stdout(\"" << d_class->name() << "\", \"" << signal->name() << "\").newline;" << endl;
-            s << INDENT << "d_object." << signal->name() << "_emit(";
+            s << INDENT << "//d_object." << signal->name() << "_emit(";
             for (int j = 0; j<sz; ++j) {
                 AbstractMetaArgument *argument = arguments.at(j);
                 QString arg_name = argument->indexedName();
@@ -1786,6 +1785,29 @@
     }
 }
 
+AbstractMetaFunctionList DGenerator::generatedClassFunctions(const AbstractMetaClass *d_class)
+{
+    AbstractMetaFunctionList r;
+    AbstractMetaFunctionList d_funcs = d_class->functionsInTargetLang();
+    for (int i=0; i<d_funcs.size(); ++i) {
+        AbstractMetaFunction *function = d_funcs.at(i);
+
+        // If a method in an interface class is modified to be private, this should
+        // not be present in the interface at all, only in the implementation.
+        if (d_class->isInterface()) {
+            uint includedAttributes = 0;
+            uint excludedAttributes = 0;
+            retrieveModifications(function, d_class, &excludedAttributes, &includedAttributes);
+            if (includedAttributes & AbstractMetaAttributes::Private)
+                continue;
+        }
+
+        if (!notWrappedYet(function)) // qtd2
+            r += function;
+    }
+    return r;
+}
+
 void DGenerator::write(QTextStream &s, const AbstractMetaClass *d_class)
 {
     ReportHandler::debugSparse("Generating class: " + d_class->fullName());
@@ -1909,6 +1931,7 @@
           << "private import qt.qtd.Array;" << endl;
         if (d_class->isQObject()) {
             s << "public import qt.Signal;" << endl
+              << "public import qt.qtd.MOC;" << endl
               << "public import qt.core.QMetaObject;" << endl
               << "public import qt.qtd.Traits;" << endl;
 
@@ -2148,7 +2171,7 @@
     foreach (AbstractMetaEnum *d_enum, d_class->enums())
         writeEnumAlias(s, d_enum);
 
-    // Signals    
+    // Signals
     if (d_class->isQObject())
     {
         AbstractMetaFunctionList signal_funcs = signalFunctions(d_class, false);
@@ -2181,22 +2204,13 @@
 
     // Functions
     AbstractMetaFunctionList d_funcs = d_class->functionsInTargetLang();
-    for (int i=0; i<d_funcs.size(); ++i) {
-        AbstractMetaFunction *function = d_funcs.at(i);
-
-        // If a method in an interface class is modified to be private, this should
-        // not be present in the interface at all, only in the implementation.
-        if (d_class->isInterface()) {
-            uint includedAttributes = 0;
-            uint excludedAttributes = 0;
-            retrieveModifications(function, d_class, &excludedAttributes, &includedAttributes);
-            if (includedAttributes & AbstractMetaAttributes::Private)
-                continue;
-        }
-
-        if (!notWrappedYet(function)) // qtd2
-            writeFunction(s, function);
-//        s << function->minimalSignature() << endl;
+    AbstractMetaFunctionList d_funcs_gen = generatedClassFunctions(d_class);
+    for (int i=0; i<d_funcs_gen.size(); ++i) {
+        AbstractMetaFunction *function = d_funcs_gen.at(i);
+//        if(function->isSlot())
+//            writeSlot(s, function);
+          writeFunction(s, function);
+// qtd       s << function->minimalSignature() << endl;
     }
     if(d_class->isInterface())
         s << endl << INDENT << "public void* __ptr_" << d_class->name() << "();" << endl << endl;
@@ -2243,6 +2257,17 @@
     if (d_class->isQObject())
         writeQObjectFunctions(s, d_class);
 
+    // flag to mark the type of class (to use in templates to convert arguments)
+    if (d_class->baseClassName().isEmpty())
+    {
+        if (d_class->typeEntry()->isQObject())
+            s << INDENT << "public static enum __isQObjectType = true;" << endl << endl;
+        else if (d_class->typeEntry()->isObject())
+            s << INDENT << "public static enum __isObjectType = true;" << endl << endl;
+        else if (d_class->typeEntry()->isValue())
+            s << INDENT << "public static enum __isValueType = true;" << endl << endl;
+    }
+
     // Add dummy constructor for use when constructing subclasses
     if (!d_class->isNamespace() && !d_class->isInterface() && !fakeClass) {
         s << endl
@@ -2633,10 +2658,7 @@
 
 
     if (d_class->isQObject())
-    {
-      s << "private extern(C) void* qtd_" << d_class->name() << "_staticMetaObject();" << endl << endl
-        << "private extern(C) void qtd_" << d_class->name() << "_createEntity(void* nativeId, void* dId);" <<  endl << endl;
-    }
+        writeQObjectFreeFunctions(s, d_class);
 }
 
 void DGenerator::writeConversionFunction(QTextStream &s, const AbstractMetaClass *d_class)
@@ -2674,12 +2696,67 @@
     s << "}" << endl << endl;
 }
 
+void DGenerator::writeQObjectFreeFunctions(QTextStream &s, const AbstractMetaClass *d_class)
+{
+    s << "private extern(C) QMetaObjectNative* qtd_" << d_class->name() << "_staticMetaObject();" << endl << endl
+      << "private extern(C) void qtd_" << d_class->name() << "_createEntity(void* nativeId, void* dId);" <<  endl << endl;
+
+  if (!d_class->isFinal())
+    s << "private extern(C) int qtd_" << d_class->name() << "_qt_metacall(void* __this_nativeId, QMetaObject.Call _c, int _id, void **_a);"
+      << "private extern(C) int qtd_" << d_class->name() << "_qt_metacall_dispatch(void *d_entity, QMetaObject.Call _c, int _id, void **_a) {"
+      << "    auto d_object = cast(" << d_class->name() << ") d_entity;"
+      << "    return d_object.qt_metacall(_c, _id, _a);"
+      << "}" << endl << endl;
+}
+
+void writeMetaMethodSignatures(QTextStream &s, const QString &var_name, AbstractMetaFunctionList meta_funcs)
+{
+    s << INDENT << "private static const string[] " << var_name << " = [";
+    {
+        Indentation indent(INDENT);
+        for (int i = 0; i < meta_funcs.size(); ++i)
+        {
+            if (i)
+                s << ", ";
+            int j = 0;
+            bool hasDefault = false;
+            do // need this to look for default arguments and generate extra signatures
+            {
+                if (i || j)
+                    s << ", ";
+                s << endl << INDENT << "    \"" << meta_funcs.at(i)->minimalSignature(j) << "\"";
+                AbstractMetaArgumentList args = meta_funcs.at(i)->arguments();
+                if(args.size() && j<args.size())
+                    hasDefault = !args.at(args.size() - 1 - j)->defaultValueExpression().isEmpty();
+                else
+                    hasDefault = false;
+                j++;
+            } while (hasDefault);
+        }
+    }
+    s << INDENT << "];" << endl << endl;
+}
+
 void DGenerator::writeQObjectFunctions(QTextStream &s, const AbstractMetaClass *d_class)
 {
-    QString concreteArg;
+  AbstractMetaFunctionList d_funcs_gen = generatedClassFunctions(d_class);
+  AbstractMetaFunctionList slot_funcs;
+  for (int i=0; i<d_funcs_gen.size(); ++i) {
+      AbstractMetaFunction *function = d_funcs_gen.at(i);
+      if(function->isSlot())
+          slot_funcs += function;
+  }
+  writeMetaMethodSignatures(s, "__slotSignatures", slot_funcs);
+
+  QString concreteArg;
     if (d_class->isAbstract())
         concreteArg += ", " + d_class->name() + "_ConcreteWrapper";
 
+  if (!d_class->isFinal())
+  s << "    int qt_metacall(QMetaObject.Call _c, int _id, void **_a) {" << endl
+    << "        return qtd_" << d_class->name() << "_qt_metacall(__nativeId, _c, _id, _a);" << endl
+    << "    }" << endl << endl;
+
   s << "    private static QMetaObject _staticMetaObject;" << endl
     << "    protected static void createStaticMetaObject() {" << endl
     << "        assert(!_staticMetaObject);" << endl
@@ -2695,6 +2772,7 @@
 
   s << "        _staticMetaObject = new QMetaObject(qtd_" << d_class->name() << "_staticMetaObject, base);"   << endl
     << "        _staticMetaObject.construct!(" << d_class->name() << concreteArg << ");" << endl
+    << "        _populateMetaInfo();" << endl
     << "    }" << endl << endl
 
     << "    QMetaObject metaObject() {" << endl
@@ -2711,7 +2789,64 @@
 
     << "    static void __createEntity(void* nativeId, void* dId) {" << endl
     << "        return qtd_" << d_class->name() << "_createEntity(nativeId, dId);" << endl
-    << "    }" << endl << endl;
+    << "    }" << endl << endl
+
+    << "    private static void _populateMetaInfo() {" << endl
+    << "        int index;" << endl << endl;
+
+  AbstractMetaFunctionList signal_funcs = signalFunctions(d_class, false);
+
+  int staticId = 0;
+  for (int i = 0; i < signal_funcs.size(); ++i)
+  {
+      int j = 0;
+      bool hasDefault = false;
+      do // need this to look for default arguments and generate extra signatures
+      {
+          AbstractMetaFunction *fn = signal_funcs.at(i);
+  s << "        index = _staticMetaObject.indexOfMethod_Cpp(__signalSignatures[" << staticId << "]);" << endl
+    << "        _staticMetaObject.addMethod(new QMetaSignal(signature!(\"" << fn->name() << "\"";
+          if(fn->arguments().size()-j > 0)
+              s << ", ";
+          writeMetaMethodArguments(s, fn, j);
+  s << "), index));" << endl << endl;
+          AbstractMetaArgumentList args = fn->arguments();
+          if(args.size() && j<args.size())
+              hasDefault = !args.at(args.size() - 1 - j)->defaultValueExpression().isEmpty();
+          else
+              hasDefault = false;
+          j++;
+          staticId++;
+      } while (hasDefault);
+  }
+
+  staticId = 0;
+  for (int i = 0; i < slot_funcs.size(); ++i)
+  {
+      int j = 0;
+      bool hasDefault = false;
+      do // need this to look for default arguments and generate extra signatures
+      {
+          AbstractMetaFunction *fn = slot_funcs.at(i);
+  s << "        index = _staticMetaObject.indexOfMethod_Cpp(__slotSignatures[" << staticId << "]);" << endl
+    << "        _staticMetaObject.addMethod(new QMetaSlot(signature!(\"" << fn->name() << "\"";
+          if(fn->arguments().size()-j > 0)
+              s << ", ";
+          writeMetaMethodArguments(s, fn, j);
+  s << "), index));" << endl << endl;
+          AbstractMetaArgumentList args = fn->arguments();
+          if(args.size() && j<args.size())
+              hasDefault = !args.at(args.size() - 1 - j)->defaultValueExpression().isEmpty();
+          else
+              hasDefault = false;
+          j++;
+          staticId++;
+      } while (hasDefault);
+  }
+
+  s  << "    }" << endl << endl;
+
+  s << INDENT << "mixin Q_OBJECT_BIND;" << endl << endl;
 }
 
 /*
@@ -2778,17 +2913,7 @@
 
 void DGenerator::writeSignalSignatures(QTextStream &s, const AbstractMetaClass *d_class, AbstractMetaFunctionList signal_funcs)
 {
-    s << INDENT << "private const string[" << signal_funcs.size() << "] __signalSignatures = [";
-    {
-        Indentation indent(INDENT);
-        for (int i = 0; i < signal_funcs.size(); ++i)
-        {            
-            if (i)
-                s << ", ";                
-            s << endl << INDENT << "    \"" << signal_funcs.at(i)->minimalSignature() << "\"";
-        }
-    }
-    s << INDENT << "];" << endl << endl;
+    writeMetaMethodSignatures(s, "__signalSignatures", signal_funcs);
 
     s << INDENT << "int signalSignature(int signalId, ref stringz signature) {" << endl;
     {
@@ -2810,29 +2935,42 @@
     s << INDENT << "}" << endl;
 }
 
+void DGenerator::writeMetaMethodArguments(QTextStream &s, const AbstractMetaFunction *d_function, int reduce)
+{
+    bool withDefArgs = false;
+    if(reduce == -1) {
+        reduce = 0;
+        withDefArgs = true;
+    }
+
+    AbstractMetaArgumentList arguments = d_function->arguments();
+    int sz = arguments.count() - reduce;
+
+    for (int i=0; i<sz; ++i) {
+        if(i != 0)
+            s << ",";
+
+        QString modifiedType = d_function->typeReplaced(i+1);
+
+        if (modifiedType.isEmpty())
+            s << translateType(arguments.at(i)->type(), d_function->implementingClass(), BoxedPrimitive);
+        else
+            s << modifiedType;
+
+        if (!arguments.at(i)->defaultValueExpression().isEmpty() && withDefArgs) // qtd
+            s << " = " + arguments.at(i)->defaultValueExpression();
+    }
+}
+
 void DGenerator::writeSignal(QTextStream &s, const AbstractMetaFunction *d_function)
 {
     Q_ASSERT(d_function->isSignal());
 
-    AbstractMetaArgumentList arguments = d_function->arguments();
-    int sz = arguments.count();
-
-    s << INDENT << "mixin BindQtSignal!(\"" << d_function->name() << "\"";
-
-    if (sz > 0) {
-        for (int i=0; i<sz; ++i) {
-            s << ", ";
-
-            QString modifiedType = d_function->typeReplaced(i+1);
-
-            if (modifiedType.isEmpty())
-                s << translateType(arguments.at(i)->type(), d_function->implementingClass(), BoxedPrimitive);
-            else
-                s << modifiedType;
-        }
-    }
-
-    s << ");" << endl;
+    s << INDENT << "mixin BindQtSignal!(\"" << d_function->name() << "(";
+
+    writeMetaMethodArguments(s, d_function);
+
+    s << ")\");" << endl;
 }
 
 void DGenerator::writeShellVirtualFunction(QTextStream &s, const AbstractMetaFunction *d_function,
--- a/generator/dgenerator.h	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/dgenerator.h	Sun Nov 08 19:28:01 2009 +0000
@@ -149,13 +149,16 @@
     void addInstantiations(const AbstractMetaType* d_type);
     void writeRequiredImports(QTextStream &s, const AbstractMetaClass *d_class);
     const TypeEntry* fixedTypeEntry(const TypeEntry *type);
+    AbstractMetaFunctionList generatedClassFunctions(const AbstractMetaClass *d_class);
 
     void writeDestructor(QTextStream &s, const AbstractMetaClass *d_class);
     void writeFlagsSetter(QTextStream &s, const AbstractMetaClass *d_class);
     void writeSignalHandlers(QTextStream &s, const AbstractMetaClass *d_class);
     void writeEnumAlias(QTextStream &s, const AbstractMetaEnum *d_enum);
     void writeSignalSignatures(QTextStream &s, const AbstractMetaClass *d_class, AbstractMetaFunctionList signal_funcs);
+    void writeMetaMethodArguments(QTextStream &s, const AbstractMetaFunction *d_function, int reduce = -1);
     void writeQObjectFunctions(QTextStream &s, const AbstractMetaClass *d_class);
+    void writeQObjectFreeFunctions(QTextStream &s, const AbstractMetaClass *d_class);
     void writeConversionFunction(QTextStream &s, const AbstractMetaClass *d_class);
 
 //    void writeMarshallFunction(QTextStream &s, const AbstractMetaClass *d_class);
--- a/generator/typesystem_core-java.java	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/typesystem_core-java.java	Sun Nov 08 19:28:01 2009 +0000
@@ -79,7 +79,7 @@
         QObject __next;
         QObject __prev;
     }
-    
+/*    
     override void onSignalHandlerCreated(ref SignalHandler sh)
     {
         sh.signalEvent = &onSignalEvent;
@@ -104,7 +104,7 @@
             }
         }
     }
-    
+*/
     ~this()
     {
         if (__prev)
@@ -154,6 +154,13 @@
         find(children);
         return result;
     }
+    
+    static void connect(QObject sender, string signal, QObject receiver, string method)
+    {
+        int signalIndex = sender.metaObject.lookUpSignal(signal);
+        int methodIndex = receiver.metaObject.lookUpMethod(method);
+        QMetaObject.connect(sender, signalIndex, receiver, methodIndex);
+    }
 }// class
 
 abstract class QAbstractItemModel___ extends QAbstractItemModel {
--- a/generator/typesystem_core.xml	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/typesystem_core.xml	Sun Nov 08 19:28:01 2009 +0000
@@ -103,7 +103,7 @@
     <primitive-type name="__int64" java-name="long" preferred-conversion="no" jni-name="jlong"/>
     <primitive-type name="unsigned __int64" java-name="long" preferred-conversion="no" jni-name="jlong"/>
     <primitive-type name="unsigned long long" java-name="ulong" preferred-conversion="no" jni-name="jlong"/>
-    <primitive-type name="long long" java-name="long" preferred-conversion="no" jni-name="jlong"/>
+    <primitive-type name="qint64" java-name="long" preferred-conversion="no" jni-name="jlong"/>
     <primitive-type name="quintptr" preferred-conversion="no" java-name="quintptr" jni-name="quintptr" />
 
     <primitive-type name="short" preferred-conversion="no" java-name="short" jni-name="jchar"/>
@@ -2282,9 +2282,10 @@
         <modify-function signature="error()const">
             <rename to="lastError"/>
         </modify-function>
-        <modify-function signature="finished(int, QProcess::ExitStatus)">
+<!--        <modify-function signature="finished(int, QProcess::ExitStatus)">
             <rename to="finishedWithStatusCode"/>
         </modify-function>
+        -->
         <modify-function signature="setStandardOutputProcess(QProcess*)">
             <modify-argument index="1">
                 <reference-count action="set" variable-name="__rcStandardOutputProcess"/>
@@ -2302,7 +2303,7 @@
   </object-type>
 
   <object-type name="QSignalMapper">
-    <modify-function signature="mapped(const QString &amp;)">
+<!--    <modify-function signature="mapped(const QString &amp;)">
         <rename to="mappedString"/>
     </modify-function>
     <modify-function signature="mapped(int)">
@@ -2310,7 +2311,7 @@
     </modify-function>
     <modify-function signature="mapped(QObject *)">
         <rename to="mappedQObject"/>
-    </modify-function>
+    </modify-function> -->
     <modify-function signature="mapped(QWidget *)" remove="all"/>
 
     <modify-function signature="mapping(QWidget*)const" remove="all"/>
@@ -2477,11 +2478,11 @@
         </inject-code> -->
 
     </modify-function>
-
+<!--
     <modify-function signature="deleteLater()">
         <rename to="disposeLater"/>
     </modify-function>
-
+-->
     <modify-function signature="inherits(const char*)const">
         <remove/>
     </modify-function>
@@ -2655,7 +2656,7 @@
           <rename to="writeInt"/>
           <modify-argument index="0" replace-value="this"/>
       </modify-function>
-      <modify-function signature="operator&lt;&lt;(long long)">
+      <modify-function signature="operator&lt;&lt;(qint64)">
           <rename to="writeLong"/>
           <modify-argument index="0" replace-value="this"/>
       </modify-function>
@@ -2691,7 +2692,7 @@
           <access modifier="private"/>
       </modify-function>
 
-      <modify-function signature="operator&gt;&gt;(long long&amp;)">
+      <modify-function signature="operator&gt;&gt;(qint64&amp;)">
           <rename to="operator_shift_right_long"/>
           <modify-argument index="0" replace-value="this"/>
           <access modifier="private"/>
--- a/generator/typesystem_gui.xml	Sun Nov 08 19:20:53 2009 +0000
+++ b/generator/typesystem_gui.xml	Sun Nov 08 19:28:01 2009 +0000
@@ -3703,13 +3703,13 @@
     <modify-function signature="layoutSpacingImplementation(QSizePolicy::ControlType, QSizePolicy::ControlType, Qt::Orientation, const QStyleOption *, const QWidget *) const" virtual-slot="yes"/>
   </object-type>
   <object-type name="QPrintDialog">
-      <modify-function signature="accepted(QPrinter *)">
+<!--      <modify-function signature="accepted(QPrinter *)">
           <rename to="accepted_printer"/>
-      </modify-function>
+      </modify-function> -->
       <modify-function signature="accepted()" remove="all"/>
       <modify-function signature="open(QObject *, const char *)" remove="all"/> <!-- # TODO -->
 
-  </object-type>
+  </object-type> 
   <object-type name="QPrintEngine"/>
   <object-type name="QProgressBar">
 <!--    <modify-function signature="initStyleOption(QStyleOptionProgressBar*)const">
@@ -5330,12 +5330,12 @@
   </object-type>
 
   <object-type name="QCompleter">
-    <modify-function signature="activated(const QModelIndex &amp;)">
+<!--    <modify-function signature="activated(const QModelIndex &amp;)">
         <rename to="activatedIndex"/>
     </modify-function>
     <modify-function signature="highlighted(const QModelIndex &amp;)">
         <rename to="highlightedIndex"/>
-    </modify-function>
+    </modify-function> -->
     <modify-function signature="setModel(QAbstractItemModel *)">
         <modify-argument index="1">
             <reference-count action="set" variable-name="__rcModel"/>
@@ -6815,25 +6815,25 @@
   </object-type>
 
   <object-type name="QSpinBox">
-    <modify-function signature="valueChanged(const QString &amp;)">
+<!--    <modify-function signature="valueChanged(const QString &amp;)">
         <rename to="valueStringChanged"/>
-    </modify-function>
+    </modify-function> -->
   </object-type>
 
   <object-type name="QTextBrowser">
-    <modify-function signature="highlighted(const QString &amp;)">
+<!--    <modify-function signature="highlighted(const QString &amp;)">
         <rename to="highlightedString"/>
-    </modify-function>
+    </modify-function> -->
   </object-type>
 
   <object-type name="QDoubleSpinBox">
-    <modify-function signature="valueChanged(const QString &amp;)">
+<!--    <modify-function signature="valueChanged(const QString &amp;)">
         <rename to="valueStringChanged"/>
-    </modify-function>
+    </modify-function> -->
   </object-type>
 
   <object-type name="QButtonGroup">
-    <modify-function signature="buttonClicked(int)">
+<!--    <modify-function signature="buttonClicked(int)">
         <rename to="buttonIdClicked"/>
     </modify-function>
     <modify-function signature="buttonPressed(int)">
@@ -6841,7 +6841,7 @@
     </modify-function>
     <modify-function signature="buttonReleased(int)">
         <rename to="buttonIdReleased"/>
-    </modify-function>
+    </modify-function> -->
     <modify-function signature="addButton(QAbstractButton *)">
         <modify-argument index="1">
             <reference-count action="add" variable-name="__rcButtons"/>
@@ -7235,7 +7235,7 @@
     <inject-code>
         <import-file name="typesystem_gui-java.java" quote-after-line="class QComboBox___" quote-before-line="}// class"/>
     </inject-code>
-    <modify-function signature="activated(int)">&gt;
+<!--    <modify-function signature="activated(int)">&gt;
         <rename to="activatedIndex"/>
     </modify-function>
     <modify-function signature="currentIndexChanged(const QString &amp;)">
@@ -7244,7 +7244,7 @@
     <modify-function signature="highlighted(int)">
         <rename to="highlightedIndex"/>
     </modify-function>
-
+-->
       <modify-function signature="autoCompletion()const" remove="all"/> <!--### Obsolete in 4.3-->
       <modify-function signature="autoCompletionCaseSensitivity()const" remove="all"/> <!--### Obsolete in 4.3-->
       <modify-function signature="setAutoCompletion(bool)" remove="all"/> <!--### Obsolete in 4.3-->
--- a/qt/core/QMetaObject.d	Sun Nov 08 19:20:53 2009 +0000
+++ b/qt/core/QMetaObject.d	Sun Nov 08 19:28:01 2009 +0000
@@ -4,14 +4,96 @@
 import qt.core.QObject;
 import qt.QtdObject;
 
+import std.algorithm;
+
+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_;
+    }
+}
+
+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;
+}
+
 final class QMetaObject
 {
+    enum Call
+    {
+        InvokeMetaMethod,
+        ReadProperty,
+        WriteProperty,
+        ResetProperty,
+        QueryPropertyDesignable,
+        QueryPropertyScriptable,
+        QueryPropertyStored,
+        QueryPropertyEditable,
+        QueryPropertyUser,
+        CreateInstance
+    }
+    
     private
     {
-        void* _nativeId;
+        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;
@@ -24,7 +106,7 @@
     }
     
     // NOTE: construction is split between this non-templated constructor and 'construct' function below.
-    this(void* nativeId, QMetaObject base)
+    this(QMetaObjectNative* nativeId, QMetaObject base)
     {
         _nativeId = nativeId;
         if (base)
@@ -57,7 +139,7 @@
     
     /++
     +/
-    void* nativeId()
+    QMetaObjectNative* nativeId()
     {
         return _nativeId;
     }
@@ -69,6 +151,39 @@
         return _classInfo;
     }
     
+    const (QMetaMethod[]) methods()
+    {
+        return _methods;
+    }
+    
+    void addMethod(QMetaMethod method_)
+    {
+        _methods ~= method_;
+    }
+    
+    int lookUpMethod(string slot)
+    {
+        foreach (method; _methods)
+            if (method.signature == slot)
+                return method.indexOfMethod;
+        if (_base)
+            return _base.lookUpMethod(slot);
+        else
+            return -1;
+    }
+    
+    int lookUpSignal(string signal)
+    {
+//        auto signalBegin = signal[0..$-1];
+        foreach (method; _methods)
+            if (method.signature == signal && cast(QMetaSignal)method)
+                return method.indexOfMethod;
+        if (_base)
+            return _base.lookUpSignal(signal);
+        else
+            return -1;
+    }
+    
     private QMetaObject lookupDerived(void*[] moIds)
     {
         assert (moIds.length >= 1);
@@ -123,12 +238,49 @@
                         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);
+    }
+
 }
 
+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);
\ No newline at end of file
--- a/qt/d2/qt/QtdObject.d	Sun Nov 08 19:20:53 2009 +0000
+++ b/qt/d2/qt/QtdObject.d	Sun Nov 08 19:28:01 2009 +0000
@@ -27,8 +27,6 @@
     protected QtdObjectFlags __flags_;
     void* __nativeId;
 
-    mixin SignalHandlerOps;
-        
     this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none)
     {
         __nativeId = nativeId;
--- a/qt/d2/qt/Signal.d	Sun Nov 08 19:20:53 2009 +0000
+++ b/qt/d2/qt/Signal.d	Sun Nov 08 19:28:01 2009 +0000
@@ -12,856 +12,137 @@
 module qt.Signal;
 
 public import qt.QGlobal;
-public import
-    std.metastrings,
-    std.typetuple;
+import qt.qtd.MetaMarshall;
+
 import core.stdc.stdlib : crealloc = realloc, cfree = free;
 import core.stdc.string : memmove;
 import
-    std.traits,
     core.thread,
-    core.exception;
-
-private: // private by default
-
-alias void delegate(Object) DEvent;
-
-extern(C) void rt_attachDisposeEvent(Object o, DEvent e);
-extern(C) void rt_detachDisposeEvent(Object o, DEvent e);
-extern(C) Object _d_toObject(void* p);
-
-void realloc(T)(ref T[] a, size_t length)
-{
-    a = (cast(T*)crealloc(a.ptr, length * T.sizeof))[0..length];
-    if (!a.ptr)
-        new OutOfMemoryError(__FILE__, __LINE__);
-}
+    core.exception,
+    std.algorithm;
 
-
-void append(T)(ref T[] a, T element)
-{
-    auto newLen = a.length + 1;
-    a = (cast(T*)crealloc(a.ptr, newLen * T.sizeof))[0..newLen];
-    if (!a.ptr)
-        new OutOfMemoryError(__FILE__, __LINE__);
-    a[newLen - 1] = element;
-}
+public import
+    std.typetuple,
+    std.traits,
+    std.conv,
+    std.string,
+    std.metastrings;
 
-void move(T)(ref T[] a, size_t src, size_t dest, size_t length)
-{
-    if (a.length > 1)
-        memmove(a.ptr + dest, a.ptr + src, length * T.sizeof);
-}
-
-// COMPILER BUG: Though this is private cannot name it 'remove' because of conflicts
-// with Array.remove
-void erase(T)(ref T[] a, size_t i) 
+   
+// returns name, arguments or tuple of the function depending on type parameter
+enum {_Name, _Tuple, _Args}
+string getFunc(int type)(string fullName)
 {
-    auto newLen = a.length - 1;
-    move(a, i + 1, i, newLen);
-    realloc(a, newLen);
-}
-
-version (QtdUnittest)
-{
-    unittest
-    {
-        int[] a;
-        realloc(a, 16);
-        assert(a.length == 16);
-        foreach (i, ref e; a)
-            e = i;
-        realloc(a, 4096);
-        assert(a.length == 4096);
-        foreach (i, e; a[0..16])
-            assert(e == i);
-        cfree(a.ptr);
-    }
-}
-
-//TODO: should be in the standard library
-struct STuple(A...)
-{
-    static string genSTuple()
-    {
-        string r = "";
-        foreach (i, e; A)
-            r ~= A[i].stringof ~ " _" ~ ToString!(i) ~ ";";
-        return r;
-    }
-
-    mixin (genSTuple);
-    template at(size_t i) { mixin("alias _" ~ ToString!(i) ~ " at;"); };
-}
-
-enum SignalEventId
-{
-    firstSlotConnected,
-    lastSlotDisconnected
+    int pos = 0;
+    foreach(i, c; fullName)
+        if (c == '(')
+            static if (type == _Tuple)
+                return fullName[i..$];
+            else if (type == _Name)
+                return fullName[0..i];
+            else if (type == _Args)
+                for(int j = fullName.length-1;; j--)
+                    if(fullName[j] == ')')
+                        return fullName[i+1 .. j];
+    return null;
 }
 
-public class SignalException : Exception
+/** The beast that takes string representation of function arguments
+  * and returns an array of default values it doesn't check if arguments
+  * without default values follow the arguments with default values for
+  * simplicity. It is done by mixing in an delegate alias.
+  */
+string[] defaultValues(string signature)
 {
-    this(string msg)
-    {
-        super(msg);
-    }
-}
-
-struct Fn
-{
-    void* funcptr;
-
-    static typeof(this) opCall(R, A...)(R function(A) fn)
-    {
-        typeof(this) r;
-        r.funcptr = fn;
-        return r;
-    }
+    int braces = 0;
+    bool inDefaultValue = false;
+    bool inStringLiteral = false;
+    string[] res;
+    int startValue = 0;
+    
+    if(strip(signature).length == 0)
+        return res;
 
-    template call(R)
-    {
-        R call(A...)(A args)
-        {
-            alias R function(A) Fn;
-            return (cast(Fn)funcptr)(args);
-        }
-    }
-
-    S get(S)()
-    {
-        static assert (is(typeof(*S.init) == function));
-        return cast(S)funcptr;
-    }
-}
-
-struct Dg
-{
-    void* context;
-    void* funcptr;
-
-    static typeof(this) opCall(R, A...)(R delegate(A) dg)
+    foreach (i,c; signature)
     {
-        typeof(this) r;
-        r.context = dg.ptr;
-        r.funcptr = dg.funcptr;
-        return r;
-    }
-
-    template call(R)
-    {
-        R call(A...)(A args)
+        if(!inStringLiteral)
         {
-            R delegate(A) dg; // BUG: parameter storage classes are ignored
-            dg.ptr = context;
-            dg.funcptr = cast(typeof(dg.funcptr))funcptr;
-            return dg(args);
-        }
-    }
-
-    S get(S)()
-    {
-        static assert (is(S == delegate));
-        S r;
-        r.ptr = context;
-        r.funcptr = cast(typeof(r.funcptr))funcptr;
-        return r;
-    }
-}
-
-struct Slot(R)
-{
-    alias R Receiver;
-
-    Receiver receiver;
-    Dg invoker;
-    ConnectionFlags flags;
-    
-    static if (is(Receiver == Dg))
-    {
-        static const isDelegate = true;
-                
-        bool isDisposed()
-        {
-            return !receiver.funcptr;
-        }
-        
-        void dispose()
-        {
-            receiver.funcptr = null;
-            receiver.context = null;
+            if(c == '{' || c =='(')
+                braces++;
+            else if(c == '}' || c ==')')
+                braces--;
         }
 
-        Object getObject()
-        {           
-            return flags & ConnectionFlags.NoObject || !receiver.context
-                ? null : _d_toObject(receiver.context);
-        }
-    }
-    else
-        static const isDelegate = false;
-}
-
-enum SlotListId
-{
-    Func, // function pointers
-    Weak, // object delegates stored in C heap
-    Strong // delegates stored in GC heap
-}
-
-/**
-    Used to specify the type of a signal-to-slot connection.
-
-    Examples:
-----
-class Sender
-{
-    mixin Signal!("changed");
-    void change()
-    {
-        changed.emit;
-    }
-}
-
-
-class Receiver
-{
-    void alarm() {}
-}
-
-void main()
-{
-    auto s = new Sender;
-    auto r = new Receiver;
-    s.changed.connect(&r.alarm); // now s weakly references r
-
-    r = null;
-    // collect garbage (assume there is no more reachable pointers
-    // to the receiver and it gets finalized)
-    ...
-
-    s.change;
-    // weak reference to the receiving object
-    // has been removed from the sender's connection lists.
-
-    r = new Receiver;
-    s.changed.connect(&r.alarm, ConnectionFlags.Strong);
-
-    r = null;
-    // collect garbage
-    ...
-    // the receiving object has not been finalized because s strongly references it.
-
-    s.change; // the receiver is called.
-    delete r;
-    s.change; // the receiver is disconnected from the sender.
-
-    static void foo()
-    {
-    }
-
-    s.changed.connect(&foo);
-    s.changed.emit; // foo is called.
-    s.changed.disconnect(&foo); // must be explicitly disconnected.
-
-    void bar()
-    {
-    }
-
-    // ConnectionFlags.NoObject must be specified for delegates
-    // to non-static local functions or struct member functions.
-    s.changed.connect(&bar, ConnectionFlags.NoObject);
-    s.changed.emit; // bar is called.
-    s.changed.disconnect(&bar); // must be explicitly disconnected.
-}
-----
-*/
-public enum ConnectionFlags : ubyte
-{
-    ///
-    None,
-    /**
-        The receiver will be stored as weak reference (implied if ConnectionFlags.NoObject is not specified).
-        If the signal receiver is not a function pointer or a delegate referencing a D class instance.
-        the sender will not be notified when the receiving object is deleted and emitting the signal
-        connected to that receiving object will result in undefined behavior.
-    */
-    Weak                = 0x0001,
-    /**
-        The receiver is stored as strong reference (implied if ConnectionFlags.NoObject is specified).
-    */
-    Strong              = 0x0002,
-    /**
-        Must be specified if the receiver is not a function pointer or a delegate referencing a D class instance.
-    */
-    NoObject            = 0x0004
-
-    // Queued           = 0x0004,
-    // BlockingQueued   = 0x0008
-}
-
-
-struct SlotList(SlotT, bool strong = false)
-{
-    alias SlotT SlotType;
-    SlotType[] data;
-
-    void length(size_t length)
-    {
-        static if (strong)
-            data.length = length;
-        else
-            realloc(data, length);
-    }
-
-    SlotType* add(SlotType slot)
-    {
-        auto oldLen = data.length;
-        length = oldLen + 1;
-        auto p = &data[oldLen];
-        *p = slot;
-        return p;
-    }
-
-    SlotType* get(int slotId)
-    {
-        return &data[slotId];
-    }
-
-    void remove(int slotId)
-    {
-        move(data, slotId, slotId + 1, data.length - slotId - 1);
-        data = data[0..$ - 1];
-    }
-
-    size_t length()
-    {
-        return data.length;
-    }
-
-    void free()
-    {
-        static if (!strong)
-            cfree(data.ptr);
-    }
-}
-
-public alias void delegate(int signalId, SignalEventId event) SignalEvent;
-
-struct Receivers
-{
-    struct Data
-    {
-        Object object;
-        int refs;
-    }
-    
-    Data[] data;
-    void add(Object receiver, DEvent disposeEvent)
-    {        
-        foreach (ref d; data)
+        if(c == '\"' || c == '\'')
         {
-            if (d.object is receiver)
-            {               
-                d.refs++;              
-                return;
+            if (inStringLiteral)
+            {
+                if(signature[i-1] != '\\')
+                    inStringLiteral = false;
+            }
+            else
+            {
+                inStringLiteral = true;
             }
         }
         
-        append(data, Data(receiver, 1));
-        rt_attachDisposeEvent(receiver, disposeEvent);
-    }
-    
-    void remove(Object receiver, DEvent disposeEvent)
-    {
-        foreach (i, ref d; data)
+        if (!inStringLiteral && braces == 0)
         {
-            if (d.object is receiver)
+            if(c == '=') // found default value
             {
-                assert (d.refs);
-                d.refs--;
-                if (!d.refs)
+                inDefaultValue = true;
+                startValue = i+1;
+            }
+            else if(c == ',') // next function argument
+            {
+                if (inDefaultValue)
                 {
-                    .erase(data, i);                    
-                    rt_detachDisposeEvent(receiver, disposeEvent);
+                    res ~= signature[startValue..i];
+                    inDefaultValue = false;
                 }
-                return;
-            }
-        }
-        
-        assert (false);
-    }
-    
-    // remove all refarences for receiver, receiver has been disposed
-    void removeAll(Object receiver)
-    {
-        foreach (i, ref d; data)
-        {
-            if (d.object is receiver) 
-            {
-                .erase(data, i);
-                return;
             }
         }
     }
     
-    // remove all references for all receivers, detaching dispose events
-    void free(DEvent disposeEvent)
-    {
-        foreach (i, ref d; data)
-            rt_detachDisposeEvent(d.object, disposeEvent);
-        cfree(data.ptr);
-        data = null;
-    }
-}
-
-struct SignalConnections
-{
-    bool isInUse;
-
-    STuple!(
-        SlotList!(Slot!(Fn)),
-        SlotList!(Slot!(Dg)),
-        SlotList!(Slot!(Dg), true)
-    ) slotLists;
-
-    STuple!(
-        Fn[],
-        Dg[]
-    ) delayedDisconnects;
-
-    void addDelayedDisconnect(Fn r)
-    {
-        delayedDisconnects.at!(0) ~= r;
-    }
-
-    void addDelayedDisconnect(Dg r)
-    {
-        delayedDisconnects.at!(1) ~= r;
-    }
-
-    SlotListType!(slotListId)* getSlotList(int slotListId)()
-    {
-        return &slotLists.tupleof[slotListId];
-    }
-
-    bool hasSlots()
-    {
-        foreach(i, e; slotLists.tupleof)
-        {
-            if (slotLists.tupleof[i].length)
-                return true;
-        }
-        return false;
-    }
-
-    int slotCount()
-    {
-        int count;
-        foreach(i, e; slotLists.tupleof)
-            count += slotLists.at!(i).length;
-        return count;
-    }
+    if (inDefaultValue)
+        res ~= signature[startValue..$];
 
-    void slotListLengths(int[] lengths)
-    {
-        foreach(i, e; slotLists.tupleof)
-             lengths[i] = slotLists.at!(i).length;
-    }
-
-    SlotType!(slotListId)* addSlot(int slotListId)(SlotType!(slotListId) slot)
-    {
-        return getSlotList!(slotListId).add(slot);
-    }
-
-    void removeSlot(int slotListId)(int slotId)
-    {
-        slotLists.at!(slotListId).remove(slotId);
-    }
-
-    void free()
-    {
-        foreach(i, e; slotLists.tupleof)
-        {
-            static if (is(typeof(slotLists.at!(i).free)))
-                slotLists.at!(i).free;
-        }
-    }
-    
-    void onReceiverDisposed(Object receiver)
-    {
-        foreach (i, e; slotLists.tupleof)
-        {
-            static if (slotLists.at!(i).SlotType.isDelegate)
-            {
-                foreach (ref slot; slotLists.at!(i).data)
-                {
-                    if (slot.getObject is receiver)
-                        slot.dispose;
-                }
-            }
-        }
-    }
-
-    template SlotListType(int slotListId)
-    {
-        alias typeof(slotLists.tupleof)[slotListId] SlotListType;
-    }
-
-    template SlotType(int slotListId)
-    {
-        alias SlotListType!(slotListId).SlotType SlotType;
-    }
-
-    template ReceiverType(int slotListId)
-    {
-        alias SlotType!(slotListId).Receiver ReceiverType;
-    }
-
-    static const slotListCount = slotLists.tupleof.length;
-}
-
-
-private Object signalSender_;
-
-/**
-    If called from a slot, returns the object
-    that is emitting the signal. Otherwise, returns null.
-*/
-public Object signalSender() {
-    return signalSender_;
+    return res;
 }
 
-public final class SignalHandler
+int defaultValuesLength(string[] defVals)
 {
-    SignalConnections[] connections;
-    Receivers receivers;
-    Object owner;
-    int blocked;
-    
-    SignalEvent signalEvent;
-       
-    alias SignalConnections.SlotType SlotType;
-    alias SignalConnections.ReceiverType ReceiverType;
-
-    public this(Object owner_) {
-        owner = owner_;
-    }
-
-    private SignalConnections* getConnections(int signalId)
-    {
-        if (signalId < connections.length)
-            return &connections[signalId];
-        return null;
-    }
-
-    private SlotType!(slotListId)* addSlot(int slotListId)(int signalId, ReceiverType!(slotListId) receiver,
-        Dg invoker, ConnectionFlags flags)
-    {
-        if (signalId >= connections.length)
-            connections.length = signalId + 1;
-        auto slot = connections[signalId].addSlot!(slotListId)(SlotType!(slotListId)(receiver, invoker));
-        
-        static if (slot.isDelegate)
-        {
-            if (!(flags & ConnectionFlags.NoObject))
-                receivers.add(_d_toObject(receiver.context), &onReceiverDisposed);
-        }
-
-        if (signalEvent && connections[signalId].slotCount == 1)
-            signalEvent(signalId, SignalEventId.firstSlotConnected);
-
-        return slot;
-    }
-    
-    void onReceiverDisposed(Object receiver)
-    {
-        synchronized(this)
-        {
-            foreach(ref c; connections)
-                c.onReceiverDisposed(receiver);
-            receivers.removeAll(receiver);
-        }
-    }
-
-    private void removeSlot(int slotListId)(int signalId, int slotId)
-    {
-        auto slot = connections[signalId].getSlotList!(slotListId).get(slotId);
-        static if (slot.isDelegate)
-        {
-            if (auto obj = slot.getObject)
-                receivers.remove(obj, &onReceiverDisposed);
-        }
-        
-        connections[signalId].removeSlot!(slotListId)(slotId);
-
-        if (signalEvent && !connections[signalId].slotCount)
-            signalEvent(signalId, SignalEventId.lastSlotDisconnected);
-    }
-
-    size_t slotCount(int signalId)
-    {
-        synchronized(this)
-        {
-            auto con = getConnections(signalId);
-            if (con)
-                return con.slotCount;
-            return 0;
-        }
-    }
-
-    void connect(Receiver)(int signalId, Receiver receiver,
-        Dg invoker, ConnectionFlags flags)
-    {
-        synchronized(this)
-        {
-            static if (is(typeof(receiver.context)))
-            {
-                Object obj;
-                if ((flags & ConnectionFlags.NoObject))
-                {
-                    // strong by default
-                    if (flags & ConnectionFlags.Weak)
-                        addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
-                    else
-                        addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
-                }
-                else
-                {
-                    // weak by default
-                    if (flags & ConnectionFlags.Strong)
-                        addSlot!(SlotListId.Strong)(signalId, receiver, invoker, flags);
-                    else
-                        addSlot!(SlotListId.Weak)(signalId, receiver, invoker, flags);
-                }
-            }
-            else
-                addSlot!(SlotListId.Func)(signalId, receiver, invoker, flags);
-        }
-    }
-
-    void disconnect(Receiver)(int signalId, Receiver receiver)
-    {
-        synchronized(this)
-        {
-            auto cons = getConnections(signalId);
-            if (!cons)
-                return;
-
-            // if called from a slot being executed by this signal, delay disconnection
-            // until all slots has been called.
-            if (cons.isInUse)
-            {
-                cons.addDelayedDisconnect(receiver);
-                return;
-            }
-
-        TOP:
-            foreach (slotListId, e; cons.slotLists.tupleof)
-            {
-                /// COMPILER BUG: ReceiverType is evaluated to expression instead of type.
-                static if (is(typeof(cons.ReceiverType!(slotListId)) == Receiver))
-                {
-                    auto slotList = cons.getSlotList!(slotListId);
-                    for (int slotId; slotId < slotList.length;)
-                    {
-                        auto slot = slotList.get(slotId);
-                        static if (slot.isDelegate)
-                        {
-                            if (slot.isDisposed)
-                            {
-                                removeSlot!(slotListId)(signalId, slotId);
-                                continue;
-                            }
-                        }
-
-                        if (slot.receiver == receiver)
-                        {
-                            removeSlot!(slotListId)(signalId, slotId);
-                            break TOP;
-                        }
-
-                        slotId++;
-                    }
-                }
-            }
-        }
-    }
-
-    void emit(A...)(size_t signalId, A args)
-    {
-        synchronized(this)
-        {
-            if (signalId >= connections.length || blocked)
-                return;
-            auto cons = &connections[signalId];
-
-            if (cons.hasSlots)
-            {
-                {
-                    cons.isInUse = true;
-                    signalSender_ = owner;
-                    scope(exit)
-                    {
-                        cons.isInUse = false;
-                        signalSender_ = null;
-                    }
-
-                    // Store the lengths to avoid calling new slots
-                    // connected in the slots being called.
-                    // dmd bug: int[cons.slotListCount] fails
-                    static const c = cons.slotListCount;
-                    int[c] lengths = void;
-                    cons.slotListLengths(lengths);
-
-                    foreach (slotListId, e; cons.slotLists.tupleof)
-                    {
-                        auto slotList = cons.getSlotList!(slotListId);
-                        for (size_t slotId; slotId < lengths[slotListId];)
-                        {
-                            auto slot = slotList.get(slotId);
-                            static if (slot.isDelegate)
-                            {
-                                if (slot.isDisposed)
-                                {
-                                    removeSlot!(slotListId)(signalId, slotId);
-                                    lengths[slotListId]--;
-                                    continue;
-                                }
-                            }
-
-                            slot.invoker.call!(void)(slot.receiver, args);
-                            ++slotId;
-                        }
-                    }
-                }
-
-
-                // process delayed disconnects if any
-                foreach(i, e; cons.delayedDisconnects.tupleof)
-                {
-                    if (cons.delayedDisconnects.at!(i).length)
-                    {
-                        foreach (d; cons.delayedDisconnects.at!(i))
-                            disconnect(signalId, d);
-                        cons.delayedDisconnects.at!(i).length = 0;
-                    }
-                }
-            }
-        }
-    }
-
-    // Adjusts signal arguments and calls the slot. S - slot signature, A - signal arguments
-    private void invokeSlot(S, Receiver, A...)(Receiver r, A args)
-    {
-        r.get!(S)()(args[0..ParameterTypeTuple!(S).length]);
-    }
-
-    void blockSignals()
-    {
-        synchronized(this)
-            blocked++;
-    }
-
-    void unblockSignals()
-    {
-        synchronized(this)
-        {
-            if(!blocked)
-                throw new SignalException("Signals are not blocked");
-            blocked--;
-        }
-    }
-
-    ~this()
-    {
-        receivers.free(&onReceiverDisposed);
-        foreach(ref c; connections)
-            c.free;
-    }
-}
-
-public template SignalHandlerOps()
-{
-    static assert (is(typeof(this.signalHandler)),
-        "SignalHandlerOps is already instantiated in " ~ typeof(this).stringof ~ " or one of its base classes");
-
-protected:
-    SignalHandler signalHandler_; // manages signal-to-slot connections
-
-    final SignalHandler signalHandler()
-    {
-        if (!signalHandler_)
-        {
-            signalHandler_ = new SignalHandler(this);
-            onSignalHandlerCreated(signalHandler_);
-        }
-        return signalHandler_;
-    }
-
-    void onSignalHandlerCreated(ref SignalHandler sh)
-    {
-    }
-
-public:
-    final void blockSignals()
-    {
-        signalHandler.blockSignals();
-    }
-
-    final void unblockSignals()
-    {
-        signalHandler.unblockSignals();
-    }
-
-    template connect(string signalName, A...)
-    {
-        static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None)
-            if (isFnOrDg!(Func))
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            static if (isFn!(Func))
-                alias Fn Callable;
-            else
-                alias Dg Callable;
-            auto invoker = Dg(&sh.invokeSlot!(typeof(func), Callable, sig[2..$]));
-            sh.connect(sig[1], Callable(func), invoker, flags);
-        }
-    }
-
-    template disconnect(string signalName, A...)
-    {
-        static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None)
-            if (isFnOrDg!(Func))
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            static if (isFn!(Func))
-                alias Fn Callable;
-            else
-                alias Dg Callable;
-            sh.disconnect(sig[1], Callable(func));
-        }
-    }
-/*
-    template slotCount(string signalName, A...)
-    {
-        debug static void slotCount(T)(T sender)
-        {
-            alias findSignal!(T, signalName, Func, A).result sig;
-            auto sh = sender.signalHandler();
-            return sh.slotCount(sig[1]);
-        }
-    }
-    */
+    return defVals.length;
 }
 
 /**
     New implementation.
 */
 
-const string signalPrefix = "__signal";
+
+// need this to mark static metamethods-info whether it's generated by presence of default args
+enum DefaultArgs
+{
+    None, Start, Continue
+}
+
+// templates for extracting data from static meta-information of signals, slots or properties
+// public alias TypeTuple!("name", index, OwnerClass, DefaultArgs.Start, ArgTypes) __signal
+template MetaEntryName(source...)
+{
+    enum MetaEntryName = source[0]; // name of the metaentry is the first element
+}
+
+template MetaEntryOwner(source...)
+{
+    alias TupleWrapper!(source[2]).at[0] MetaEntryOwner; // class that owns the property is the third
+    // Compiler #BUG 3092 - evaluates MetaEntryOwner as a Tuple with one element
+}
+
+template MetaEntryArgs(source...)
+{
+    alias source[4 .. $] MetaEntryArgs; // arguments-tuple starts from the fourth position
+}
 
 template TupleWrapper(A...) { alias A at; }
 
@@ -955,6 +236,14 @@
     }
 }
 
+template ByOwner(Owner)
+{
+    template ByOwner(source...)
+    {
+        enum ByOwner = is(MetaEntryOwner!source == Owner);
+    }
+}
+
 template staticSymbolName(string prefix, int id)
 {
     const string staticSymbolName = prefix ~ ToString!(id);
@@ -965,6 +254,7 @@
     const string signatureString = name ~ "(" ~ joinArgs!(A) ~ ")";
 }
 
+// recursive search in the static meta-information
 template findSymbolImpl(string prefix, C, int id, alias pred)
 {
     static if ( is(typeof(mixin("C." ~ staticSymbolName!(prefix, id)))) )
@@ -1006,6 +296,30 @@
     }
 }
 
+// recursive search in the static meta-information
+template findSymbolsImpl(string prefix, C, int id, alias pred)
+{
+    static if ( is(typeof(mixin("C." ~ staticSymbolName!(prefix, id)))) )
+    {
+        mixin ("alias C." ~ staticSymbolName!(prefix, id) ~ " current;");
+        static if (pred!current) {
+            alias TupleWrapper!current subres;
+//                    pragma(msg, toStringNow!id ~ " " ~ subres.stringof);
+        } else
+            alias TypeTuple!() subres;
+        alias TypeTuple!(subres, findSymbolsImpl!(prefix, C, id + 1, pred).result) result;
+    }
+    else
+    {
+        alias TypeTuple!() result;
+    }
+}
+
+template findSymbols(string prefix, C, alias pred)
+{
+    alias findSymbolsImpl!(prefix, C, 0, pred).result findSymbols;
+}
+
 string __toString(long v)
 {
     if (v == 0)
@@ -1032,18 +346,42 @@
     return ret;
 }
 
-public string SignalEmitter(A...)(SignalType signalType, string name, int index)
+string convertSignalArguments(Args...)()
+{
+//        void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+
+    string res = "void*[" ~ __toString(Args.length+1) ~ "] _a = [null";
+    foreach(i, _; Args)
+        res ~= ", " ~ "cast(void*) &" ~ convertSignalArgument!(Args[i])("_t" ~ __toString(i));
+    res ~= "];\n";
+    return res;
+}
+
+public string SignalEmitter(A...)(SignalType signalType, string name, string[] defVals, int localIndex)
 {
     string fullArgs, args;
+    int defValsLength = defVals.length;
+    string argsConversion = "";
+    string argsPtr = "null";
     static if (A.length)
     {
-        fullArgs = A[0].stringof ~ " a0";
-        args = ", a0";
+        while(A.length != defVals.length)
+            defVals = "" ~ defVals;
+        
+        fullArgs = A[0].stringof ~ " _t0";
+        if (defVals[0].length)
+            fullArgs ~= " = " ~ defVals[0];
+        args = "_t0";
         foreach(i, _; A[1..$])
         {
-            fullArgs ~= ", " ~ A[i+1].stringof ~ " a" ~ __toString(i+1);
-            args ~= ", a" ~ __toString(i+1);
+            fullArgs ~= ", " ~ A[i+1].stringof ~ " _t" ~ __toString(i+1);
+            if (defVals[i+1].length)
+                fullArgs ~= " = " ~ defVals[i+1];
+            args ~= ", _t" ~ __toString(i+1);
         }
+        // build up conversion of signal args from D to C++
+        argsPtr = "_a.ptr";
+        argsConversion = convertSignalArguments!(A)();
     }
     string attribute;
     string sigName = name;
@@ -1051,197 +389,147 @@
         name ~= "_emit";
     else
         attribute = "protected ";
-    string str = attribute ~ "void " ~ name ~ "(" ~ fullArgs ~ ")" ~
-                 "{ this.signalHandler.emit(" ~ __toString(index) ~ args ~ "); }";
+    
+    string indexArgs = __toString(localIndex);
+    if(defValsLength > 0)
+        indexArgs ~= ", " ~ __toString(localIndex+defValsLength);
+    string str = attribute ~ "final void " ~ name ~ "(" ~ fullArgs ~ ") {\n" ~ argsConversion ~ "\n"
+                           ~ "    QMetaObject.activate(this, typeof(this).staticMetaObject, " ~ indexArgs ~ ", " ~ argsPtr ~ ");\n"
+                           ~ "}\n"; // ~
     return str;
 }
-
 /** ---------------- */
 
 
-/**
-    Examples:
-----
-struct Args
-{
-    bool cancel;
-}
-
-class C
-{
-    private int _x;
-    // reference parameters are not supported yet,
-    // so we pass arguments by pointer.
-    mixin Signal!("xChanging", int, Args*);
-    mixin Signal!("xChanged");
-
-    void x(int v)
-    {
-        if (v != _x)
-        {
-            Args args;
-            xChanging.emit(v, &args);
-            if (!args.cancel)
-            {
-                _x = v;
-                xChanged.emit;
-            }
-        }
-    }
-}
-----
-*/
+const string signalPrefix = "__signal";
+const string slotPrefix = "__slot";
 
 enum SignalType
 {
     BindQtSignal,
-    NewSignal
-}
-
-template BindQtSignal(string name, A...)
-{
-    mixin SignalImpl!(0, name, SignalType.BindQtSignal, A);
-}
-
-template Signal(string name, A...)
-{
-    mixin SignalImpl!(0, name, SignalType.NewSignal, A);
+    NewSignal,
+    NewSlot
 }
 
-template SignalImpl(int index, string name, SignalType signalType, A...)
+template BindQtSignal(string fullName)
 {
-    static if (is(typeof(mixin(typeof(this).stringof ~ ".__signal" ~ ToString!(index)))))
-        mixin SignalImpl!(index + 1, name, signalType, A);
-    else
-    {
-        // mixed-in once
-        static if (!is(typeof(this.signalHandler)))
-            mixin SignalHandlerOps;
-
-        mixin (SignalEmitter!(A)(signalType, name, index));
-        mixin("public alias TypeTuple!(\"" ~ name ~ "\", index, A) __signal" ~ ToString!(index) ~ ";");
-    }
+    mixin MetaMethodImpl!(signalPrefix, 0, fullName, SignalType.BindQtSignal);
 }
 
-extern(C) alias void function(void*) SlotConnector;
-
-debug (UnitTest)
+template Signal(string fullName)
 {
-    class A
-    {
-        mixin Signal!("scorched", int);
-
-        int signalId1 = -1;
-        int signalId2 = -1;
-
-        void onFirstConnect(int sId)
-        {
-            signalId1 = sId;
-        }
-
-        void onLastDisconnect(int sId)
-        {
-            signalId2 = sId;
-        }
+    mixin MetaMethodImpl!(signalPrefix, 0, fullName, SignalType.NewSignal);
+}
 
-        this()
-        {
-            signalHandler.firstSlotConnected = &onFirstConnect;
-            signalHandler.lastSlotDisconnected = &onLastDisconnect;
-        }
-    }
-
-    class B : A
-    {
-        mixin Signal!("booed", int);
-
-        int bazSum;
-        void baz(int i)
-        {
-            bazSum += i;
-        }
-    }
-
-    class C : A
-    {
-        mixin Signal!("cooked");
-    }
+template Slot(string fullName)
+{
+    mixin MetaMethodImpl!(slotPrefix, 0, fullName, SignalType.NewSlot);
 }
 
-unittest
+template SignalImpl(int index, string fullName, SignalType signalType)
 {
-    static int fooSum;
-    static int barSum;
-
-    static void foo(int i)
-    {
-        fooSum += i;
-    }
-
-    void bar(long i)
+    static if (is(typeof(mixin(typeof(this).stringof ~ "." ~ signalPrefix ~ ToString!(index)))))
+        mixin SignalImpl!(index + 1, fullName, signalType);
+    else
     {
-        barSum += i;
-    }
-
-    auto a = new A;
-    auto b = new B;
-    auto c = new C;
-    assert(b.scorched.signalId == 0);
-    assert(b.booed.signalId == 1);
-    assert(c.cooked.signalId == 1);
-
-    auto sh = b.signalHandler;
-
-    b.scorched.connect(&foo);
-    assert(sh.connections.length == 1);
-    assert(b.signalId1 == 0);
-    auto scCons = &sh.connections[0];
-
-    assert(scCons.getSlotList!(SlotListId.Func).length == 1);
-    b.scorched.emit(1);
-    assert(fooSum == 1);
-
-    b.scorched.connect(&bar, ConnectionFlags.NoObject);
-    assert(sh.connections.length == 1);
-    assert(scCons.getSlotList!(SlotListId.Strong).length == 1);
-    b.scorched.emit(1);
-    assert (fooSum == 2 && barSum == 1);
+//        pragma(msg, "alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        mixin("alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        alias ParameterTypeTuple!(Dg) ArgTypes;
+        enum args = getFunc!_Args(fullName);
+        enum defVals = defaultValues(args);
+        enum defValsLength = defaultValuesLength(defVals);
 
-    b.scorched.connect(&b.baz);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert (fooSum == 3 && barSum == 2 && b.bazSum == 1);
-
-    b.scorched.disconnect(&bar);
-    assert(scCons.slotCount == 2);
-    b.scorched.disconnect(&b.baz);
-    assert(scCons.slotCount == 1);
-    b.scorched.disconnect(&foo);
-    assert(scCons.slotCount == 0);
-    assert(b.signalId2 == 0);
-
-    fooSum = 0;
-    void connectFoo()
+//        pragma (msg, SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, index));
+        mixin InsertMetaSignal!(fullName, index, defValsLength, ArgTypes);
+//        pragma (msg, ctfe_meta_signal!(ArgTypes)(fullName, index, defValsLength));
+    }
+}
+template MetaMethodImpl(string metaPrefix, int index, string fullName, SignalType signalType)
+{
+    static if (is(typeof(mixin(typeof(this).stringof ~ "." ~ metaPrefix ~ toStringNow!(index)))))
+    {
+        mixin MetaMethodImpl!(metaPrefix, index + 1, fullName, signalType);
+    }
+    else
     {
-        b.scorched.connect(&foo);
-        b.scorched.disconnect(&connectFoo);
+        mixin("alias void delegate" ~ getFunc!_Tuple(fullName) ~ " Dg;");
+        alias ParameterTypeTuple!(Dg) ArgTypes;
+        enum args = getFunc!_Args(fullName);
+        enum defVals = defaultValues(args);
+        enum defValsLength = defaultValuesLength(defVals);
+        
+        static if (metaPrefix == signalPrefix)
+        {
+            // calculating local index of the signal
+            static if (typeof(this).stringof == "QObject")
+                enum localIndex = index;
+            else
+                mixin ("enum localIndex = index - 1 - lastSignalIndex_" ~ (typeof(super)).stringof ~ ";");
+            
+            static if (signalType == SignalType.NewSignal)
+            {
+                pragma (msg, SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, localIndex));
+                mixin (SignalEmitter!(ArgTypes)(SignalType.NewSignal, getFunc!_Name(fullName), defVals, localIndex));
+            }
+        }
+        mixin InsertMetaMethod!(fullName, metaPrefix, index, defValsLength, DefaultArgs.Start, ArgTypes);
+//        pragma (msg, ctfe_meta_signal!(ArgTypes)(fullName, index, defValsLength));
+    }
+}
+template InsertMetaMethod(string fullName, string metaPrefix, int index, int defValsCount, DefaultArgs defArgsInitFlag, ArgTypes...)
+{
+    // this identifies if metamethod is was generated by the presence of default args or not
+    static if(defValsCount > 0)
+    {
+        static if (defArgsInitFlag == DefaultArgs.Start)
+            enum defValsFlag = DefaultArgs.Start;
+        else
+            enum defValsFlag = DefaultArgs.Continue;
     }
+    else
+    {
+        static if (defArgsInitFlag == DefaultArgs.Start)
+            enum defValsFlag = DefaultArgs.None;
+        else
+            enum defValsFlag = DefaultArgs.Continue;
+    }
+    static if(defValsCount >= 0)
+        mixin("public alias TypeTuple!(\"" ~ getFunc!_Name(fullName) ~ "\", index, typeof(this), defValsFlag, ArgTypes) " ~ metaPrefix ~ toStringNow!(index) ~ ";");
+    static if(defValsCount > 0)
+        mixin InsertMetaMethod!(fullName, metaPrefix, index+1, defValsCount-1, DefaultArgs.Continue, ArgTypes[0..$-1]);
+}
 
-    b.scorched.connect(&connectFoo, ConnectionFlags.NoObject);
-    b.scorched.emit(1);
-    assert(scCons.getSlotList!(SlotListId.Func).length == 1);
-    assert(scCons.getSlotList!(SlotListId.Strong).length == 0);
-    assert(!fooSum);
 
-    auto r = new B();
-    b.scorched.connect(&r.baz);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert(r.bazSum == 1);
-    assert(fooSum == 1);
+string signature_impl(T...)(string name)
+{
+    string res = name ~ "(";
+    foreach(i, _; T)
+    {
+        if(i > 0)
+            res ~= ",";
+        res ~= T[i].stringof;
+    }
+    res ~= ")";
+    return res;
+}
 
-    delete(r);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 1);
-    b.scorched.emit(1);
-    assert(scCons.getSlotList!(SlotListId.Weak).length == 0);
+template signature(string name, T...)
+{
+    enum signature = signature_impl!(T)(name);
 }
+
+template lastSignalIndex(T)
+{
+    static if (T.stringof == "QObject")
+        enum lastSignalIndex = lastSignalIndexImpl!(T, 0);
+    else
+        mixin ("enum lastSignalIndex = lastSignalIndexImpl!(T, " ~ "T.lastSignalIndex_" ~ (BaseClassesTuple!(T)[0]).stringof ~ ");");
+}
+
+template lastSignalIndexImpl(T, int index)
+{
+    static if (is(typeof(mixin("T." ~ signalPrefix ~ toStringNow!(index)))))
+        enum lastSignalIndexImpl = lastSignalIndexImpl!(T, index + 1);
+    else
+        enum lastSignalIndexImpl = index - 1;
+}
\ No newline at end of file
--- a/qt/d2/qt/core/QModelIndex.d	Sun Nov 08 19:20:53 2009 +0000
+++ b/qt/d2/qt/core/QModelIndex.d	Sun Nov 08 19:28:01 2009 +0000
@@ -4,8 +4,8 @@
 private import qt.core.QObject;
 
 // automatic imports-------------
-private import qt.core.QVariant;
-private import qt.core.QAbstractItemModel;
+//private import qt.core.QVariant;
+//private import qt.core.QAbstractItemModel;
 public import qt.core.Qt;
 
 
@@ -51,7 +51,7 @@
     public final bool isValid() const {
         return __qtd_QModelIndex_isValid(cast(void*)&this);
     }
-
+/*
     public final QAbstractItemModel model() {
 //        void* __qt_return_value = __qtd_QModelIndex_model(&this);
         void* __qt_return_value = m;
@@ -60,7 +60,7 @@
         void* d_obj = qtd_get_d_qobject(__qt_return_value);
         return cast(QAbstractItemModel) d_obj;
     }
-
+*/
     private final bool operator_less(QModelIndex other) {
         return __qtd_QModelIndex_operator_less_QModelIndex(&this, other);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/MOC.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,534 @@
+module qt.qtd.MOC;
+
+import qt.qtd.ctfe.Format;
+
+import std.typetuple;
+
+import qt.Signal;
+import qt.qtd.MetaMarshall;
+
+public import std.traits;
+/**
+   Utils.
+  */
+
+T qMin(T)(T a,T b) { if (a < b) return a; return b; }
+T qMax(T)(T a, T b) { if (a < b) return b; return a; }
+T qBound(T)(T min, T val,T max) { return qMax(min, qMin(max, val)); }
+
+bool is_digit_char(const char s)
+{
+    return (s >= '0' && s <= '9');
+}
+
+bool is_octal_char(const char s)
+{
+    return (s >= '0' && s <= '7');
+}
+
+bool is_hex_char(const char s)
+{
+    return ((s >= 'a' && s <= 'f')
+            || (s >= 'A' && s <= 'F')
+            || (s >= '0' && s <= '9')
+       );
+}
+
+int lastIndexOf(T)(T[] haystack, T[] needle, int from = -1)
+{
+    auto l = haystack.length;
+    auto ol = needle.length;
+    int delta = l - ol;
+    if (from < 0)
+        from = delta;
+    if (from < 0 || from > l)
+        return -1;
+    if (from > delta)
+        from = delta;
+    
+    while(from >= 0)
+    {
+        if (haystack[from..from+ol] == needle)
+            return from;
+        from--;
+    }
+    return -1;
+}
+
+
+T[] newArray(T)(size_t len, T[] from = [])
+{
+    if (len == from.length)
+        return from;
+
+    if (!from.length)
+        from = [T.init];
+
+    if (from.length < len)
+        return newArray!T(len, from ~ from);
+
+    return from[0..len];
+}
+
+string replicate(int n, char value)
+{
+    char[] ret = "".dup;
+    if (n > 0)
+    {
+//        ret = newArray!char(n);
+        for(int i = 0; i < n; i++)
+            ret ~= value;
+    }
+    return cast(string)ret;
+}
+
+template Repeat(T, int I)
+{
+    static if (!I) alias TypeTuple!() Repeat;
+    else alias TypeTuple!(T, Repeat!(T, I - 1)) Repeat;
+}
+
+/**
+   CTFE MOC port.
+  */
+
+enum MethodFlags {
+    AccessPrivate = 0x00,
+    AccessProtected = 0x01,
+    AccessPublic = 0x02,
+    MethodMethod = 0x00,
+    MethodSignal = 0x04,
+    MethodSlot = 0x08,
+    MethodConstructor = 0x0c,
+    MethodCompatibility = 0x10,
+    MethodCloned = 0x20,
+    MethodScriptable = 0x40
+}
+
+enum Access { Private, Protected, Public }
+
+struct FunctionDef
+{
+/*    FunctionDef(): returnTypeIsVolatile(false), access(Private), isConst(false), isVirtual(false),
+                   inlineCode(false), wasCloned(false), isCompat(false), isInvokable(false),
+                   isScriptable(false), isSlot(false), isSignal(false),
+                   isConstructor(false), isDestructor(false), isAbstract(false) {}
+                   */
+//    Type type;
+//    string normalizedType;
+//    string tag;
+//    string name;
+    string sig;
+    string arguments;
+    Access access;    
+/*    bool returnTypeIsVolatile;
+
+    QList<ArgumentDef> arguments;
+
+    enum Access { Private, Protected, Public };
+    bool isConst;
+    bool isVirtual;
+    bool inlineCode;
+    bool wasCloned;
+
+    QByteArray inPrivateClass;
+    bool isCompat;
+    bool isInvokable;
+    bool isScriptable;
+    bool isSlot;
+    bool isSignal;
+    bool isConstructor;
+    bool isDestructor;
+    bool isAbstract;
+    */
+}
+
+FunctionDef newSlot(string sig, string args)
+{
+    return FunctionDef(sig, args, Access.Public);
+}
+
+FunctionDef newSignal(string sig, string args)
+{
+    return FunctionDef(sig, args, Access.Protected);
+}
+
+struct Generator
+{
+    string output;
+    string[] strings;
+//    QByteArray purestSuperClass;
+//    QList<QByteArray> metaTypes;
+}
+
+int lengthOfEscapeSequence(string s, uint i)
+{
+    if (s[i] != '\\' || i >= s.length - 1)
+        return 1;
+    const int startPos = i;
+    ++i;
+    auto ch = s[i];
+    if (ch == 'x') {
+        ++i;
+        while (i < s.length && is_hex_char(s[i]))
+            ++i;
+    } else if (is_octal_char(ch)) {
+        while (i < startPos + 4
+               && i < s.length
+               && is_octal_char(s[i])) {
+            ++i;
+        }
+    } else { // single character escape sequence
+        i = qMin(i + 1, s.length);
+    }
+    return i - startPos;
+}
+
+int strreg(ref Generator gen, string s)
+{
+    int idx = 0;
+    foreach (str; gen.strings) {
+        if (str == s)
+            return idx;
+        idx += str.length + 1;
+        foreach (i, c; str) {
+            if (c == '\\') {
+                int cnt = lengthOfEscapeSequence(str, i) - 1;
+                idx -= cnt;
+                i += cnt;
+            }
+        }
+    }
+    gen.strings ~= s;
+    return idx;
+}
+
+void generateFunctions(ref Generator gen, FunctionDef[] list, string functype, byte type)
+{
+    if (!list.length)
+        return;
+    gen.output ~= format_ctfe("\n // ${}s: signature, parameters, type, tag, flags\n", functype);
+
+    foreach (i, f; list) {
+        byte flags = type;
+
+        if (f.access == Access.Private)
+            flags |= MethodFlags.AccessPrivate;
+        else if (f.access == Access.Public)
+            flags |= MethodFlags.AccessPublic;
+        else if (f.access == Access.Protected)
+            flags |= MethodFlags.AccessProtected;
+
+        gen.output ~= format_ctfe("    ${}, ${}, ${}, ${}, 0x${:x},\n", strreg(gen, f.sig),
+                strreg(gen, f.arguments), strreg(gen, ""/*f.normalizedType*/), strreg(gen, ""/*f.tag*/), flags);
+    }
+}
+
+string generateCode(string className, FunctionDef[] signalList, FunctionDef[] slotList)
+{
+    auto gen = Generator("", []);
+
+/*    bool isQt = (cdef->classname == "Qt");
+    bool isQObject = (cdef->classname == "QObject");
+    bool isConstructible = !cdef->constructorList.isEmpty();
+
+//
+// build the data array
+//
+    int i = 0;
+
+
+    // filter out undeclared enumerators and sets
+    {
+        QList<EnumDef> enumList;
+        for (i = 0; i < cdef->enumList.count(); ++i) {
+            EnumDef def = cdef->enumList.at(i);
+            if (cdef->enumDeclarations.contains(def.name)) {
+                enumList += def;
+            }
+            QByteArray alias = cdef->flagAliases.value(def.name);
+            if (cdef->enumDeclarations.contains(alias)) {
+                def.name = alias;
+                enumList += def;
+            }
+        }
+        cdef->enumList = enumList;
+    }
+
+
+    QByteArray qualifiedClassNameIdentifier = cdef->qualified;
+    qualifiedClassNameIdentifier.replace(':', '_');
+*/
+    bool isConstructible = false;
+    
+    FunctionDef[] propertyList, enumList, constructorList;
+    int index = 12;
+    gen.output ~= format_ctfe("static const uint[] qt_meta_data_${} = [\n", className);
+    gen.output ~= format_ctfe("\n // content:\n");
+    gen.output ~= format_ctfe("    ${},       // revision\n", 2);
+    gen.output ~= format_ctfe("    ${},       // classname\n", strreg(gen, className));
+    gen.output ~= format_ctfe("    ${}, ${}, // classinfo\n", 0, 0);
+//    index += cdef->classInfoList.count() * 2;
+
+    int methodCount = signalList.length + slotList.length;// + cdef->methodList.count();
+    gen.output ~= format_ctfe("    ${}, ${}, // methods\n", methodCount, methodCount ? index : 0);
+    index += methodCount * 5;
+    gen.output ~= format_ctfe("    ${}, ${}, // properties\n", propertyList.length, propertyList.length ? index : 0);
+    index += propertyList.length * 3;
+//    if(cdef->notifyableProperties)
+//        index += cdef->propertyList.count();
+    gen.output ~= format_ctfe("    ${}, ${}, // enums/sets\n", enumList.length, enumList.length ? index : 0);
+
+//    int enumsIndex = index;
+//    for (i = 0; i < cdef->enumList.count(); ++i)
+//        index += 4 + (cdef->enumList.at(i).values.count() * 2);
+    gen.output ~= format_ctfe("    ${}, ${}, // constructors\n", isConstructible ? constructorList.length : 0,
+            isConstructible ? index : 0);
+
+//
+// Build classinfo array
+//
+//    generateClassInfos();
+
+//
+// Build signals array first, otherwise the signal indices would be wrong
+//
+    generateFunctions(gen, signalList, "signal", MethodFlags.MethodSignal);
+
+//
+// Build slots array
+//
+    generateFunctions(gen, slotList, "slot", MethodFlags.MethodSlot);
+
+//
+// Build method array
+//
+//    generateFunctions(cdef->methodList, "method", MethodMethod);
+
+
+//
+// Build property array
+//
+//    generateProperties();
+
+//
+// Build enums array
+//
+//    generateEnums(enumsIndex);
+
+//
+// Build constructors array
+//
+//    if (isConstructible)
+//        generateFunctions(cdef->constructorList, "constructor", MethodConstructor);
+
+//
+// Terminate data array
+//
+    gen.output ~= format_ctfe("\n       0        // eod\n];\n\n");
+
+//
+// Build stringdata array
+//
+    gen.output ~= format_ctfe("static const string qt_meta_stringdata_${} = \n", className);
+    gen.output ~= format_ctfe("    \"");
+    int col = 0;
+    int len = 0;
+    foreach (i, s; gen.strings) {
+        len = s.length;
+        if (col && col + len >= 72) {
+            gen.output ~= format_ctfe("\"\n    \"");
+            col = 0;
+        } else if (len && s[0] >= '0' && s[0] <= '9') {
+            gen.output ~= format_ctfe("\"\"");
+            len += 2;
+        }
+        int idx = 0;
+        while (idx < s.length) {
+            if (idx > 0) {
+                col = 0;
+                gen.output ~= format_ctfe("\"\n    \"");
+            }
+            int spanLen = qMin(cast(uint)70, s.length - idx);
+            // don't cut escape sequences at the end of a line
+            int backSlashPos = s.lastIndexOf("\\", idx + spanLen - 1);
+            if (backSlashPos >= idx) {
+                int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
+                spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, cast(int)(s.length - idx));
+            }
+            gen.output ~= s[idx..idx+spanLen];
+            idx += spanLen;
+            col += spanLen;
+        }
+
+        gen.output ~= "\\0";
+        col += len + 2;
+    }
+    gen.output ~=  "\";\n\n";
+    
+    return gen.output;
+}
+
+string metaCallArgs(Args...)()
+{
+    string res;
+    foreach(i, _; Args) {
+        if (i > 0)
+            res ~= ",";
+        res ~= metaCallArgument!(Args[i])("_a[" ~ __toString(i+1) ~ "]");
+    }
+    return res;
+}
+
+string qtDeclArgs(Args...)()
+{
+    string ret;
+    foreach(i, _; Args)
+    {
+        if(i > 0)
+            ret ~= ",";
+        ret ~= qtDeclArg!(Args[i]);
+    }
+    return ret;
+}
+
+string generate_qt_metacall(alias Signals, alias Slots)()
+{
+    string res = "
+protected int qt_metacall(QMetaObject.Call _c, int _id, void **_a)
+    {
+        _id = super.qt_metacall(_c, _id, _a);
+        if (_id < 0)
+            return _id;\n";
+
+    alias TypeTuple!(Signals.at, Slots.at) Methods;
+    enum methodCount = Methods.length;
+    if(methodCount)
+    {
+        res ~= "
+        if (_c == QMetaObject.Call.InvokeMetaMethod) {
+            switch (_id) {";
+        foreach(i, bogus; Repeat!(void, methodCount)) {
+            res ~= "
+            case " ~ __toString(i) ~ ": " ~ MetaEntryName!(Methods[i].at) ~ "(" ~ metaCallArgs!(MetaEntryArgs!(Methods[i].at))() ~ "); break;";
+        }
+        res ~= "\n            default: ;\n            }\n";
+        res ~= "            _id -= " ~ __toString(methodCount) ~ ";";
+        res ~= "\n        }";
+    }
+    
+    res ~= "\n        return _id;
+    }";
+    return res;
+}
+
+string dDeclArgs(Args...)()
+{
+    string ret;
+    foreach(i, _; Args)
+        ret ~= ", " ~ Args[i].stringof;
+    return ret;
+}
+string genMetaMethodsConstr(alias Funcs)(string className)
+{
+    string res;
+    enum funcsCount = Funcs.at.length;
+    foreach(i, bogus; Repeat!(void, funcsCount))
+    {
+        res ~= "        index++;\n" ~
+               "        _staticMetaObject.addMethod(new " ~ className ~ "(signature!(\"" ~ MetaEntryName!(Funcs.at[i].at) ~ "\"" ~ dDeclArgs!(MetaEntryArgs!(Funcs.at[i].at))()~ "), index));\n\n";
+    }
+    return res;
+}
+string generateMetaObjectConstruction(alias Signals, alias Slots)()
+{
+    string res;
+    res ~= "\n
+    private static void _populateMetaInfo() {
+        alias BaseClassesTuple!(typeof(this))[0] BaseClass;
+        int index = BaseClass.staticMetaObject().methodCount() - 1;\n\n";
+    
+    res ~= genMetaMethodsConstr!(Signals)("QMetaSignal");
+    res ~= genMetaMethodsConstr!(Slots)("QMetaSlot");
+    
+    res ~= "
+    }\n";
+    return res;
+}
+
+string generateQMetaObject(string className)
+{
+    string res;
+    res ~= "
+    QMetaObject metaObject() { return staticMetaObject; }
+    private static QMetaObject _staticMetaObject;
+    private static QMetaObjectNative _nativeStaticMetaObject;
+    public static QMetaObject staticMetaObject() { return _staticMetaObject; }
+    protected static void createStaticMetaObject() {
+        assert(!_staticMetaObject);
+        alias BaseClassesTuple!(typeof(this))[0] BaseClass;
+        if (!BaseClass._staticMetaObject)
+            BaseClass.createStaticMetaObject;
+        auto base = BaseClass._staticMetaObject;
+        _nativeStaticMetaObject = QMetaObjectNative(base.nativeId, qt_meta_stringdata_" ~ className ~ ".ptr,
+                                                    qt_meta_data_" ~ className ~ ".ptr, null );
+        
+        _staticMetaObject = new QMetaObject(&_nativeStaticMetaObject, base);
+//        _staticMetaObject.construct!(typeof(this));
+        _populateMetaInfo();
+    }
+    static this()
+    {
+        createStaticMetaObject();
+    }\n\n";
+    return res;
+}
+
+size_t commaCount(int argCount)
+{
+    size_t ret = 0;
+    if(argCount > 1)
+        ret = argCount - 1;
+    return ret;
+}
+
+FunctionDef[] genFuncDefs(alias Funcs, alias newFunc)()
+{
+    typeof(return) res;
+    enum funcsCount = Funcs.at.length;
+    foreach(i, bogus; Repeat!(void, funcsCount))
+    {
+        string args = replicate(commaCount((MetaEntryArgs!(Funcs.at[i].at)).length), ',');
+        string funcSig = MetaEntryName!(Funcs.at[i].at) ~ "(" ~ qtDeclArgs!(MetaEntryArgs!(Funcs.at[i].at))() ~ ")";
+        res ~= newFunc(funcSig, args);
+    }
+    return res;
+}
+
+string generateMetaInfo(string className, alias Signals, alias Slots)()
+{
+    string res = "";
+    auto signalList = genFuncDefs!(Signals, newSignal)();
+    auto slotList = genFuncDefs!(Slots, newSlot)();
+    res ~= generateCode(className, signalList, slotList);
+    res ~= generate_qt_metacall!(Signals, Slots);
+    res ~= generateMetaObjectConstruction!(Signals, Slots);
+    res ~= generateQMetaObject(className);
+    return res;
+}
+
+template Q_OBJECT_BIND()
+{
+    mixin ("enum lastSignalIndex_" ~ typeof(this).stringof ~ " = " ~ toStringNow!(lastSignalIndex!(typeof(this))) ~ ";");
+}
+
+template Q_OBJECT()
+{
+//    pragma(msg, toStringNow!(lastSignalIndex!(typeof(this))));
+    mixin ("enum lastSignalIndex_" ~ typeof(this).stringof ~ " = " ~ toStringNow!(lastSignalIndex!(typeof(this))) ~ ";");
+    
+    alias TupleWrapper!(findSymbols!(slotPrefix,   typeof(this), ByOwner!(typeof(this)))) Slots;
+    alias TupleWrapper!(findSymbols!(signalPrefix, typeof(this), ByOwner!(typeof(this)))) Signals;
+//    pragma(msg, generateMetaInfo!((typeof(this)).stringof, Signals, Slots)());
+    mixin(generateMetaInfo!((typeof(this)).stringof, Signals, Slots)());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/MetaMarshall.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,57 @@
+module qt.qtd.MetaMarshall;
+
+import std.traits;
+
+template isQObjectType(T) // is a QObject type that belongs to the library
+{
+    enum isQObjectType = is(typeof(mixin("T." ~ "__isQObjectType")));
+}
+
+template isObjectType(T) // is a QObject type that belongs to the library
+{
+    enum isQObjectType = is(typeof(mixin("T." ~ "__isObjectType")));
+}
+
+template isValueType(T) // is a QObject type that belongs to the library
+{
+    enum isQObjectType = is(typeof(mixin("T." ~ "__isValueType")));
+}
+
+template isNativeType(T) // type that doesn't require conversion i.e. is the same in C++ and D
+{
+    enum isNativeType = isNumeric!T || is(T == bool);
+}
+
+// converts an argumnent from C++ to D in qt_metacall
+string metaCallArgument(T)(string ptr)
+{
+    static if (isQObjectType!T)
+        return T.stringof ~ ".__getObject(*cast(void**)(" ~ ptr ~ "))";
+    else static if (isNativeType!T)
+        return "*(cast(" ~ T.stringof ~ "*)" ~ ptr ~ ")";
+    else
+        return "*(cast(" ~ T.stringof ~ "*)" ~ ptr ~ ")";
+        //res = T.stringof;
+}
+
+// converts a D argument type to C++ for registering in Qt meta system
+string qtDeclArg(T)()
+{
+    static if (isQObjectType!T)
+        return T.stringof ~ "*";
+    else static if (isNativeType!T)
+        return T.stringof;
+    else
+        return T.stringof;
+}
+
+// converts an argument from D to C++ in a signal emitter
+string convertSignalArgument(T)(string arg)
+{
+    static if (isQObjectType!T)
+        return arg ~ ".__nativeId";
+    else static if (isNativeType!T)
+        return arg;
+    else
+        return arg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/ctfe/Format.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,693 @@
+/**
+ * Compile-Time String Formatting.
+ * 
+ * Authors: Daniel Keep <daniel.keep@gmail.com>
+ * Copyright: See LICENSE.
+ */
+module qt.qtd.ctfe.Format;
+
+//debug = gb_Format_verbose;
+
+import Integer = qt.qtd.ctfe.Integer;
+import String = qt.qtd.ctfe.String;
+import Tuple = qt.qtd.util.Tuple;
+
+private
+{
+    string stringify(Args...)(size_t index, int alignment,
+                              string opt, Args args)
+    {
+        if( index >= args.length )
+            return "{invalid index " ~ Integer.format_ctfe(index) ~ "}";
+
+        if( alignment != 0 )
+            return "{non-zero alignments not supported yet}";
+
+        foreach( i,_ ; Args )
+        {
+            if( i == index )
+            {
+                static if( is( Args[i] == char ) )
+                {
+                    string r;
+                    r ~= args[i];
+                    return r;
+                }
+                else static if( is( Args[i] : long ) || is( Args[i] : ulong ) )
+                {
+                    int base = 10;
+                    string prefix = "";
+
+                    if( opt == "x" )
+                        base = 16;
+
+                    else if( opt == "xx" )
+                    {
+                        base = 16;
+                        prefix = "0x";
+                    }
+                    else if( opt == "o" )
+                        base = 8;
+
+                    else if( opt == "b" )
+                        base = 2;
+
+                    return prefix ~ Integer.format_ctfe(args[i], base);
+                }
+                else static if( is( Args[i] : string ) )
+                {
+                    if( opt == "x" )
+                    {
+                        return String.hexify_ctfe(args[i][]);
+                    }
+                    
+                    if( opt == "q" )
+                    {
+                        return String.escape_ctfe(args[i][]);
+                    }
+
+                    if( opt == "l" )
+                    {
+                        return Integer.format_ctfe(args[i].length);
+                    }
+                    
+                    // If you don't slice, then the CALLER has to slice the
+                    // string, otherwise CTFE barfs.
+                    return args[i][];
+                }
+                else static if( is( Args[i] Elem : Elem[] ) )
+                {
+                    if( opt == "l" )
+                    {
+                        return Integer.format_ctfe(args[i].length);
+                    }
+                    
+                    string r = "[";
+                    foreach( ei, e ; args[i][] )
+                    {
+                        if( ei != 0 )
+                            r ~= ", ";
+                        r ~= stringify(0, alignment, opt, e);
+                    }
+                    r ~= "]";
+                    return r;
+                }
+                else
+                {
+                    return "{cannot stringify "~Args[i].stringof~"}";
+                }
+            }
+        }
+
+        assert(false);
+    }
+
+    version( Unittest )
+    {
+        static assert( stringify(0, 0, "", 0) == "0" );
+        static assert( stringify(0, 0, "", 1, -2, "abc") == "1" );
+        static assert( stringify(1, 0, "", 1, -2, "abc") == "-2" );
+        static assert( stringify(2, 0, "", 1, -2, "abc") == "abc" );
+
+        static assert( stringify(0, 0, "x", "abc") == `616263` );
+        static assert( stringify(0, 0, "q", "abc") == `"abc"` );
+        static assert( stringify(0, 0, "l", "abc") == `3` );
+
+        static assert( stringify(0, 0, "x", 0x4a) == "4a" );
+
+        static assert( stringify(0, 0, "", [1,2,3]) == "[1, 2, 3]" );
+        static assert( stringify(0, 0, "l", [1,2,3]) == "3" );
+        static assert( stringify(0, 0, "x", [9,10]) == "[9, a]" );
+        static assert( stringify(0, 0, "", ["a","b"]) == "[a, b]" );
+        static assert( stringify(0, 0, "q", ["a","b"]) == "[\"a\", \"b\"]" );
+
+        static assert( stringify(0, 0, "", 'a') == "a" );
+    }
+}
+
+/**
+ * Substitutes a set of arguments into a template string.
+ *
+ * The template string allows for the following escape forms:
+ *
+ * - $$ -- Literal dollar.
+ * - $* -- Next argument.
+ * - $n -- nth argument; 0-9 only.
+ * - ${} -- Next argument.
+ * - ${:f} -- Next argument, using format options "f".
+ * - ${n} -- nth argument.
+ * - ${n:f} -- nth argument, using format options "f".
+ *
+ * formatNamed allows the use of named arguments (given as alternating
+ * name,value pairs), but disallows "next" argument and indexed forms.
+ *
+ * Eventually, alignment and named arguments will be supported.
+ *
+ * Supported formatting options are:
+ *
+ * Integers:
+ * - x -- format integer in hexadecimal.
+ * - o -- format integer in octal.
+ * - b -- format integer in binary.
+ *
+ * Strings:
+ * - q -- quotes the string as a literal.
+ * - x -- formats as hexadecimal data.
+ * - l -- length of the string in decimal.
+ *
+ * Arrays:
+ * - l -- length of the array in decimal.
+ * - Other options are used to control element formatting.
+ *
+ * Params:
+ *  tmpl    = template string.
+ *  args    = arguments to substitute.
+ * Returns:
+ *  formatted string.
+ */
+
+string format_ctfe(Args...)(string tmpl, Args args)
+{
+    string r = "";
+    int argPos = 0;
+    
+    while( tmpl.length > 0 )
+    {
+        bool inExp = false;
+       
+        // Look for a $
+        foreach( i,c ; tmpl )
+        {
+            if (c == '$')
+            {
+                inExp = true;
+                r ~= tmpl[0..i];
+                tmpl = tmpl[i+1..$];
+                break;
+            }
+        }
+
+        // If we didn't find a $, it's because we hit the end of the template.
+        if( !inExp )
+        {
+            r ~= tmpl;
+            break;
+        }
+        
+        // So we're in an expansion/substitution.
+
+        debug(gb_Format_verbose) r ~= "{in exp}";
+
+        if( tmpl.length == 0 )
+        {
+            r ~= "{unterminated substitution}";
+            break;
+        }
+
+        // c is the next character, whilst tmpl is everything left in the
+        // template string.
+        char c = tmpl[0];
+        tmpl = tmpl[1..$];
+        
+        // $$ - escaped $.
+        if( c == '$' )
+        {
+            debug(gb_Format_verbose) r ~= "{escaped $}";
+            r ~= '$';
+            continue;
+        }
+
+        // $n - shortcut for ${n}.
+        if( '0' <= c && c <= '9' )
+        {
+            debug(gb_Format_verbose) r ~= "{shorthand index}";
+            r ~= stringify(c-'0', 0, "", args);
+            continue;
+        }
+
+        // $* - shortcut for ${}
+        if( c == '*' )
+        {
+            debug(gb_Format_verbose) r ~= "{shorthand next}";
+            r ~= stringify(argPos++, 0, "", args);
+            continue;
+        }
+
+        // This means we got a $ followed by something unexpected.
+        if( c != '{' )
+        {
+            r ~= "{malformed substitution}";
+            break;
+        }
+        
+        if( tmpl.length == 0 )
+        {
+            r ~= "{unterminated substitution}";
+            break;
+        }
+        
+        debug(gb_Format_verbose)
+        {
+            r ~= "{parse complex at '";
+            r ~= c;
+            r ~= "':\"" ~ tmpl ~ "\"}";
+        }
+
+        // NOTE: We haven't updated c and tmpl yet.
+
+        {
+            // arg will contain the index of the argument the user wanted
+            // substituted.
+            size_t arg = size_t.max;
+            // fmt will contain any additional formatting options.
+            string fmt = "";
+
+            // If we didn't get a : or }, that means we expect an index.
+            if( !( tmpl[0] == ':' || tmpl[0] == '}' ) )
+            {
+                // So parse it.
+                auto used = Integer.parse_ctfe!(size_t)(tmpl, true);
+                
+                if( used == 0 )
+                {
+                    debug(gb_Format_verbose) r ~= "{used zero of \""~tmpl~"\"}";
+                    r ~= "{invalid argument index}";
+                    break;
+                }
+                
+                arg = Integer.parse_ctfe!(size_t)(tmpl);
+                tmpl = tmpl[used..$];
+                
+                if( tmpl.length == 0 )
+                {
+                    r ~= "{unterminated substitution}";
+                    break;
+                }
+            }
+            else
+            {
+                // Otherwise, the index was elided, which means we want to use
+                // the index of the "next" argument.
+                arg = argPos;
+                ++ argPos;
+            }
+
+            c = tmpl[0];
+            tmpl = tmpl[1..$];
+
+            debug(gb_Format_verbose)
+                r ~= "{index " ~ Integer.format_ctfe(arg) ~ "}";
+
+            // If c is :, then we've got formatting options to parse
+
+            if( c == ':' )
+            {
+                debug(gb_Format_verbose) r ~= "{fmt string}";
+
+                // Look for the closing }.
+                size_t len = 0;
+                foreach( i,d ; tmpl )
+                {
+                    if( d == '}' )
+                    {
+                        len = i;
+                        break;
+                    }
+                }
+                if( len == 0 )
+                {
+                    r ~= "{malformed format}";
+                    break;
+                }
+                fmt = tmpl[0..len];
+                tmpl = tmpl[len..$];
+
+                if( tmpl.length == 0 )
+                {
+                    r ~= "{unterminated substitution}";
+                    break;
+                }
+
+                c = tmpl[0];
+                tmpl = tmpl[1..$];
+            }
+
+            // At this point, we should have the closing }.  If not, someone's
+            // screwed up.
+            if( c != '}' )
+            {
+                debug(gb_Format_verbose)
+                {
+                    r ~= "{expected closing; got '";
+                    r ~= c;
+                    r ~= "':\"" ~ tmpl ~ "\"}";
+                }
+                r ~= "{malformed substitution}";
+                break;
+            }
+
+            // Stringify that bugger.
+            r ~= stringify(arg, 0, fmt, args);
+
+            // When we fall off the end here, we'll continue with the
+            // remainder of tmpl, unless it's empty in which case we're
+            // finished.
+        }
+    }
+    
+    return r;
+}
+
+version( Unittest )
+{
+    static assert(format_ctfe("A: $$", "foo"[]) == "A: $");
+    static assert(format_ctfe("B: a $$ c", "b"[]) == "B: a $ c");
+    
+    static assert(format_ctfe("C: ${}", "foo"[]) == "C: foo");
+    static assert(format_ctfe("D: a ${} c", "b"[]) == "D: a b c");
+    
+    static assert(format_ctfe("E: $0", "foo"[]) == "E: foo");
+    static assert(format_ctfe("F: a $0 c", "b"[]) == "F: a b c");
+    
+    static assert(format_ctfe("G: $*", "foo"[]) == "G: foo");
+    static assert(format_ctfe("H: a $* c", "b"[]) == "H: a b c");
+    
+    static assert(format_ctfe("I: ${0}", "foo"[]) == "I: foo");
+    static assert(format_ctfe("J: a ${0} c", "b"[]) == "J: a b c");
+
+    static assert(format_ctfe("K: ${} ${} ${}", 1, -2, "c"[]) == "K: 1 -2 c");
+    static assert(format_ctfe("L: $* $* $*", 1, -2, "c"[]) == "L: 1 -2 c");
+    static assert(format_ctfe("M: $0 $1 $2", 1, -2, "c"[]) == "M: 1 -2 c");
+    static assert(format_ctfe("N: ${0} ${1} ${2}", 1, -2, "c"[]) == "N: 1 -2 c");
+
+    static assert(format_ctfe("O: ${2} ${0} ${1}", 1, -2, "c"[]) == "O: c 1 -2");
+
+    static assert(format_ctfe("P: ${:x} ${0:x} ${0:o} ${0:b}", 42) == "P: 2a 2a 52 101010");
+
+    static assert(format_ctfe("Q: ${0} ${0:q} ${0:x}", "abc"[]) == "Q: abc \"abc\" 616263");
+    static assert(format_ctfe("R: ${0} ${0:q}", ["a","b","c"][]) == "R: [a, b, c] [\"a\", \"b\", \"c\"]");
+
+    const TORTURE_TMPL = `
+        struct $*Enum
+        {
+            const Name = ${0:q};
+            const string[${:l}] Members = ${1:q};
+
+            ${2} value()
+            {
+                return ${3:xx};
+            }
+        }
+    `[];
+
+    const TORTURE_EXPECTED = `
+        struct FooEnum
+        {
+            const Name = "Foo";
+            const string[3] Members = ["bar", "quxx", "zyzzy"];
+
+            int value()
+            {
+                return 0x42;
+            }
+        }
+    `[];
+
+    const TORTURE_ACTUAL = format_ctfe(TORTURE_TMPL,
+            "Foo"[], ["bar"[],"quxx","zyzzy"][],
+            "int"[], 0x42);
+
+    static assert( TORTURE_EXPECTED == TORTURE_ACTUAL );
+}
+
+private
+{
+    size_t findIndexByName(Args...)(string name, Args args)
+    {
+        foreach( i ; Tuple.Sequence!(0, Args.length, 2) )
+        {
+            static if( !is( Args[i] : string ) )
+            {
+                static assert(false, "expected string for argument "
+                        ~ Integer.format_ctfe(i) ~ " in " ~ Args.stringof
+                        ~ " not " ~ Args[i].stringof);
+            }
+            if( name == args[i][] )
+                return i+1;
+        }
+        return size_t.max;
+    }
+
+    version( Unittest )
+    {
+        static assert( findIndexByName("a", "a", 0, "b", 1) == 1 );
+        static assert( findIndexByName("b", "a", 0, "b", 1) == 3 );
+        static assert( findIndexByName("c", "a", 0, "b", 1) == size_t.max );
+    }
+}
+
+/// ditto
+
+string formatNamed_ctfe(Args...)(string tmpl, Args args)
+{
+    string r = "";
+    int argPos = 0;
+    
+    while( tmpl.length > 0 )
+    {
+        bool inExp = false;
+       
+        // Look for a $
+        foreach( i,c ; tmpl )
+        {
+            if (c == '$')
+            {
+                inExp = true;
+                r ~= tmpl[0..i];
+                tmpl = tmpl[i+1..$];
+                break;
+            }
+        }
+
+        // If we didn't find a $, it's because we hit the end of the template.
+        if( !inExp )
+        {
+            r ~= tmpl;
+            break;
+        }
+        
+        // So we're in an expansion/substitution.
+
+        debug(gb_Format_verbose) r ~= "{in exp}";
+
+        if( tmpl.length == 0 )
+        {
+            r ~= "{unterminated substitution}";
+            break;
+        }
+
+        // c is the next character, whilst tmpl is everything left in the
+        // template string.
+        char c = tmpl[0];
+        tmpl = tmpl[1..$];
+        
+        // $$ - escaped $.
+        if( c == '$' )
+        {
+            debug(gb_Format_verbose) r ~= "{escaped $}";
+            r ~= '$';
+            continue;
+        }
+
+        // $a... - shortcut for $a...
+        if( String.isIdentStartChar_ctfe(c) )
+        {
+            debug(gb_Format_verbose) r ~= "{shorthand name}";
+            size_t i = 0;
+            while( i < tmpl.length )
+            {
+                if( !String.isIdentChar_ctfe(tmpl[i]) )
+                    break;
+                ++ i;
+            }
+            string name = c ~ tmpl[0..i];
+            tmpl = tmpl[i..$];
+            r ~= stringify(findIndexByName(name, args), 0, "", args);
+            continue;
+        }
+
+        // This means we got a $ followed by something unexpected.
+        if( c != '{' )
+        {
+            r ~= "{malformed substitution}";
+            break;
+        }
+        
+        if( tmpl.length == 0 )
+        {
+            r ~= "{unterminated substitution}";
+            break;
+        }
+        
+        debug(gb_Format_verbose)
+        {
+            r ~= "{parse complex at '";
+            r ~= c;
+            r ~= "':\"" ~ tmpl ~ "\"}";
+        }
+
+        // NOTE: We haven't updated c and tmpl yet.
+
+        {
+            // arg will contain the index of the argument the user wanted
+            // substituted.
+            size_t arg = size_t.max;
+            // fmt will contain any additional formatting options.
+            string fmt = "";
+
+            // If we didn't get a : or }, that means we expect a name.
+            if( !( tmpl[0] == ':' || tmpl[0] == '}' ) )
+            {
+                // So parse it.
+                size_t i = 0;
+                while( i < tmpl.length )
+                {
+                    if( !String.isIdentChar_ctfe(tmpl[i]) )
+                        break;
+                    ++ i;
+                }
+                string name = tmpl[0..i];
+                tmpl = tmpl[i..$];
+
+                arg = findIndexByName(name, args);
+                
+                if( tmpl.length == 0 )
+                {
+                    r ~= "{unterminated substitution}";
+                    break;
+                }
+            }
+            else
+            {
+                // Otherwise, the name was elided.  Kaboom!
+                r ~= "{substitution missing name}";
+                break;
+            }
+
+            c = tmpl[0];
+            tmpl = tmpl[1..$];
+
+            debug(gb_Format_verbose)
+                r ~= "{index " ~ Integer.format_ctfe(arg) ~ "}";
+
+            // If c is :, then we've got formatting options to parse
+
+            if( c == ':' )
+            {
+                debug(gb_Format_verbose) r ~= "{fmt string}";
+
+                // Look for the closing }.
+                size_t len = 0;
+                foreach( i,d ; tmpl )
+                {
+                    if( d == '}' )
+                    {
+                        len = i;
+                        break;
+                    }
+                }
+                if( len == 0 )
+                {
+                    r ~= "{malformed format}";
+                    break;
+                }
+                fmt = tmpl[0..len];
+                tmpl = tmpl[len..$];
+
+                debug(gb_Format_verbose) r ~= "{fmt:"~fmt~"}";
+
+                if( tmpl.length == 0 )
+                {
+                    r ~= "{unterminated substitution}";
+                    break;
+                }
+
+                c = tmpl[0];
+                tmpl = tmpl[1..$];
+            }
+
+            // At this point, we should have the closing }.  If not, someone's
+            // screwed up.
+            if( c != '}' )
+            {
+                debug(gb_Format_verbose)
+                {
+                    r ~= "{expected closing; got '";
+                    r ~= c;
+                    r ~= "':\"" ~ tmpl ~ "\"}";
+                }
+                r ~= "{malformed substitution}";
+                break;
+            }
+
+            // Stringify that bugger.
+            r ~= stringify(arg, 0, fmt, args);
+
+            // When we fall off the end here, we'll continue with the
+            // remainder of tmpl, unless it's empty in which case we're
+            // finished.
+        }
+    }
+    
+    return r;
+}
+
+version( Unittest )
+{
+    static assert( formatNamed_ctfe("A: $$", "a"[], 0, "b"[], 1) == "A: $" );
+    static assert( formatNamed_ctfe("B: $a", "a"[], 0, "b"[], 1) == "B: 0" );
+    static assert( formatNamed_ctfe("C: $b", "a"[], 0, "b"[], 1) == "C: 1" );
+
+    static assert( formatNamed_ctfe("D: ${a}", "a"[], 0, "b"[], 1) == "D: 0" );
+    static assert( formatNamed_ctfe("E: ${b}", "a"[], 0, "b"[], 1) == "E: 1" );
+    
+    static assert( formatNamed_ctfe("F: $foo$bar", "foo"[], 0, "bar"[], 1) == "F: 01" );
+    static assert( formatNamed_ctfe("G: ${foo}${bar}", "foo"[], 0, "bar"[], 1) == "G: 01" );
+
+    static assert( formatNamed_ctfe("H: ${foo:x}${bar:xx}", "foo"[], 0, "bar"[], 1) == "H: 00x1" );
+
+    const TORTURE_NAMED_TMPL = `
+        struct ${name}Enum
+        {
+            const Name = ${name:q};
+            const string[${members:l}] Members = ${members:q};
+
+            ${retType} value()
+            {
+                return ${value:xx};
+            }
+        }
+    `[];
+
+    const TORTURE_NAMED_EXPECTED = `
+        struct FooEnum
+        {
+            const Name = "Foo";
+            const string[3] Members = ["bar", "quxx", "zyzzy"];
+
+            int value()
+            {
+                return 0x42;
+            }
+        }
+    `[];
+
+    const TORTURE_NAMED_ACTUAL = formatNamed_ctfe(TORTURE_NAMED_TMPL,
+            "name"[], "Foo"[],
+            "members"[], ["bar"[],"quxx","zyzzy"][],
+            "retType"[], "int"[],
+            "value"[], 0x42);
+
+    static assert( TORTURE_NAMED_EXPECTED == TORTURE_NAMED_ACTUAL );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/ctfe/Integer.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,169 @@
+/**
+ * CTFE Integer routines.
+ * 
+ * Authors: Daniel Keep <daniel.keep@gmail.com>
+ * Copyright: See LICENSE.
+ */
+module qt.qtd.ctfe.Integer;
+
+/**
+ * Formats an integer as a string.  You can optionally specify a different
+ * base; any value between 2 and 16 inclusive is supported.
+ * 
+ * Params:
+ *     v = value to format.
+ *     base = base to use; defaults to 10.
+ * Returns:
+ *      integer formatted as a string.
+ */
+
+string format_ctfe(intT)(intT v, int base = 10)
+{
+    static if( !is( intT == ulong ) ) 
+    {
+        return (v < 0)
+            ? "-" ~ format_ctfe(cast(ulong) -v, base)
+            : format_ctfe(cast(ulong) v, base);
+    }
+    else
+    {
+        assert( 2 <= base && base <= 16,
+                "base must be between 2 and 16; got " ~ format_ctfe(base, 10) );
+        
+        string r = "";
+        do
+        {
+            r = INT_CHARS[cast(size_t)(v % base)] ~ r;
+            v /= base;
+        }
+        while( v > 0 );
+        return r;
+    }
+}
+
+/**
+ * Parses an integer value from a string.  You can optionally specify a
+ * different base; any value between 2 and 16 inclusive is supported.
+ * 
+ * Note that this does not fail if it cannot consume the entire string;
+ * use returnUsed to determine the number of characters consumed.
+ * 
+ * Params:
+ *     str = string to parse.
+ *     returnUsed = defaults to false; if set to true, returns the number of
+ *                  characters consumed from the string instead of the
+ *                  parsed value.
+ *     base = base to use; defaults to 10.
+ * Returns:
+ *      either the parsed integer or the number of characters consumed,
+ *      depending on the value of returnUsed.
+ */
+
+intT parse_ctfe(intT)(string str, bool returnUsed = false, int base = 10)
+{
+    auto origStr = str;
+    
+    assert( 2 <= base && base <= 16,
+        "base must be between 2 and 16; got " ~ format_ctfe(base, 10) );
+
+    bool neg = false;
+    if( str.length > 0 && str[0] == '-' )
+    {
+        neg = true;
+        str = str[1..$];
+    }
+    
+    if( intT.min == 0 && neg )
+        assert(false, "underwhile while parsing \"" ~ origStr
+                ~ "\" as a " ~ intT.stringof ~ ": cannot represent negative "
+                ~ "values");
+    
+    intT r = 0;
+    size_t used = 0;
+    
+    foreach( c ; str )
+    {
+        int cv = -1;
+        
+        if( '0' <= c && c <= '9' )
+            cv = c - '0';
+        
+        else if( 'A' <= c && c <= 'Z' )
+            cv = 10 + c - 'A';
+        
+        else if( 'a' <= c && c <= 'z' )
+            cv = 10 + c - 'a';
+        
+        if( cv >= base || cv < 0 )
+            break;
+        
+        auto oldR = r;
+        r = r*base + cast(intT) cv;
+        ++ used;
+        
+        if( r < oldR )
+            assert(false, "overflow while parsing \"" ~ origStr
+                    ~ "\" as a " ~ intT.stringof);
+    }
+    
+    if( neg )
+    {
+        r = -r;
+        ++used;
+    }
+    
+    if( returnUsed )
+    {
+        assert( used < intT.max, "overflow attempting to return "
+                ~ "number of characters consumed in a " ~ intT.stringof );
+        
+        return used;
+    }
+    else
+        return r;
+}
+
+/**
+ * Like parse_ctfe, except it will raise an error if the provided string
+ * cannot be parsed in its entirety.
+ * 
+ * Params:
+ *     str = the string to parse.
+ *     base = base to use; defaults to 10.
+ * Returns:
+ *      the parsed integer.
+ */
+
+intT parseAll_ctfe(intT)(string str, int base = 10)
+{
+    auto used = parse_ctfe!(intT)(str, true, base);
+    assert( used == str.length, "could not parse entire string \"" ~ str
+            ~ "\"" );
+    return parse_ctfe!(int)(str, false, base);
+}
+
+private
+{
+    const INT_CHARS = "0123456789abcdef";
+}
+
+version( Unittest )
+{
+    static assert( format_ctfe(0) == "0", "got: " ~ format_ctfe(0) );
+    static assert( format_ctfe(1) == "1" );
+    static assert( format_ctfe(-1) == "-1" );
+    static assert( format_ctfe(42) == "42" );
+    static assert( format_ctfe(0xf00, 16) == "f00" );
+    static assert( format_ctfe(0123, 8) == "123" );
+    
+    static assert( parse_ctfe!(long)("0") == 0 );
+    static assert( parse_ctfe!(long)("1") == 1 );
+    static assert( parse_ctfe!(long)("-1") == -1 );
+    static assert( parse_ctfe!(long)("42") == 42 );
+    static assert( parse_ctfe!(long)("f00", false, 16) == 0xf00 );
+    static assert( parse_ctfe!(long)("123", false, 8) == 0123 );
+    static assert( parse_ctfe!(long)("123ax", true) == 3 );
+    static assert( parse_ctfe!(long)("123ax", true, 16) == 4 );
+    
+    static assert( parseAll_ctfe!(long)("123") == 123 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/ctfe/String.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,317 @@
+/**
+ * CTFE String routines.
+ * 
+ * Authors: Daniel Keep <daniel.keep@gmail.com>
+ * Copyright: See LICENSE.
+ */
+module qt.qtd.ctfe.String;
+
+import Integer = qt.qtd.ctfe.Integer;
+
+private
+{
+    const HEX_CHARS = "0123456789abcdef";
+}
+
+/**
+ * Escapes a string into an equivalent string literal.
+ * 
+ * Params:
+ *     str = string to escape.
+ *     aggressive = if set, the function will escape all non-printing
+ *                  characters, non-space whitespace and newlines.  Defaults
+ *                  to true.
+ * Returns:
+ *      Escaped string literal.
+ */
+string escape_ctfe(string str, bool aggressive=true)
+{
+    string head = "";
+    
+    foreach( i,c ; str )
+    {
+        if( c == '"' || c == '\\' || c == '\0' )
+        {
+            head = "\""~str[0..i];
+            str = str[i..$];
+            break;
+        }
+        
+        if( aggressive )
+        {
+            if( c < 0x20 || c == 0x7f )
+            {
+                head = "\""~str[0..i];
+                str = str[i..$];
+                break;
+            }
+        }
+    }
+    
+    if( head.length == 0 )
+        return "\"" ~ str ~ "\"";
+    
+    string tail = "";
+    
+    foreach( c ; str )
+    {
+        if( c == '"' )
+            tail ~= `\"`;
+        
+        else if( c == '\\' )
+            tail ~= "\\\\";
+        
+        else if( c == '\0' )
+            tail ~= `\0`;
+        
+        else if( aggressive )
+        {
+            switch( c )
+            {                    
+                case '\?':
+                    tail ~= `\?`;
+                    break;
+                    
+                case '\a':
+                    tail ~= `\a`;
+                    break;
+                    
+                case '\b':
+                    tail ~= `\b`;
+                    break;
+                    
+                case '\f':
+                    tail ~= `\f`;
+                    break;
+                    
+                case '\n':
+                    tail ~= `\n`;
+                    break;
+                    
+                case '\r':
+                    tail ~= `\r`;
+                    break;
+                    
+                case '\t':
+                    tail ~= `\t`;
+                    break;
+                    
+                case '\v':
+                    tail ~= `\v`;
+                    break;
+
+                default:
+                    if( c < 0x20 || c == 0x75 )
+                    {
+                        tail ~= `\x`;
+                        tail ~= HEX_CHARS[c/0xf];
+                        tail ~= HEX_CHARS[c&0xf];
+                    }
+                    else
+                        tail ~= c;
+            }
+        }
+        else
+            tail ~= c;
+    }
+    
+    return head ~ tail ~ "\"";
+}
+
+version( Unittest )
+{
+    static assert( escape_ctfe("abc") == "\"abc\"" );
+    static assert( escape_ctfe("a\"c") == "\"a\\\"c\"" );
+}
+
+/**
+ * Turns an array of bytes into a hexadecimal string.
+ * 
+ * Params:
+ *     arr = array to hexify.
+ *     grouping = if non-zero, specifies after how many bytes to insert a
+ *                space.
+ * Returns:
+ *      String of hex bytes.
+ */
+
+string hexify_ctfe(ubyte[] arr, int grouping = 0)
+{
+    string r = "";
+    int bytes = grouping;
+    foreach( b ; arr )
+    {
+        if( bytes == 0 && grouping > 0 )
+        {
+            r ~= ' ';
+            bytes = grouping;
+        }
+
+        auto bh = b/16;
+        auto bl = b&15;
+        
+        assert( bh < 16 );
+        assert( bl < 16 );
+        
+        r ~= HEX_CHARS[bh];
+        r ~= HEX_CHARS[bl];
+        
+        if( grouping > 0 )
+            -- bytes;
+    }
+    return r;
+}
+
+/// ditto
+
+string hexify_ctfe(string arr, int grouping = 0)
+{
+    string r = "";
+    int bytes = grouping;
+    foreach( b ; arr )
+    {
+        if( bytes == 0 && grouping > 0 )
+        {
+            r ~= ' ';
+            bytes = grouping;
+        }
+
+        auto bh = b/16;
+        auto bl = b&15;
+        
+        assert( bh < 16 );
+        assert( bl < 16 );
+        
+        r ~= HEX_CHARS[bh];
+        r ~= HEX_CHARS[bl];
+        
+        if( grouping > 0 )
+            -- bytes;
+    }
+    return r;
+}
+
+version( Unittest )
+{
+    static const ubyte[] DATA_1 = [0x00,0x01,0x02,0x03];
+    static const ubyte[] DATA_2 = [0x0f,0x10,0xef,0xf0];
+
+    static assert( hexify_ctfe(DATA_1) == "00010203" );
+    static assert( hexify_ctfe(DATA_2) == "0f10eff0" );
+    
+    static assert( hexify_ctfe(DATA_1, 1) == "00 01 02 03" );
+    static assert( hexify_ctfe(DATA_2, 1) == "0f 10 ef f0" );
+    
+    static assert( hexify_ctfe(DATA_1, 2) == "0001 0203" );
+    static assert( hexify_ctfe(DATA_2, 2) == "0f10 eff0" );
+    
+    static assert( hexify_ctfe(DATA_1, 4) == "00010203" );
+    static assert( hexify_ctfe(DATA_2, 4) == "0f10eff0" );
+}
+
+/**
+ * Pads a string.  padl adds padding to the left, padr adds it to the right.
+ * Params:
+ *     str = string to pad.
+ *     len = length to pad to.
+ *     padding = character to use for padding.  Defaults to space.
+ * Returns:
+ *      padded string.
+ */
+
+string padl_ctfe(string str, int len, char padding = ' ')
+{
+    while( str.length < len )
+        str = padding ~ str;
+    return str;
+}
+
+/// ditto
+
+string padr_ctfe(string str, int len, char padding = ' ')
+{
+    while( str.length < len )
+        str ~= padding;
+    return str;
+}
+
+version( Unittest )
+{
+    static assert( padl_ctfe("abc", 2) == "abc" );
+    static assert( padl_ctfe("abc", 3) == "abc" );
+    static assert( padl_ctfe("abc", 4) == " abc" );
+    static assert( padl_ctfe("abc", 4, 'x') == "xabc" );
+
+    static assert( padr_ctfe("abc", 2) == "abc" );
+    static assert( padr_ctfe("abc", 3) == "abc" );
+    static assert( padr_ctfe("abc", 4) == "abc " );
+    static assert( padr_ctfe("abc", 4, 'x') == "abcx" );
+}
+
+/**
+ * Returns the tail of a string after a given splitting character.  The Rev
+ * variant returns the tail after the last instance of the splitting
+ * character.
+ */
+
+string tail_ctfe(string str, char split)
+{
+    foreach( i,c ; str )
+    {
+        if( c == split )
+            return str[i+1..$];
+    }
+    return str;
+}
+
+/// ditto
+
+string tailRev_ctfe(string str, char split)
+{
+    foreach_reverse( i,c ; str )
+    {
+        if( c == split )
+            return str[i+1..$];
+    }
+    return str;
+}
+
+/**
+ * Determines whether a character is valid in an identifier in a
+ * non-initial position.
+ *
+ * Does not support the full range of valid D identifier characters.
+ */
+
+bool isIdentChar_ctfe(char c)
+{
+    return ('a' <= c && c <= 'z')
+        || ('A' <= c && c <= 'Z')
+        || ('0' <= c && c <= '9')
+        || (c == '_');
+}
+
+/**
+ * Determines whether a character is valid in an identifier in an
+ * initial position.
+ *
+ * Does not support the full range of valid D identifier characters.
+ */
+
+bool isIdentStartChar_ctfe(char c)
+{
+    return ('a' <= c && c <= 'z')
+        || ('A' <= c && c <= 'Z')
+        || (c == '_');
+}
+
+/**
+ * Returns a line spec suitable for mixing in.  This can be used with string
+ * mixins to ensure compile errors appear on the "correct" line in the source.
+ */
+
+string linespec_ctfe(string file, long line)
+{
+    return "#line "~Integer.format_ctfe(line)~" \"" ~ file ~ "\"\n";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qt/qtd/util/Tuple.d	Sun Nov 08 19:28:01 2009 +0000
@@ -0,0 +1,64 @@
+/**
+ * Tuple-related stuff.
+ * 
+ * Authors: Daniel Keep <daniel.keep@gmail.com>
+ * Copyright: See LICENSE.
+ */
+module qt.qtd.util.Tuple;
+
+import std.typetuple;
+
+/**
+ * Sequence can be used to generate a tuple of integer values.  It can be
+ * used in one of three forms:
+ *
+ * -----
+ *  Sequence!(6)     // ==> (0, 1, 2, 3, 4, 5)
+ *  Sequence!(1,6)   // ==> (1, 2, 3, 4, 5)
+ *  Sequence!(1,6,2) // ==> (1, 3, 5)
+ * -----
+ */
+
+template Sequence(int max)
+{
+    static if( max <= 0 )
+        alias TypeTuple!() Sequence;
+    else
+        alias TypeTuple!(Sequence!(max-1), max-1) Sequence;
+}
+
+/// ditto
+
+template Sequence(int min, int max)
+{
+    static if( max <= min )
+        alias TypeTuple!() Sequence;
+    else
+        alias TypeTuple!(Sequence!(min, max-1), max-1) Sequence;
+}
+
+/// ditto
+
+template Sequence(int min, int max, int stride)
+{
+    static if( min >= max )
+        alias TypeTuple!() Sequence;
+    else
+        alias TypeTuple!(min, Sequence!(min+stride, max, stride)) Sequence;
+}
+
+version( Unittest )
+{
+    static assert( Sequence!(3)[0] == 0 );
+    static assert( Sequence!(3)[1] == 1 );
+    static assert( Sequence!(3)[2] == 2 );
+    static assert( Sequence!(3).length == 3 );
+
+    static assert( Sequence!(1, 3)[0] == 1 );
+    static assert( Sequence!(1, 3)[1] == 2 );
+    static assert( Sequence!(1, 3).length == 2 );
+
+    static assert( Sequence!(1, 5, 2)[0] == 1 );
+    static assert( Sequence!(1, 5, 2)[1] == 3 );
+    static assert( Sequence!(1, 5, 2).length == 2 );
+}