1 /************************************************************************
2  *
3  * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com)
4  *
5  * This file is part of SuperCollider Qt GUI.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  ************************************************************************/
21 
22 #pragma once
23 
24 #include "QObjectProxy.h"
25 #include "Common.h"
26 #include "metatype.hpp"
27 
28 #include <PyrObject.h>
29 
30 #include <QMetaObject>
31 #include <QObject>
32 #include <QWidget>
33 #include <QHash>
34 
35 class QcAbstractFactory;
36 
37 typedef QHash<QString, QcAbstractFactory*> QcFactoryHash;
38 
39 namespace QtCollider {
40 QcFactoryHash& factories();
41 }
42 
43 class QcAbstractFactory {
44 public:
45     virtual const QMetaObject* metaObject() = 0;
46     virtual QObjectProxy* newInstance(PyrObject*, QtCollider::MetaValue arg[10]) = 0;
47 };
48 
qcNoConstructorMsg(const QMetaObject * metaObject,int argc,QtCollider::MetaValue * argv)49 static void qcNoConstructorMsg(const QMetaObject* metaObject, int argc, QtCollider::MetaValue* argv) {
50     QString str = QStringLiteral("No appropriate constructor found for %1 (").arg(metaObject->className());
51 
52     for (int i = 0; i < argc; ++i) {
53         MetaType* type = argv[i].type();
54         if (type) {
55             if (i > 0)
56                 str += ", ";
57             str += QMetaType::typeName(type->id());
58         } else
59             break;
60     }
61 
62     str += ")";
63 
64     qcErrorMsg(str);
65 }
66 
67 template <class QOBJECT> class QcObjectFactory : public QcAbstractFactory {
68 public:
metaObject()69     const QMetaObject* metaObject() { return &QOBJECT::staticMetaObject; }
70 
newInstance(PyrObject * scObject,QtCollider::MetaValue arg[10])71     virtual QObjectProxy* newInstance(PyrObject* scObject, QtCollider::MetaValue arg[10]) {
72         QOBJECT* qObject;
73 
74         if (!arg[0].type()) {
75             qObject = new QOBJECT;
76         } else {
77             QObject* obj = QOBJECT::staticMetaObject.newInstance(
78                 arg[0].toGenericArgument(), arg[1].toGenericArgument(), arg[2].toGenericArgument(),
79                 arg[3].toGenericArgument(), arg[4].toGenericArgument(), arg[5].toGenericArgument(),
80                 arg[6].toGenericArgument(), arg[7].toGenericArgument(), arg[8].toGenericArgument(),
81                 arg[9].toGenericArgument());
82 
83             qObject = qobject_cast<QOBJECT*>(obj);
84             if (!qObject) {
85                 qcNoConstructorMsg(metaObject(), 10, arg);
86                 return 0;
87             }
88         }
89 
90         return proxy(qObject, scObject);
91     }
92 
93 protected:
proxy(QOBJECT * obj,PyrObject * sc_obj)94     virtual QObjectProxy* proxy(QOBJECT* obj, PyrObject* sc_obj) {
95         QObjectProxy* prox(new QObjectProxy(obj, sc_obj));
96         initialize(prox, obj);
97         return prox;
98     }
99 
initialize(QObjectProxy * proxy,QOBJECT * obj)100     virtual void initialize(QObjectProxy* proxy, QOBJECT* obj) {};
101 };
102 
103 #define QC_DECLARE_FACTORY(QOBJECT, FACTORY)                                                                           \
104     void add_factory_##QOBJECT() {                                                                                     \
105         QcAbstractFactory* factory = new FACTORY;                                                                      \
106         factories().insert(factory->metaObject()->className(), factory);                                               \
107     }
108 
109 #define QC_DECLARE_QOBJECT_FACTORY(QOBJECT) QC_DECLARE_FACTORY(QOBJECT, QcObjectFactory<QOBJECT>)
110 
111 #define QC_ADD_FACTORY(QOBJECT)                                                                                        \
112     void add_factory_##QOBJECT();                                                                                      \
113     add_factory_##QOBJECT()
114