1 /************************************************************************
2  *
3  * Copyright 2010-2011 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 "Common.h"
25 
26 #include <QObject>
27 #include <QString>
28 #include <QVariant>
29 #include <QVector>
30 #include <QEvent>
31 
32 #include <PyrObject.h>
33 #include <PyrSlot.h>
34 #include <PyrSymbol.h>
35 
36 #define qcProxyDebugMsg(LEVEL, MSG) qcDebugMsg(LEVEL, QStringLiteral("[%1]: ").arg(_scClassName) + QString(MSG))
37 
38 class QObjectProxy;
39 class QcSignalSpy;
40 class QcMethodSignalHandler;
41 class QcFunctionSignalHandler;
42 
43 namespace QtCollider {
44 struct SetPropertyEvent;
45 class DestroyEvent;
46 struct ScMethodCallEvent;
47 
48 class ProxyToken : public QObject {
49     Q_OBJECT
50 public:
ProxyToken(QObjectProxy * p,QObject * parent)51     ProxyToken(QObjectProxy* p, QObject* parent): QObject(parent), proxy(p) {}
52     QObjectProxy* proxy;
53 };
54 }
55 
56 class QObjectProxy : public QObject {
57     friend class QcMethodSignalHandler;
58     friend class QcFunctionSignalHandler;
59 
60     Q_OBJECT
61 
62 public:
63     enum DestroyAction {
64         DestroyProxy,
65         DestroyObject,
66         DestroyProxyAndObject,
67     };
68 
69     struct EventHandlerData {
EventHandlerDataEventHandlerData70         EventHandlerData(): type(QEvent::None) {}
71         int type;
72         PyrSymbol* method;
73         QtCollider::Synchronicity sync;
74         bool enabled;
75     };
76 
77     QObjectProxy(QObject* qObject, PyrObject* scObject);
78 
79     virtual ~QObjectProxy();
80 
81     // Check if this is the right thread.
82     // WARNING: must be called with language locked!
83     bool compareThread();
84 
85     // WARNING: must be called with language locked!
finalize()86     void finalize() { _scObject = 0; }
87 
object()88     inline QObject* object() const { return qObject; }
scObject()89     inline PyrObject* scObject() const { return _scObject; }
90 
91     // Lock for usage of object() outside Qt thread.
lock()92     inline void lock() { mutex.lock(); }
unlock()93     inline void unlock() { mutex.unlock(); }
94 
scClassName()95     QString scClassName() const { return _scClassName; }
96 
97     QList<PyrObject*> children(PyrSymbol* className);
98     PyrObject* parent(PyrSymbol* className);
99     virtual bool setParent(QObjectProxy* parent);
100 
101     bool setProperty(const char* property, const QVariant& val);
102     QVariant property(const char* property);
103 
104     bool connectObject(const char* signal, PyrObject* object, Qt::ConnectionType);
105     bool connectMethod(const char* signal, PyrSymbol* method, Qt::ConnectionType);
106     bool disconnectObject(const char* signal, PyrObject* object);
107     bool disconnectMethod(const char* signal, PyrSymbol* method);
108     bool setEventHandler(int eventType, PyrSymbol* method, QtCollider::Synchronicity, bool enabled = true);
109     bool setEventHandlerEnabled(int eventType, bool enabled);
110 
111     // thread-safe if connection == queued
112     bool invokeMethod(const char* method, PyrSlot* ret, PyrSlot* arg, Qt::ConnectionType);
113 
114     void destroy(DestroyAction);
115 
116     static QObjectProxy* fromObject(QObject*);
117 
118 protected:
119     void invokeScMethod(PyrSymbol* method, const QList<QVariant>& args = QList<QVariant>(), PyrSlot* result = 0,
120                         bool locked = false);
121 
122     virtual bool eventFilter(QObject* watched, QEvent* event);
123 
124     virtual void customEvent(QEvent*);
125 
126     virtual bool preProcessEvent(QObject*, QEvent*, EventHandlerData&, QList<QVariant>& args);
127 
postProcessEvent(QObject *,QEvent *,bool handled)128     virtual bool postProcessEvent(QObject*, QEvent*, bool handled) { return handled; }
129 
130     bool invokeEventHandler(QEvent* e, EventHandlerData&, QList<QVariant>& args);
131 
eventHandlers()132     const QVector<EventHandlerData>& eventHandlers() { return _eventHandlers; }
133 
134 private Q_SLOTS:
135 
136     void invalidate();
137 
138 private:
139     void scMethodCallEvent(QtCollider::ScMethodCallEvent*);
140     bool setPropertyEvent(QtCollider::SetPropertyEvent*);
141     bool destroyEvent(QtCollider::DestroyEvent*);
142 
143     QObject* qObject;
144     // NOTE: scObject is protected by the language lock. Should not use it without it!
145     PyrObject* _scObject;
146     // NOTE: for the reason above we extract SC class name at construction
147     QString _scClassName;
148 
149     QVector<EventHandlerData> _eventHandlers;
150     QList<QcMethodSignalHandler*> methodSigHandlers;
151     QList<QcFunctionSignalHandler*> funcSigHandlers;
152     QMutex mutex;
153 };
154 
155 namespace QtCollider {
156 
157 struct SetPropertyEvent : public QEvent {
SetPropertyEventSetPropertyEvent158     SetPropertyEvent(): QEvent((QEvent::Type)QtCollider::Event_Proxy_SetProperty) {}
159     PyrSymbol* property;
160     QVariant value;
161 };
162 
163 class DestroyEvent : public QEvent {
164 public:
DestroyEvent(QObjectProxy::DestroyAction act)165     DestroyEvent(QObjectProxy::DestroyAction act):
166         QEvent((QEvent::Type)QtCollider::Event_Proxy_Destroy),
167         _action(act) {}
action()168     QObjectProxy::DestroyAction action() { return _action; }
169 
170 private:
171     QObjectProxy::DestroyAction _action;
172 };
173 
174 struct ScMethodCallEvent : public QEvent {
175     ScMethodCallEvent(PyrSymbol* m, const QList<QVariant>& l = QList<QVariant>(), bool b_locked = false):
176         QEvent((QEvent::Type)QtCollider::Event_ScMethodCall),
177         method(m),
178         args(l),
179         locked(b_locked) {}
180 
181     PyrSymbol* method;
182     QList<QVariant> args;
183     bool locked;
184 };
185 
186 } // namespace
187 
188 Q_DECLARE_METATYPE(QObjectProxy*);
189