2
Copyright (C) 2009-2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
3
Copyright (C) 2010 Collabora Ltd.
4
@author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
6
This library is free software; you can redistribute it and/or modify
7
it under the terms of the GNU Lesser General Public License as published
8
by the Free Software Foundation; either version 2.1 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public License
17
along with this program. If not, see <http://www.gnu.org/licenses/>.
24
#include "refpointer.h"
25
#include <boost/mpl/if.hpp>
26
#include <boost/type_traits.hpp>
28
#include <QtCore/QString>
29
#include <QtCore/QDebug>
30
#include <QtCore/QSharedData>
34
/*! This structure holds the set and get methods that are used internally
35
* by Value to handle data of a specific type. If you want to provide
36
* support for a custom type, you need to write two such methods, create
37
* a new ValueVTable instance that holds pointers to them and register it
38
* using Value::registerValueVTable().
39
* \sa \ref value_design
41
struct QTGLIB_EXPORT ValueVTable
43
typedef void (*SetFunction)(Value & value, const void *data);
44
typedef void (*GetFunction)(const Value & value, void *data);
46
inline ValueVTable() : set(NULL), get(NULL) {}
47
inline ValueVTable(SetFunction s, GetFunction g) : set(s), get(g) {}
54
/*! \headerfile value.h <QGlib/Value>
55
* \brief Wrapper class for GValue
57
* This class serves as a wrapper for GValue. GValue is a data type that can hold different
58
* types of values inside, like a QVariant.
60
* A Value object holds a single value of a single type() at a time. To create a new Value,
61
* use the static create() method or one of the constructors. To get the held value, use
62
* the template get() method or one of the toT() functions (ex. toInt()).
64
* To set a value to an invalid Value (on which isValid() returns false), you must first
65
* initialize this Value using one of the init() methods (preferably the template one) in order
66
* to tell it what kind of value it is going to hold. Once initialized to hold a specific type,
67
* you can use the set() method to set a value. To change the type that this value holds, you
68
* can call the init() method again at any time. In this case, though, any previously held value
71
* \note This class is implicitly shared.
73
class QTGLIB_EXPORT Value
76
/*! Creates a new invalid Value \sa isValid() */
79
/*! Creates a new Value that holds a copy of the given \a gvalue */
80
explicit Value(const GValue *gvalue);
82
/*! Creates a new Value and initializes it to hold values of the given \a type.
83
* This is equivalent to:
89
explicit Value(Type type);
91
Value(bool val); ///< Creates a new Value of Type::Bool and sets it to hold \a val
92
Value(char val); ///< Creates a new Value of Type::Char and sets it to hold \a val
93
Value(uchar val); ///< Creates a new Value of Type::Uchar and sets it to hold \a val
94
Value(int val); ///< Creates a new Value of Type::Int and sets it to hold \a val
95
Value(uint val); ///< Creates a new Value of Type::Uint and sets it to hold \a val
96
Value(long val); ///< Creates a new Value of Type::Long and sets it to hold \a val
97
Value(ulong val); ///< Creates a new Value of Type::Ulong and sets it to hold \a val
98
Value(qint64 val); ///< Creates a new Value of Type::Int64 and sets it to hold \a val
99
Value(quint64 val); ///< Creates a new Value of Type::Uint64 and sets it to hold \a val
100
Value(float val); ///< Creates a new Value of Type::Float and sets it to hold \a val
101
Value(double val); ///< Creates a new Value of Type::Double and sets it to hold \a val
102
Value(const char *val); ///< Creates a new Value of Type::String and sets it to hold \a val
103
Value(const QByteArray & val); ///< Creates a new Value of Type::String and sets it to hold \a val
104
Value(const QString & val); ///< Creates a new Value of Type::String and sets it to hold \a val
106
Value(const Value & other);
107
Value & operator=(const Value & other);
112
/*! Creates a new Value that is intialized to hold data
113
* of type T and sets it to hold \a data.
114
* \note T must be a type registered with the QtGLib type system. Attempting
115
* to use a type that is not properly registered will fail to compile.
117
template <typename T>
118
static inline Value create(const T & data);
121
/*! Initializes or re-initializes this Value to hold data of the given \a type.
122
* If this Value was previously holding any data, this data will be freed.
124
void init(Type type);
126
/*! Initializes or re-initializes this Value to hold data of type T.
127
* If this Value was previously holding any data, this data will be freed.
128
* \note T must be a type registered with the QtGLib type system. Attempting
129
* to use a type that is not properly registered will fail to compile.
131
template <typename T>
135
/*! \returns whether this Value instance is initialized to hold a certain type
137
bool isValid() const;
139
/*! \returns the type that this Value instance has been initialized to hold */
142
/*! \returns whether it is possible to transform this Value to a Value of another type */
143
bool canTransformTo(Type type) const;
145
/*! Transforms the current value into a value of the specified \a type, if possible.
146
* Possible transformations are, for example, int to float, int to string, etc...
147
* The original Value remains unaffected and the transformed Value is returned.
149
Value transformTo(Type type) const;
151
/*! Clears the current value in this Value instance and resets it to the
152
* default value (as if the Value had just been initialized). */
156
/*! Retrieves the value stored in this Value instance, as the specified type T.
157
* The bindings take care of calling the appropriate g_value_get_* method depending
158
* on the type T. Note though that this is only meant to be used with the types of
159
* the bindings, not their C types. This means that if for example the Value has
160
* been initialized to hold a GstObject pointer, you can use:
162
* QGst::ObjectPtr object = value.get<QGst::ObjectPtr>();
166
* GstObject *object = value.get<GstObject*>(); //will cause compilation error
169
* If the underlying stored value is not of the type T, this method will attempt
170
* to convert it to type T. If this is not possible, a default constructed value
173
* If \a ok has been specified, it is set to true if the value was retrieved
174
* successfully or false if there was an error (probably conversion error) and
175
* a default constructed value has been returned.
177
template <typename T> T get(bool *ok = NULL) const;
179
/*! Sets this Value instance to hold the specified \a data.
180
* As with get(), the bindings take care of calling the appropriate g_value_set_*
181
* method depending on the type T, but note that this is only meant to be used
182
* with the types of the bindings.
184
* If this Value instance has been initialized to hold a different type of data
185
* than T, a conversion to the correct type() will be attempted. If the conversion
186
* fails, the Value will remain unaffected and a warning will be printed.
189
template <typename T> void set(const T & data);
192
/*! Returns the held value as a bool. Equivalent to get<bool>(ok); \sa get() */
193
inline bool toBool(bool *ok = NULL) const { return get<bool>(ok); }
195
/*! Returns the held value as a char. Equivalent to get<char>(ok); \sa get() */
196
inline char toChar(bool *ok = NULL) const { return get<char>(ok); }
198
/*! Returns the held value as a uchar. Equivalent to get<uchar>(ok); \sa get() */
199
inline uchar toUChar(bool *ok = NULL) const { return get<uchar>(ok); }
201
/*! Returns the held value as an int. Equivalent to get<int>(ok); \sa get() */
202
inline int toInt(bool *ok = NULL) const { return get<int>(ok); }
204
/*! Returns the held value as a uint. Equivalent to get<uint>(ok); \sa get() */
205
inline uint toUInt(bool *ok = NULL) const { return get<uint>(ok); }
207
/*! Returns the held value as a long. Equivalent to get<long>(ok); \sa get() */
208
inline long toLong(bool *ok = NULL) const { return get<long>(ok); }
210
/*! Returns the held value as a ulong. Equivalent to get<ulong>(ok); \sa get() */
211
inline ulong toULong(bool *ok = NULL) const { return get<ulong>(ok); }
213
/*! Returns the held value as a qint64. Equivalent to get<qint64>(ok); \sa get() */
214
inline qint64 toInt64(bool *ok = NULL) const { return get<qint64>(ok); }
216
/*! Returns the held value as a quint64. Equivalent to get<quint64>(ok); \sa get() */
217
inline quint64 toUInt64(bool *ok = NULL) const { return get<quint64>(ok); }
219
/*! Returns the held value as a QByteAray. Equivalent to get<QByteArray>(ok); \sa get() */
220
inline QByteArray toByteArray(bool *ok = NULL) const { return get<QByteArray>(ok); }
222
/*! Returns the held value as a QString. Equivalent to get<QString>(ok); \sa get() */
223
inline QString toString(bool *ok = NULL) const { return get<QString>(ok); }
226
/*! This is a cast operator that gives access to the underlying GValue instance.
227
* It is provided for convenience, to be able to pass this Value as argument to C
228
* functions that expect a GValue pointer. Use this feature with care. Do not store
229
* the pointer, as it may go away at any time. This Value instance keeps control of
230
* this pointer. If you need to store it, use g_value_copy() to copy it first.
233
operator const GValue*() const; ///< \overload
236
/*! Registers the given ValueVTable \a vtable for the given \a type.
237
* This is provided to let you add support for a custom type, if necessary.
238
* You should normally not need to do that, as most types are handled
239
* by the handlers of their parent types.
240
* \sa \ref value_design
242
static void registerValueVTable(Type type, const ValueVTable & vtable);
245
template <typename T>
246
friend struct ValueImpl;
248
/*! Retrieves the data from this Value and places it into the memory position
249
* pointed to by \a data. \a dataType indicates the actual data type of \a data
250
* and is used, among others, to cast \a data back to the actual C++ type that
251
* it points to and assign it.
252
* \note This method should only be accessed from ValueImpl.
253
* \sa \ref value_design
255
void getData(Type dataType, void *data) const;
257
/*! Sets the data of this Value to be the data pointed to by \a data.
258
* \a dataType indicates the actual data type of \a data and is used,
259
* among others, to cast \a data back to the actual C++ type that
260
* it points to and retrieve its value.
261
* \note This method should only be accessed from ValueImpl.
262
* \sa \ref value_design
264
void setData(Type dataType, const void *data);
267
QSharedDataPointer<Data> d;
271
/*! This struct provides the implementation for the Value::get() and Value::set() methods.
272
* If you want to provide support for a custom type, you may want to provide a template
273
* specialization of this class to handle your type in a different way than the default
274
* implementation. You should normally not need to be concerned at all with this.
275
* \note this struct is declared as friend in Value and as a result it has access to
276
* Value::setData() and Value::getData()
277
* \sa \ref value_design
279
template <typename T>
282
static inline T get(const Value & value);
283
static inline void set(Value & value, const T & data);
286
// -- template implementations --
289
template <typename T>
290
inline Value Value::create(const T & data)
298
template <typename T>
299
inline void Value::init()
304
template <typename T>
305
T Value::get(bool *ok) const
312
return ValueImpl<T>::get(*this);
313
} catch (const std::exception &) {
321
template <typename T>
322
void Value::set(const T & data)
325
ValueImpl<T>::set(*this, data);
326
} catch (const std::exception & e) {
327
qWarning() << "QGlib::Value::set:" << e.what();
331
// -- default ValueImpl implementation --
333
template <typename T>
334
inline T ValueImpl<T>::get(const Value & value)
336
//Use int for enums, T for everything else
337
typename boost::mpl::if_<
342
value.getData(GetType<T>(), &result);
343
return static_cast<T>(result);
346
template <typename T>
347
inline void ValueImpl<T>::set(Value & value, const T & data)
349
//Use const int for enums, const T for everything else
350
typename boost::mpl::if_<
353
>::type dataRef = data;
355
value.setData(GetType<T>(), &dataRef);
358
// -- ValueImpl specialization for QFlags --
361
struct ValueImpl< QFlags<T> >
363
static inline QFlags<T> get(const Value & value)
366
value.getData(GetType< QFlags<T> >(), &flags);
367
return QFlags<T>(QFlag(flags));
370
static inline void set(Value & value, const QFlags<T> & data)
373
value.setData(GetType< QFlags<T> >(), &flags);
377
// -- ValueImpl specialization for RefPointer --
380
struct ValueImpl< RefPointer<T> >
382
static inline RefPointer<T> get(const Value & value)
384
typename T::CType *gobj;
385
value.getData(GetType<T>(), &gobj);
386
return RefPointer<T>::wrap(gobj);
389
static inline void set(Value & value, const RefPointer<T> & data)
391
typename T::CType *gobj = static_cast<typename T::CType*>(data);
392
value.setData(GetType<T>(), &gobj);
396
// -- ValueImpl specializations for string literals --
399
struct ValueImpl<const char[N]> //ISO C++ string literals are const char[]
401
//No get method, obviously.
403
static inline void set(Value & value, const char (&data)[N])
405
QByteArray str = QByteArray::fromRawData(data, N);
406
value.setData(Type::String, &str);
411
struct ValueImpl<char[N]> //gcc string literals are char[]
413
//No get method, obviously.
415
static inline void set(Value & value, const char (&data)[N])
417
QByteArray str = QByteArray::fromRawData(data, N);
418
value.setData(Type::String, &str);
422
// -- ValueImpl specialization for const char* --
425
struct ValueImpl<const char*>
427
//No get method, obviously.
429
static inline void set(Value & value, const char *data)
431
QByteArray str = QByteArray::fromRawData(data, qstrlen(data));
432
value.setData(Type::String, &str);
436
// -- ValueImpl specialization for QString --
439
struct ValueImpl<QString>
441
static inline QString get(const Value & value)
444
value.getData(Type::String, &str);
445
return QString::fromUtf8(str);
448
static inline void set(Value & value, const QString & data)
450
QByteArray str = data.toUtf8();
451
value.setData(Type::String, &str);
455
// -- ValueImpl specialization for Value --
458
struct ValueImpl<Value>
460
static inline Value get(const Value & value)
465
static inline void set(Value & value, const Value & data)
471
// -- Exceptions thrown from getData/setData --
475
class QTGLIB_EXPORT InvalidValueException : public std::logic_error
478
inline InvalidValueException()
479
: std::logic_error("This Value instance has not been initialized") {}
482
class QTGLIB_EXPORT InvalidTypeException : public std::logic_error
485
inline InvalidTypeException(const std::string & dataType, const std::string & valueType)
486
: std::logic_error("Unable to handle value type \"" + dataType +
487
"\". This Value instance has been initialized to hold values of type \""
488
+ valueType + "\" and no conversion is possible") {}
491
class QTGLIB_EXPORT UnregisteredTypeException : public std::logic_error
494
inline UnregisteredTypeException(const std::string & typeName)
495
: std::logic_error("Unable to handle unregistered type \"" + typeName + "\"") {}
498
class QTGLIB_EXPORT TransformationFailedException : public std::runtime_error
501
inline TransformationFailedException(const std::string & srcTypeName,
502
const std::string & destTypeName)
503
: std::runtime_error("Failed to transform value from type \""
504
+ srcTypeName + "\" to type \"" + destTypeName + "\"") {}
507
} //namespace Private
509
// -- QDebug operator --
511
/*! \relates QGlib::Value */
512
QTGLIB_EXPORT QDebug operator<<(QDebug debug, const Value & value);
516
QGLIB_REGISTER_TYPE(QGlib::Value)