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