1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtCore module of the Qt eXTension library
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
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.
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.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
25 #ifndef QXTBOUNDFUNCTION_H
26 #define QXTBOUNDFUNCTION_H
29 #include <QMetaObject>
30 #include <QGenericArgument>
31 #include <qxtmetaobject.h>
37 * \class QxtBoundFunction
39 * \brief Binds parameters to a function call
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.
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:
50 * connect(button, SIGNAL(clicked()), lineEdit, SLOT(setText("Hello, world")));
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.
57 * QxtBoundFunction enables the previous connect statement to be written like this:
59 * connect(button, SIGNAL(clicked()), QxtMetaObject::bind(lineEdit, SLOT(setText(QString)), Q_ARG(QString, "Hello, world!")));
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.
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.
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.
75 class QxtBoundFunction : public QObject
80 * Invokes the bound function and returns a value.
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.
86 inline QxtNullable<T> invoke(QXT_PROTO_10ARGS(QVariant))
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);
93 qWarning() << "QxtBoundFunction::invoke: Cannot return a value using a queued connection";
99 * Invokes the bound function and returns a value.
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.
105 QxtNullable<T> invoke(Qt::ConnectionType type, QVariant p1, QXT_PROTO_9ARGS(QVariant))
107 if (type == Qt::QueuedConnection)
109 qWarning() << "QxtBoundFunction::invoke: Cannot return a value using a queued connection";
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))
126 * Invokes the bound function, discarding the return value.
128 * This overload accepts QVariant parameters and will guess the data type of each
129 * parameter based on the type of the QVariant.
131 * This function returns true if the invocation was successful, otherwise it
134 inline bool invoke(QVariant p1, QXT_PROTO_9ARGS(QVariant))
136 return invoke(Qt::AutoConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
139 * Invokes the bound function, discarding the return value.
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
146 * This function returns true if the invocation was successful, otherwise it
149 bool invoke(Qt::ConnectionType, QVariant p1, QXT_PROTO_9ARGS(QVariant));
152 * Invokes the bound function, discarding the return value.
154 * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
157 * This function returns true if the invocation was successful, otherwise it
160 inline bool invoke(QXT_PROTO_10ARGS(QGenericArgument))
162 return invoke(Qt::AutoConnection, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
165 * Invokes the bound function, discarding the return value.
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.
171 * This function returns true if the invocation was successful, otherwise it
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);
179 * Invokes the bound function and assigns the return value to a parameter passed by reference.
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.
184 * This overload accepts QVariant parameters and will guess the data type of each
185 * parameter based on the type of the QVariant.
187 * This function returns true if the invocation was successful, otherwise it
190 inline bool invoke(QGenericReturnArgument returnValue, QVariant p1, QXT_PROTO_9ARGS(QVariant))
192 return invoke(Qt::AutoConnection, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
195 * Invokes the bound function and assigns the return value to a parameter passed by reference.
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.
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
205 * This function returns true if the invocation was successful, otherwise it
208 bool invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QVariant p1, QXT_PROTO_9ARGS(QVariant));
211 * Invokes the bound function and assigns the return value to a parameter passed by reference.
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.
216 * This overload accepts QGenericArgument parameters, expressed using the Q_ARG()
219 * This function returns true if the invocation was successful, otherwise it
222 inline bool invoke(QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument))
224 return invoke(Qt::AutoConnection, returnValue, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
227 * Invokes the bound function and assigns the return value to a parameter passed by reference.
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.
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.
236 * This function returns true if the invocation was successful, otherwise it
239 bool invoke(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument));
242 #ifndef QXT_DOXYGEN_RUN
243 QxtBoundFunction(QObject* parent = 0);
247 * Performs the work of invoking the bound function.
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.
253 * This function should return true if the invocation is successful and false if an error occurs.
255 virtual bool invokeImpl(Qt::ConnectionType type, QGenericReturnArgument returnValue, QXT_PROTO_10ARGS(QGenericArgument)) = 0;