Core: QDebug and comparison operator support metatypes.
This patch adds a way to enable operator<, operator== and operator<< into QDebug for QVariants with custom types. Change-Id: I3d12d891bd7252ad2b8f1de69bced354800a1f29 Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
This commit is contained in:
parent
63354e0d09
commit
7ed15da3c1
@ -420,38 +420,34 @@ public:
|
||||
int alias;
|
||||
};
|
||||
|
||||
class QMetaTypeConversionRegistry
|
||||
template<typename T, typename Key>
|
||||
class QMetaTypeFunctionRegistry
|
||||
{
|
||||
public:
|
||||
typedef QPair<int, int> Key;
|
||||
|
||||
~QMetaTypeConversionRegistry()
|
||||
~QMetaTypeFunctionRegistry()
|
||||
{
|
||||
const QWriteLocker locker(&lock);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
bool contains(int from, int to) const
|
||||
bool contains(Key k) const
|
||||
{
|
||||
const Key k(from, to);
|
||||
const QReadLocker locker(&lock);
|
||||
return map.contains(k);
|
||||
}
|
||||
|
||||
bool insertIfNotContains(int from, int to, const QtPrivate::AbstractConverterFunction *f)
|
||||
bool insertIfNotContains(Key k, const T *f)
|
||||
{
|
||||
const Key k(from, to);
|
||||
const QWriteLocker locker(&lock);
|
||||
const QtPrivate::AbstractConverterFunction* &fun = map[k];
|
||||
const T* &fun = map[k];
|
||||
if (fun != 0)
|
||||
return false;
|
||||
fun = f;
|
||||
return true;
|
||||
}
|
||||
|
||||
const QtPrivate::AbstractConverterFunction *function(int from, int to) const
|
||||
const T *function(Key k) const
|
||||
{
|
||||
const Key k(from, to);
|
||||
const QReadLocker locker(&lock);
|
||||
return map.value(k, 0);
|
||||
}
|
||||
@ -464,9 +460,16 @@ public:
|
||||
}
|
||||
private:
|
||||
mutable QReadWriteLock lock;
|
||||
QHash<Key, const QtPrivate::AbstractConverterFunction *> map;
|
||||
QHash<Key, const T *> map;
|
||||
};
|
||||
|
||||
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
|
||||
QMetaTypeConverterRegistry;
|
||||
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int>
|
||||
QMetaTypeComparatorRegistry;
|
||||
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
|
||||
QMetaTypeDebugStreamRegistry;
|
||||
|
||||
namespace
|
||||
{
|
||||
union CheckThatItIsPod
|
||||
@ -478,7 +481,9 @@ union CheckThatItIsPod
|
||||
Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE);
|
||||
Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes)
|
||||
Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
|
||||
Q_GLOBAL_STATIC(QMetaTypeConversionRegistry, customTypesConversionRegistry)
|
||||
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
|
||||
Q_GLOBAL_STATIC(QMetaTypeComparatorRegistry, customTypesComparatorRegistry)
|
||||
Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::registerConverter()
|
||||
@ -511,6 +516,23 @@ Q_GLOBAL_STATIC(QMetaTypeConversionRegistry, customTypesConversionRegistry)
|
||||
to type To in the meta type system. Returns true if the registration succeeded, otherwise false.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::registerComparators()
|
||||
\since 5.2
|
||||
Registers comparison operetarors for the user-registered type T. This requires T to have
|
||||
both an operator== and an operator<.
|
||||
Returns true if the registration succeeded, otherwise false.
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
/*!
|
||||
\fn bool QMetaType::registerDebugStreamOperator()
|
||||
Registers the debug stream operator for the user-registered type T. This requires T to have
|
||||
an operator<<(QDebug dbg, T).
|
||||
Returns true if the registration succeeded, otherwise false.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Registers function \a f as converter function from type id \a from to \a to.
|
||||
If there's already a conversion registered, this does nothing but deleting \a f.
|
||||
@ -520,7 +542,7 @@ Q_GLOBAL_STATIC(QMetaTypeConversionRegistry, customTypesConversionRegistry)
|
||||
*/
|
||||
bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to)
|
||||
{
|
||||
if (!customTypesConversionRegistry()->insertIfNotContains(from, to, f)) {
|
||||
if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
|
||||
qWarning("Type conversion already registered from type %s to type %s",
|
||||
QMetaType::typeName(from), QMetaType::typeName(to));
|
||||
return false;
|
||||
@ -538,6 +560,58 @@ void QMetaType::unregisterConverterFunction(int from, int to)
|
||||
customTypesConversionRegistry()->remove(from, to);
|
||||
}
|
||||
|
||||
bool QMetaType::registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type)
|
||||
{
|
||||
if (!customTypesComparatorRegistry()->insertIfNotContains(type, f)) {
|
||||
qWarning("Comparators already registered for type %s", QMetaType::typeName(type));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::hasRegisteredComparators()
|
||||
Returns true, if the meta type system has registered comparators for type T.
|
||||
\since 5.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns true, if the meta type system has registered comparators for type id \a typeId.
|
||||
\since 5.2
|
||||
*/
|
||||
bool QMetaType::hasRegisteredComparators(int typeId)
|
||||
{
|
||||
return customTypesComparatorRegistry()->contains(typeId);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f,
|
||||
int type)
|
||||
{
|
||||
if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) {
|
||||
qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::hasRegisteredDebugStreamOperator()
|
||||
Returns true, if the meta type system has a registered debug stream operator for type T.
|
||||
\since 5.2
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns true, if the meta type system has a registered debug stream operator for type
|
||||
id \a typeId.
|
||||
\since 5.2
|
||||
*/
|
||||
bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
|
||||
{
|
||||
return customTypesDebugStreamRegistry()->contains(typeId);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Converts the object at \a from from \a fromTypeId to the preallocated space at \a to
|
||||
typed \a toTypeId. Returns true, if the conversion succeeded, otherwise false.
|
||||
@ -545,10 +619,44 @@ void QMetaType::unregisterConverterFunction(int from, int to)
|
||||
*/
|
||||
bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
|
||||
{
|
||||
const QtPrivate::AbstractConverterFunction * const f = customTypesConversionRegistry()->function(fromTypeId, toTypeId);
|
||||
const QtPrivate::AbstractConverterFunction * const f =
|
||||
customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
|
||||
return f && f->convert(f, from, to);
|
||||
}
|
||||
|
||||
/*!
|
||||
Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId.
|
||||
\a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to
|
||||
or greater than \a rhs. Returns true, if the comparison succeeded, otherwiess false.
|
||||
\since 5.2
|
||||
*/
|
||||
bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result)
|
||||
{
|
||||
const QtPrivate::AbstractComparatorFunction * const f =
|
||||
customTypesComparatorRegistry()->function(typeId);
|
||||
if (!f)
|
||||
return false;
|
||||
if (f->equals(f, lhs, rhs))
|
||||
*result = 0;
|
||||
else
|
||||
*result = f->lessThan(f, lhs, rhs) ? -1 : 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns true
|
||||
on success, otherwise false.
|
||||
\since 5.2
|
||||
*/
|
||||
bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
|
||||
{
|
||||
const QtPrivate::AbstractDebugStreamFunction * const f = customTypesDebugStreamRegistry()->function(typeId);
|
||||
if (!f)
|
||||
return false;
|
||||
f->stream(f, dbg, rhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::hasRegisteredConverterFunction()
|
||||
Returns true, if the meta type system has a registered conversion from type From to type To.
|
||||
@ -563,7 +671,7 @@ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId
|
||||
*/
|
||||
bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
|
||||
{
|
||||
return customTypesConversionRegistry()->contains(fromTypeId, toTypeId);
|
||||
return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
|
@ -222,6 +222,74 @@ To convertImplicit(const From& from)
|
||||
return from;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
struct AbstractDebugStreamFunction
|
||||
{
|
||||
typedef void (*Stream)(const AbstractDebugStreamFunction *, QDebug&, const void *);
|
||||
typedef void (*Destroy)(AbstractDebugStreamFunction *);
|
||||
explicit AbstractDebugStreamFunction(Stream s = 0, Destroy d = 0)
|
||||
: stream(s), destroy(d) {}
|
||||
Q_DISABLE_COPY(AbstractDebugStreamFunction)
|
||||
Stream stream;
|
||||
Destroy destroy;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BuiltInDebugStreamFunction : public AbstractDebugStreamFunction
|
||||
{
|
||||
BuiltInDebugStreamFunction()
|
||||
: AbstractDebugStreamFunction(stream, destroy) {}
|
||||
static void stream(const AbstractDebugStreamFunction *, QDebug& dbg, const void *r)
|
||||
{
|
||||
const T *rhs = static_cast<const T *>(r);
|
||||
operator<<(dbg, *rhs);
|
||||
}
|
||||
|
||||
static void destroy(AbstractDebugStreamFunction *_this)
|
||||
{
|
||||
delete static_cast<BuiltInDebugStreamFunction *>(_this);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct AbstractComparatorFunction
|
||||
{
|
||||
typedef bool (*LessThan)(const AbstractComparatorFunction *, const void *, const void *);
|
||||
typedef bool (*Equals)(const AbstractComparatorFunction *, const void *, const void *);
|
||||
typedef void (*Destroy)(AbstractComparatorFunction *);
|
||||
explicit AbstractComparatorFunction(LessThan lt = 0, Equals e = 0, Destroy d = 0)
|
||||
: lessThan(lt), equals(e), destroy(d) {}
|
||||
Q_DISABLE_COPY(AbstractComparatorFunction)
|
||||
LessThan lessThan;
|
||||
Equals equals;
|
||||
Destroy destroy;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BuiltInComparatorFunction : public AbstractComparatorFunction
|
||||
{
|
||||
BuiltInComparatorFunction()
|
||||
: AbstractComparatorFunction(lessThan, equals, destroy) {}
|
||||
static bool lessThan(const AbstractComparatorFunction *, const void *l, const void *r)
|
||||
{
|
||||
const T *lhs = static_cast<const T *>(l);
|
||||
const T *rhs = static_cast<const T *>(r);
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
|
||||
static bool equals(const AbstractComparatorFunction *, const void *l, const void *r)
|
||||
{
|
||||
const T *lhs = static_cast<const T *>(l);
|
||||
const T *rhs = static_cast<const T *>(r);
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
|
||||
static void destroy(AbstractComparatorFunction *_this)
|
||||
{
|
||||
delete static_cast<BuiltInComparatorFunction *>(_this);
|
||||
}
|
||||
};
|
||||
|
||||
struct AbstractConverterFunction
|
||||
{
|
||||
typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*);
|
||||
@ -437,6 +505,43 @@ public:
|
||||
inline void destruct(void *data) const;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
static bool registerComparators()
|
||||
{
|
||||
Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn),
|
||||
"QMetaType::registerComparators: The type must be a custom type.");
|
||||
|
||||
const int typeId = qMetaTypeId<T>();
|
||||
static const QtPrivate::BuiltInComparatorFunction<T> f;
|
||||
return registerComparatorFunction( &f, typeId);
|
||||
}
|
||||
template<typename T>
|
||||
static bool hasRegisteredComparators()
|
||||
{
|
||||
return hasRegisteredComparators(qMetaTypeId<T>());
|
||||
}
|
||||
static bool hasRegisteredComparators(int typeId);
|
||||
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
template<typename T>
|
||||
static bool registerDebugStreamOperator()
|
||||
{
|
||||
Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn),
|
||||
"QMetaType::registerDebugStreamOperator: The type must be a custom type.");
|
||||
|
||||
const int typeId = qMetaTypeId<T>();
|
||||
static const QtPrivate::BuiltInDebugStreamFunction<T> f;
|
||||
return registerDebugStreamOperatorFunction(&f, typeId);
|
||||
}
|
||||
template<typename T>
|
||||
static bool hasRegisteredDebugStreamOperator()
|
||||
{
|
||||
return hasRegisteredDebugStreamOperator(qMetaTypeId<T>());
|
||||
}
|
||||
static bool hasRegisteredDebugStreamOperator(int typeId);
|
||||
#endif
|
||||
|
||||
// implicit conversion supported like double -> float
|
||||
template<typename From, typename To>
|
||||
static bool registerConverter()
|
||||
@ -490,6 +595,8 @@ public:
|
||||
#endif
|
||||
|
||||
static bool convert(const void *from, int fromTypeId, void *to, int toTypeId);
|
||||
static bool compare(const void *lhs, const void *rhs, int typeId, int* result);
|
||||
static bool debugStream(QDebug& dbg, const void *rhs, int typeId);
|
||||
|
||||
template<typename From, typename To>
|
||||
static bool hasRegisteredConverterFunction()
|
||||
@ -527,6 +634,11 @@ private:
|
||||
void *constructExtended(void *where, const void *copy = 0) const;
|
||||
void destructExtended(void *data) const;
|
||||
|
||||
static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type);
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type);
|
||||
#endif
|
||||
|
||||
#ifndef Q_NO_TEMPLATE_FRIENDS
|
||||
#ifndef Q_QDOC
|
||||
template<typename T>
|
||||
|
@ -2938,8 +2938,9 @@ bool QVariant::convert(const int type, void *ptr) const
|
||||
which means that two values can be equal even if one of them is null and
|
||||
another is not.
|
||||
|
||||
\warning This function doesn't support custom types registered
|
||||
with qRegisterMetaType().
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
/*!
|
||||
\fn bool operator!=(const QVariant &v1, const QVariant &v2)
|
||||
@ -2948,8 +2949,9 @@ bool QVariant::convert(const int type, void *ptr) const
|
||||
|
||||
Returns false if \a v1 and \a v2 are equal; otherwise returns true.
|
||||
|
||||
\warning This function doesn't support custom types registered
|
||||
with qRegisterMetaType().
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*! \fn bool QVariant::operator==(const QVariant &v) const
|
||||
@ -2962,8 +2964,9 @@ bool QVariant::convert(const int type, void *ptr) const
|
||||
type is not the same as this variant's type. See canConvert() for
|
||||
a list of possible conversions.
|
||||
|
||||
\warning This function doesn't support custom types registered
|
||||
with qRegisterMetaType().
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*!
|
||||
@ -2972,8 +2975,61 @@ bool QVariant::convert(const int type, void *ptr) const
|
||||
Compares this QVariant with \a v and returns true if they are not
|
||||
equal; otherwise returns false.
|
||||
|
||||
\warning This function doesn't support custom types registered
|
||||
with qRegisterMetaType().
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QVariant::operator<(const QVariant &v) const
|
||||
|
||||
Compares this QVariant with \a v and returns true if this is less than \a v.
|
||||
|
||||
\note Comparability might not be availabe for the type stored in this QVariant
|
||||
or in \a v.
|
||||
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QVariant::operator<=(const QVariant &v) const
|
||||
|
||||
Compares this QVariant with \a v and returns true if this is less or equal than \a v.
|
||||
|
||||
\note Comparability might not be available for the type stored in this QVariant
|
||||
or in \a v.
|
||||
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QVariant::operator>(const QVariant &v) const
|
||||
|
||||
Compares this QVariant with \a v and returns true if this is larger than \a v.
|
||||
|
||||
\note Comparability might not be available for the type stored in this QVariant
|
||||
or in \a v.
|
||||
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QVariant::operator>=(const QVariant &v) const
|
||||
|
||||
Compares this QVariant with \a v and returns true if this is larger or equal than \a v.
|
||||
|
||||
\note Comparability might not be available for the type stored in this QVariant
|
||||
or in \a v.
|
||||
|
||||
\warning To make this function work with a custom type registered with
|
||||
qRegisterMetaType(), its comparison operator must be registered using
|
||||
QMetaType::registerComparators().
|
||||
*/
|
||||
|
||||
static bool qIsNumericType(uint tp)
|
||||
@ -2992,6 +3048,7 @@ static bool qIsFloatingPoint(uint tp)
|
||||
*/
|
||||
bool QVariant::cmp(const QVariant &v) const
|
||||
{
|
||||
QVariant v1 = *this;
|
||||
QVariant v2 = v;
|
||||
if (d.type != v2.d.type) {
|
||||
if (qIsNumericType(d.type) && qIsNumericType(v.d.type)) {
|
||||
@ -3000,10 +3057,63 @@ bool QVariant::cmp(const QVariant &v) const
|
||||
else
|
||||
return toLongLong() == v.toLongLong();
|
||||
}
|
||||
if (!v2.canConvert(d.type) || !v2.convert(d.type))
|
||||
if (!v2.canConvert(v1.d.type) || !v2.convert(v1.d.type))
|
||||
return false;
|
||||
}
|
||||
return handlerManager[d.type]->compare(&d, &v2.d);
|
||||
if (v1.d.type >= QMetaType::User) {
|
||||
int result;
|
||||
if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
|
||||
return result == 0;
|
||||
}
|
||||
return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
int QVariant::compare(const QVariant &v) const
|
||||
{
|
||||
if (cmp(v))
|
||||
return 0;
|
||||
QVariant v1 = *this;
|
||||
QVariant v2 = v;
|
||||
if (v1.d.type != v2.d.type) {
|
||||
// if both types differ, try to convert
|
||||
if (v2.canConvert(v1.d.type)) {
|
||||
QVariant temp = v2;
|
||||
if (temp.convert(v1.d.type))
|
||||
v2 = temp;
|
||||
}
|
||||
if (v1.d.type != v2.d.type && v1.canConvert(v2.d.type)) {
|
||||
QVariant temp = v1;
|
||||
if (temp.convert(v2.d.type))
|
||||
v1 = temp;
|
||||
}
|
||||
if (v1.d.type != v2.d.type) {
|
||||
// if conversion fails, default to toString
|
||||
return v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
|
||||
}
|
||||
}
|
||||
if (v1.d.type >= QMetaType::User) {
|
||||
int result;
|
||||
if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2.d)), d.type, &result))
|
||||
return result;
|
||||
}
|
||||
if (qIsNumericType(v1.d.type)) {
|
||||
if (qIsFloatingPoint(v1.d.type))
|
||||
return v1.toReal() < v2.toReal() ? -1 : 1;
|
||||
else
|
||||
return v1.toLongLong() < v2.toLongLong() ? -1 : 1;
|
||||
}
|
||||
switch (v1.d.type) {
|
||||
case QVariant::Date:
|
||||
return v1.toDate() < v2.toDate() ? -1 : 1;
|
||||
case QVariant::Time:
|
||||
return v1.toTime() < v2.toTime() ? -1 : 1;
|
||||
case QVariant::DateTime:
|
||||
return v1.toDateTime() < v2.toDateTime() ? -1 : 1;
|
||||
}
|
||||
return v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -3052,7 +3162,14 @@ QDebug operator<<(QDebug dbg, const QVariant &v)
|
||||
dbg.nospace() << "QVariant(";
|
||||
if (typeId != QMetaType::UnknownType) {
|
||||
dbg.nospace() << QMetaType::typeName(typeId) << ", ";
|
||||
handlerManager[typeId]->debugStream(dbg, v);
|
||||
bool userStream = false;
|
||||
if (typeId >= QMetaType::User)
|
||||
userStream = QMetaType::debugStream(dbg, constData(v.d), typeId);
|
||||
bool canConvertToString = v.canConvert<QString>();
|
||||
if (!userStream && canConvertToString)
|
||||
dbg << v.toString();
|
||||
else if (!userStream)
|
||||
handlerManager[typeId]->debugStream(dbg, v);
|
||||
} else {
|
||||
dbg.nospace() << "Invalid";
|
||||
}
|
||||
|
@ -433,6 +433,14 @@ class Q_CORE_EXPORT QVariant
|
||||
{ return cmp(v); }
|
||||
inline bool operator!=(const QVariant &v) const
|
||||
{ return !cmp(v); }
|
||||
inline bool operator<(const QVariant &v) const
|
||||
{ return compare(v) < 0; }
|
||||
inline bool operator<=(const QVariant &v) const
|
||||
{ return compare(v) <= 0; }
|
||||
inline bool operator>(const QVariant &v) const
|
||||
{ return compare(v) > 0; }
|
||||
inline bool operator>=(const QVariant &v) const
|
||||
{ return compare(v) >= 0; }
|
||||
|
||||
protected:
|
||||
friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &);
|
||||
@ -450,6 +458,7 @@ public:
|
||||
Private d;
|
||||
void create(int type, const void *copy);
|
||||
bool cmp(const QVariant &other) const;
|
||||
int compare(const QVariant &other) const;
|
||||
bool convert(const int t, void *ptr) const;
|
||||
|
||||
private:
|
||||
|
@ -1,6 +1,7 @@
|
||||
CONFIG += testcase parallel_test
|
||||
TARGET = tst_qmetatype
|
||||
QT = core testlib
|
||||
INCLUDEPATH += $$PWD/../../../other/qvariant_common
|
||||
SOURCES = tst_qmetatype.cpp
|
||||
TESTDATA=./typeFlags.bin
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include <QtCore>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include "tst_qvariant_common.h"
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
@ -113,6 +115,9 @@ private slots:
|
||||
void constRefs();
|
||||
void convertCustomType_data();
|
||||
void convertCustomType();
|
||||
void compareCustomType_data();
|
||||
void compareCustomType();
|
||||
void customDebugStream();
|
||||
};
|
||||
|
||||
struct Foo { int i; };
|
||||
@ -1821,7 +1826,7 @@ struct CustomConvertibleType
|
||||
{
|
||||
explicit CustomConvertibleType(const QVariant &foo = QVariant()) : m_foo(foo) {}
|
||||
virtual ~CustomConvertibleType() {}
|
||||
QString toString() const { return QLatin1String("CustomConvertibleType::toString()"); }
|
||||
QString toString() const { return m_foo.toString(); }
|
||||
operator QPoint() const { return QPoint(12, 34); }
|
||||
template<typename To>
|
||||
To convert() const { return s_value.value<To>();}
|
||||
@ -1833,6 +1838,8 @@ struct CustomConvertibleType
|
||||
static bool s_ok;
|
||||
};
|
||||
|
||||
bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
|
||||
{ return lhs.m_foo < rhs.m_foo; }
|
||||
bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
|
||||
{ return lhs.m_foo == rhs.m_foo; }
|
||||
bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
|
||||
@ -1851,6 +1858,16 @@ struct CustomConvertibleType2
|
||||
QVariant m_foo;
|
||||
};
|
||||
|
||||
struct CustomDebugStreamableType
|
||||
{
|
||||
QString toString() const { return "test"; }
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&)
|
||||
{
|
||||
return dbg << "string-content";
|
||||
}
|
||||
|
||||
bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
|
||||
{ return lhs.m_foo == rhs.m_foo; }
|
||||
bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
|
||||
@ -1858,6 +1875,7 @@ bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2
|
||||
|
||||
Q_DECLARE_METATYPE(CustomConvertibleType);
|
||||
Q_DECLARE_METATYPE(CustomConvertibleType2);
|
||||
Q_DECLARE_METATYPE(CustomDebugStreamableType);
|
||||
|
||||
template<typename T, typename U>
|
||||
U convert(const T &t)
|
||||
@ -2097,6 +2115,73 @@ void tst_QMetaType::convertCustomType()
|
||||
QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo);
|
||||
}
|
||||
|
||||
void tst_QMetaType::compareCustomType_data()
|
||||
{
|
||||
QMetaType::registerComparators<CustomConvertibleType>();
|
||||
|
||||
QTest::addColumn<QVariantList>("unsorted");
|
||||
QTest::addColumn<QVariantList>("sorted");
|
||||
|
||||
QTest::newRow("int") << (QVariantList() << 37 << 458 << 1 << 243 << -4 << 383)
|
||||
<< (QVariantList() << -4 << 1 << 37 << 243 << 383 << 458);
|
||||
|
||||
QTest::newRow("dobule") << (QVariantList() << 4934.93 << 0.0 << 302.39 << -39.0)
|
||||
<< (QVariantList() << -39.0 << 0.0 << 302.39 << 4934.93);
|
||||
|
||||
QTest::newRow("QString") << (QVariantList() << "Hello" << "World" << "this" << "is" << "a" << "test")
|
||||
<< (QVariantList() << "a" << "Hello" << "is" << "test" << "this" << "World");
|
||||
|
||||
QTest::newRow("QTime") << (QVariantList() << QTime(14, 39) << QTime(0, 0) << QTime(18, 18) << QTime(9, 27))
|
||||
<< (QVariantList() << QTime(0, 0) << QTime(9, 27) << QTime(14, 39) << QTime(18, 18));
|
||||
|
||||
QTest::newRow("QDate") << (QVariantList() << QDate(2013, 3, 23) << QDate(1900, 12, 1) << QDate(2001, 2, 2) << QDate(1982, 12, 16))
|
||||
<< (QVariantList() << QDate(1900, 12, 1) << QDate(1982, 12, 16) << QDate(2001, 2, 2) << QDate(2013, 3, 23));
|
||||
|
||||
QTest::newRow("mixed") << (QVariantList() << "Hello" << "World" << QChar('a') << 38 << QChar('z') << -39 << 4.6)
|
||||
<< (QVariantList() << -39 << 4.6 << 38 << QChar('a') << "Hello" << "World" << QChar('z'));
|
||||
|
||||
QTest::newRow("custom") << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(100)) << QVariant::fromValue(CustomConvertibleType(50)))
|
||||
<< (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(50)) << QVariant::fromValue(CustomConvertibleType(100)));
|
||||
}
|
||||
|
||||
void tst_QMetaType::compareCustomType()
|
||||
{
|
||||
QFETCH(QVariantList, unsorted);
|
||||
QFETCH(QVariantList, sorted);
|
||||
qSort(unsorted);
|
||||
QCOMPARE(unsorted, sorted);
|
||||
}
|
||||
|
||||
struct MessageHandlerCustom : public MessageHandler
|
||||
{
|
||||
MessageHandlerCustom(const int typeId)
|
||||
: MessageHandler(typeId, handler)
|
||||
{}
|
||||
static void handler(QtMsgType, const QMessageLogContext &, const QString &msg)
|
||||
{
|
||||
QCOMPARE(msg.trimmed(), expectedMessage.trimmed());
|
||||
}
|
||||
static QString expectedMessage;
|
||||
};
|
||||
|
||||
QString MessageHandlerCustom::expectedMessage;
|
||||
|
||||
void tst_QMetaType::customDebugStream()
|
||||
{
|
||||
MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>());
|
||||
QVariant v1 = QVariant::fromValue(CustomDebugStreamableType());
|
||||
handler.expectedMessage = "QVariant(CustomDebugStreamableType, )";
|
||||
qDebug() << v1;
|
||||
|
||||
QMetaType::registerConverter<CustomDebugStreamableType, QString>(&CustomDebugStreamableType::toString);
|
||||
handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")";
|
||||
qDebug() << v1;
|
||||
|
||||
QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>();
|
||||
handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)";
|
||||
qDebug() << v1;
|
||||
}
|
||||
|
||||
// Compile-time test, it should be possible to register function pointer types
|
||||
class Undefined;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user