We now have a current svn snapshot of libqxt in our contrib dir, and
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / core / qxtboundfunction.h
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtCore module of the Qt eXTension library
6 **
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
9 ** IBM.
10 **
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
15 **
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24
25 #ifndef QXTBOUNDFUNCTION_H
26 #define QXTBOUNDFUNCTION_H
27
28 #include <QObject>
29 #include <QMetaObject>
30 #include <QGenericArgument>
31 #include <qxtmetaobject.h>
32 #include <qxtnull.h>
33 #include <QThread>
34 #include <QtDebug>
35
36 /**
37  * \class QxtBoundFunction
38  * \ingroup QxtCore
39  * \brief Binds parameters to a function call
40  *
41  * A bound function is very similar to what the C++ FAQ Lite refers to as "functionoids."
42  * (http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.10)
43  * It is similar in use to a function pointer, but allows any or all parameters to be
44  * pre-filled with constant values. The remaining parameters are specified when the
45  * function is invoked, for instance, by a Qt signal connection.
46  *
47  * By far, the most common expected use is to provide a parameter to a slot when the
48  * signal doesn't have offer one. Many developers new to Qt try to write code like this:
49  * \code
50  *     connect(button, SIGNAL(clicked()), lineEdit, SLOT(setText("Hello, world")));
51  * \endcode
52  * Experienced Qt developers will immediately spot the flaw here. The typical solution
53  * is to create a short, one-line wrapper slot that invokes the desired function. Some
54  * clever developers may even use QSignalMapper to handle slots that only need one
55  * int or QString parameter.
56  *
57  * QxtBoundFunction enables the previous connect statement to be written like this:
58  * \code
59  *     connect(button, SIGNAL(clicked()), QxtMetaObject::bind(lineEdit, SLOT(setText(QString)), Q_ARG(QString, "Hello, world!")));
60  * \code
61  * This accomplishes the same result without having to create a new slot, or worse,
62  * an entire object, just to pass a constant value.
63  *
64  * Additionally, through the use of the QXT_BIND macro, parameters from the signal
65  * can be rearranged, skipped, or passed alongside constant arguments provided
66  * with the Q_ARG macro. This can be used to provide stateful callbacks to a
67  * generic function, for example.
68  *
69  * Many kinds of functions can be bound. The most common binding applies to
70  * Qt signals and slots, but standard C/C++ functions can be bound as well.
71  * Future development may add the ability to bind to C++ member functions,
72  * and developers can make custom QxtBoundFunction subclasses for even more
73  * flexibility if necessary.
74  */
75 class QxtBoundFunction : public QObject
76 {
77     Q_OBJECT
78 public:
79     /**
80      * Invokes the bound function and returns a value.
81      *
82      * The template parameter should be the return type of the invoked function. This overload accepts
83      * QVariant parameters and will guess the data type of each parameter based on the type of the QVariant.
84      */
85     template <class T>
86     inline QxtNullable<T> invoke(QXT_PROTO_10ARGS(QVariant))
87     {
88         if (!parent() || QThread::currentThread() == parent()->thread())
89             return invoke<T>(Qt::DirectConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); 
90 #if QT_VERSION >= 0x040300
91         return invoke<T>(Qt::BlockingQueuedConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
92 #else
93         qWarning() << "QxtBoundFunction::invoke: Cannot return a value using a queued connection";
94         return qxtNull;
95 #endif
96     }
97
98     /**
99      * Invokes the bound function and returns a value.
100      *
101      * The template parameter should be the return type of the invoked function. This overload accepts
102      * QGenericArgument parameters, expressed using the Q_ARG() macro.
103      */
104     template <class T>
105     QxtNullable<T> invoke(Qt::ConnectionType type, QVariant p1, QXT_PROTO_9ARGS(QVariant))
106     {
107         if (type == Qt::QueuedConnection)
108         {
109             qWarning() << "QxtBoundFunction::invoke: Cannot return a value using a queued connection";
110             return qxtNull;
111         }
112         T retval;
113         // I know this is a totally ugly function call
114         if (invoke(type, QGenericReturnArgument(qVariantFromValue<T>(*reinterpret_cast<T*>(0)).typeName(), reinterpret_cast<void*>(&retval)),
115                    p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
116         {
117             return retval;
118         }
119         else
120         {
121             return qxtNull;
122         }
123     }
124
125     /**
126      * Invokes the bound function, discarding the return value.
127      *
128      * This overload accepts QVariant parameters and will guess the data type of each
129      * parameter based on the type of the QVariant.
130      *
131      * This function returns true if the invocation was successful, otherwise it
132      * returns false.
133      */
134     inline bool invoke(QVariant p1, QXT_PROTO_9ARGS(QVariant))
135     {
136         return invoke(Qt::AutoConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
137     }
138     /**
139      * Invokes the bound function, discarding the return value.
140      *
141      * This overload accepts QVariant parameters and will guess the data type of each
142      * parameter based on the type of the QVariant. It also allows you to specify the
143      * connection type, allowing the bound function to be invoked across threads using
144      * the Qt event loop.
145      *
146      * This function returns true if the invocation was successful, otherwise it
147      * returns false.
148      */
149     bool invoke(Qt::ConnectionType, QVariant p1, QXT_PROTO_9ARGS(QVariant));
150
151     /**
152      * Invokes the bound function, discarding the return value.
153      *
154      * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
155      * macro.
156      *
157      * This function returns true if the invocation was successful, otherwise it
158      * returns false.
159      */
160     inline bool invoke(QXT_PROTO_10ARGS(QGenericArgument))
161     {
162         return invoke(Qt::AutoConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
163     }
164     /**
165      * Invokes the bound function, discarding the return value.
166      *
167      * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
168      * macro. It also allows you to specify the connection type, allowing the bound
169      * function to be invoked across threads using the Qt event loop.
170      *
171      * This function returns true if the invocation was successful, otherwise it
172      * returns false.
173      */
174     inline bool invoke(Qt::ConnectionType type, QXT_PROTO_10ARGS(QGenericArgument)) {
175         return invoke(type, QGenericReturnArgument(), p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
176     }
177
178     /**
179      * Invokes the bound function and assigns the return value to a parameter passed by reference.
180      *
181      * Use the Q_RETURN_ARG() macro to pass a reference to an assignable object of the function's
182      * return type. When the function completes, its return value will be stored in that object.
183      *
184      * This overload accepts QVariant parameters and will guess the data type of each
185      * parameter based on the type of the QVariant.
186      *
187      * This function returns true if the invocation was successful, otherwise it
188      * returns false.
189      */
190     inline bool invoke(QGenericReturnArgument returnValue, QVariant p1, QXT_PROTO_9ARGS(QVariant))
191     {
192         return invoke(Qt::AutoConnection, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
193     }
194     /**
195      * Invokes the bound function and assigns the return value to a parameter passed by reference.
196      *
197      * Use the Q_RETURN_ARG() macro to pass a reference to an assignable object of the function's
198      * return type. When the function completes, its return value will be stored in that object.
199      *
200      * This overload accepts QVariant parameters and will guess the data type of each
201      * parameter based on the type of the QVariant. It also allows you to specify the
202      * connection type, allowing the bound function to be invoked across threads using
203      * the Qt event loop.
204      *
205      * This function returns true if the invocation was successful, otherwise it
206      * returns false.
207      */
208     bool invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QVariant p1, QXT_PROTO_9ARGS(QVariant));
209
210     /**
211      * Invokes the bound function and assigns the return value to a parameter passed by reference.
212      *
213      * Use the Q_RETURN_ARG() macro to pass a reference to an assignable object of the function's
214      * return type. When the function completes, its return value will be stored in that object.
215      *
216      * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
217      * macro.
218      *
219      * This function returns true if the invocation was successful, otherwise it
220      * returns false.
221      */
222     inline bool invoke(QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument))
223     {
224         return invoke(Qt::AutoConnection, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
225     }
226     /**
227      * Invokes the bound function and assigns the return value to a parameter passed by reference.
228      *
229      * Use the Q_RETURN_ARG() macro to pass a reference to an assignable object of the function's
230      * return type. When the function completes, its return value will be stored in that object.
231      *
232      * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
233      * macro. It also allows you to specify the connection type, allowing the bound
234      * function to be invoked across threads using the Qt event loop.
235      *
236      * This function returns true if the invocation was successful, otherwise it
237      * returns false.
238      */
239     bool invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument));
240
241 protected:
242 #ifndef QXT_DOXYGEN_RUN
243     QxtBoundFunction(QObject* parent = 0);
244 #endif
245
246     /**
247      * Performs the work of invoking the bound function.
248      *
249      * This function is pure virtual. The various QxtMetaObject::bind() functions return opaque subclasses
250      * of QxtBoundFunction. If you wish to create a new kind of bound function, reimplement this function to
251      * perform the invocation and assign the function's return value, if any, to the returnValue parameter.
252      *
253      * This function should return true if the invocation is successful and false if an error occurs.
254      */
255     virtual bool invokeImpl(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument)) = 0;
256 };
257
258 #endif