From 8a5a268a7726f3a404ca40bd311d6866e3620dc3 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 27 Jul 2014 03:00:13 +0200 Subject: [PATCH] refs #304, refs #307, refs #173 as preparation for GUI, name / variant pair * for a generic table and tree view * generic name pair models and view * Hash for variant --- .../models/namevariantpairlistmodel.cpp | 36 ++++ .../models/namevariantpairlistmodel.h | 45 +++++ src/blackgui/views/namevariantpairview.cpp | 32 ++++ src/blackgui/views/namevariantpairview.h | 32 ++++ src/blackmisc/blackmiscfreefunctions.cpp | 4 +- src/blackmisc/namevariantpair.cpp | 172 ++++++++++++++++++ src/blackmisc/namevariantpair.h | 113 ++++++++++++ src/blackmisc/namevariantpairlist.cpp | 39 ++++ src/blackmisc/namevariantpairlist.h | 46 +++++ src/blackmisc/variant.cpp | 132 +++++++++++++- src/blackmisc/variant.h | 65 +++++++ 11 files changed, 710 insertions(+), 6 deletions(-) create mode 100644 src/blackgui/models/namevariantpairlistmodel.cpp create mode 100644 src/blackgui/models/namevariantpairlistmodel.h create mode 100644 src/blackgui/views/namevariantpairview.cpp create mode 100644 src/blackgui/views/namevariantpairview.h create mode 100644 src/blackmisc/namevariantpair.cpp create mode 100644 src/blackmisc/namevariantpair.h create mode 100644 src/blackmisc/namevariantpairlist.cpp create mode 100644 src/blackmisc/namevariantpairlist.h diff --git a/src/blackgui/models/namevariantpairlistmodel.cpp b/src/blackgui/models/namevariantpairlistmodel.cpp new file mode 100644 index 000000000..6a0ac79b6 --- /dev/null +++ b/src/blackgui/models/namevariantpairlistmodel.cpp @@ -0,0 +1,36 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "namevariantpairlistmodel.h" +#include "blackmisc/blackmiscfreefunctions.h" + +using namespace BlackMisc; + +namespace BlackGui +{ + namespace Models + { + /* + * Constructor + */ + CNameVariantPairModel::CNameVariantPairModel(QObject *parent) : CListModelBase("ViewNameVariantPairList", parent) + { + this->m_columns.addColumn(CColumn("name", CNameVariantPair::IndexName)); + this->m_columns.addColumn(CColumn("value", CNameVariantPair::IndexVariant)); + + // default sort order + this->setSortColumnByPropertyIndex(CNameVariantPair::IndexName); + this->m_sortOrder = Qt::AscendingOrder; + + // force strings for translation in resource files + (void)QT_TRANSLATE_NOOP("ViewNameVariantPairList", "name"); + (void)QT_TRANSLATE_NOOP("ViewNameVariantPairList", "value"); + } + } +} diff --git a/src/blackgui/models/namevariantpairlistmodel.h b/src/blackgui/models/namevariantpairlistmodel.h new file mode 100644 index 000000000..77d400d10 --- /dev/null +++ b/src/blackgui/models/namevariantpairlistmodel.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2013 + * Swift Project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_NAMEVARIANTLISTMODEL_H +#define BLACKGUI_NAMEVARIANTLISTMODEL_H + +#include "blackmisc/namevariantpairlist.h" +#include "blackgui/models/listmodelbase.h" +#include +#include + +namespace BlackGui +{ + namespace Models + { + + /*! + * Simple model displaying name / variant values + */ + class CNameVariantPairModel : public CListModelBase + { + + public: + + //! Constructor + explicit CNameVariantPairModel(QObject *parent = nullptr); + + //! Constructor + explicit CNameVariantPairModel(const BlackMisc::CNameVariantPairList &nameValues, QObject *parent = nullptr); + + //! Destructor + virtual ~CNameVariantPairModel() {} + + }; + } +} +#endif // guard diff --git a/src/blackgui/views/namevariantpairview.cpp b/src/blackgui/views/namevariantpairview.cpp new file mode 100644 index 000000000..52cfb14f5 --- /dev/null +++ b/src/blackgui/views/namevariantpairview.cpp @@ -0,0 +1,32 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "namevariantpairview.h" +#include + +using namespace BlackMisc; +using namespace BlackGui::Models; + +namespace BlackGui +{ + namespace Views + { + CNameVariantPairView::CNameVariantPairView(QWidget *parent) : CViewBase(parent) + { + this->m_model = new CNameVariantPairModel(this); + this->setModel(this->m_model); // via QTableView + this->m_model->setSortColumnByPropertyIndex(BlackMisc::CNameVariantPair::IndexName); + if (this->m_model->hasValidSortColumn()) + this->horizontalHeader()->setSortIndicator( + this->m_model->getSortColumn(), + this->m_model->getSortOrder()); + this->horizontalHeader()->setStretchLastSection(true); + } + } +} diff --git a/src/blackgui/views/namevariantpairview.h b/src/blackgui/views/namevariantpairview.h new file mode 100644 index 000000000..a4d762def --- /dev/null +++ b/src/blackgui/views/namevariantpairview.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKGUI_NAMEVARIANTPAIRVIEW_H +#define BLACKGUI_NAMEVARIANTPAIRVIEW_H + +//! \file + +#include "viewbase.h" +#include "../models/namevariantpairlistmodel.h" + +namespace BlackGui +{ + namespace Views + { + //! User view + class CNameVariantPairView : public CViewBase + { + + public: + //! Constructor + explicit CNameVariantPairView(QWidget *parent = nullptr); + }; + } +} +#endif // guard diff --git a/src/blackmisc/blackmiscfreefunctions.cpp b/src/blackmisc/blackmiscfreefunctions.cpp index 38feebb37..8425ea7d1 100644 --- a/src/blackmisc/blackmiscfreefunctions.cpp +++ b/src/blackmisc/blackmiscfreefunctions.cpp @@ -12,6 +12,7 @@ #include "settingsblackmiscclasses.h" #include "hwallclasses.h" #include "indexvariantmap.h" +#include "namevariantpairlist.h" #include "variant.h" #include "statusmessagelist.h" #include "audioallclasses.h" @@ -144,6 +145,8 @@ void BlackMisc::registerMetadata() { CVariant::registerMetadata(); CIndexVariantMap::registerMetadata(); + CNameVariantPair::registerMetadata(); + CNameVariantPairList::registerMetadata(); CStatusMessage::registerMetadata(); CStatusMessageList::registerMetadata(); @@ -387,7 +390,6 @@ QVariant BlackMisc::complexQtTypeFromDbusArgument(const QDBusArgument &argument, */ size_t BlackMisc::heapSizeOf(const QMetaType &metaType) { - metaType.destroy(metaType.create()); // ignore one-off allocations of a class being instantiated for the first time _CrtMemState oldState, newState, diff; oldState.lTotalCount = newState.lTotalCount = diff.lTotalCount = 0; // avoid compiler warning diff --git a/src/blackmisc/namevariantpair.cpp b/src/blackmisc/namevariantpair.cpp new file mode 100644 index 000000000..f9b6487b5 --- /dev/null +++ b/src/blackmisc/namevariantpair.cpp @@ -0,0 +1,172 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "namevariantpair.h" +#include "blackmisc/blackmiscfreefunctions.h" + +namespace BlackMisc +{ + + /* + * Constructor + */ + CNameVariantPair::CNameVariantPair(const QString &name, const CVariant &variant) + : m_name(name), m_variant(variant) + { } + + /* + * Convert to string + */ + QString CNameVariantPair::convertToQString(bool i18n) const + { + QString s(this->m_name); + s.append(" ").append(this->m_variant.toString(i18n)); + return s; + } + + /* + * Marshall to DBus + */ + void CNameVariantPair::marshallToDbus(QDBusArgument &argument) const + { + argument << TupleConverter::toTuple(*this); + } + + /* + * Unmarshall from DBus + */ + void CNameVariantPair::unmarshallFromDbus(const QDBusArgument &argument) + { + argument >> TupleConverter::toTuple(*this); + } + + /* + * Equal? + */ + bool CNameVariantPair::operator ==(const CNameVariantPair &other) const + { + if (this == &other) return true; + return TupleConverter::toTuple(*this) == TupleConverter::toTuple(other); + } + + /* + * Unequal? + */ + bool CNameVariantPair::operator !=(const CNameVariantPair &other) const + { + return !((*this) == other); + } + + /* + * Hash + */ + uint CNameVariantPair::getValueHash() const + { + return qHash(TupleConverter::toTuple(*this)); + } + + /* + * metaTypeId + */ + int CNameVariantPair::getMetaTypeId() const + { + return qMetaTypeId(); + } + + /* + * is a + */ + bool CNameVariantPair::isA(int metaTypeId) const + { + if (metaTypeId == qMetaTypeId()) { return true; } + return this->CValueObject::isA(metaTypeId); + } + + /* + * Compare + */ + int CNameVariantPair::compareImpl(const CValueObject &otherBase) const + { + const auto &other = static_cast(otherBase); + return compare(TupleConverter::toTuple(*this), TupleConverter::toTuple(other)); + } + + /* + * Property by index + */ + QVariant CNameVariantPair::propertyByIndex(int index) const + { + switch (index) + { + case IndexName: + return QVariant(this->m_name); + case IndexVariant: + return this->m_variant.toQVariant(); + default: + break; + } + + Q_ASSERT_X(false, "CNameVariantPair", "index unknown"); + QString m = QString("no property, index ").append(QString::number(index)); + return QVariant::fromValue(m); + } + + /* + * Property by index (setter) + */ + void CNameVariantPair::setPropertyByIndex(const QVariant &variant, int index) + { + switch (index) + { + case IndexName: + this->setName(variant.value()); + break; + case IndexVariant: + this->m_variant = variant; + break; + default: + Q_ASSERT_X(false, "CNameVariantPair", "index unknown"); + break; + } + } + + /* + * Register metadata + */ + void CNameVariantPair::registerMetadata() + { + qRegisterMetaType(); + qDBusRegisterMetaType(); + } + + /* + * To JSON + */ + QJsonObject CNameVariantPair::toJson() const + { + return BlackMisc::serializeJson(TupleConverter::toMetaTuple(*this)); + } + + /* + * From JSON + */ + void CNameVariantPair::fromJson(const QJsonObject &json) + { + BlackMisc::deserializeJson(json, TupleConverter::toMetaTuple(*this)); + } + + /* + * Members + */ + const QStringList &CNameVariantPair::jsonMembers() + { + return TupleConverter::jsonMembers(); + } + +} // namespace diff --git a/src/blackmisc/namevariantpair.h b/src/blackmisc/namevariantpair.h new file mode 100644 index 000000000..81d6dbc25 --- /dev/null +++ b/src/blackmisc/namevariantpair.h @@ -0,0 +1,113 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_NAMEVARIANTPAIR_H +#define BLACKMISC_NAMEVARIANTPAIR_H + +#include "variant.h" +#include "valueobject.h" + +namespace BlackMisc +{ + /*! + * Value / variant pair + */ + class CNameVariantPair : public BlackMisc::CValueObject + { + public: + //! Default constructor. + CNameVariantPair() {} + + //! Constructor. + CNameVariantPair(const QString &name, const CVariant &variant); + + //! \copydoc CValueObject::toQVariant + virtual QVariant toQVariant() const override + { + return QVariant::fromValue(*this); + } + + //! Get name. + const QString &getName() const { return m_name; } + + //! Get variant. + CVariant getVariant() const { return m_variant; } + + //! Set name. + void setName(const QString &name) { this->m_name = name; } + + //! Set variant. + void setVariant(const CVariant &variant) { m_variant = variant; } + + //! Equal operator == + bool operator ==(const CNameVariantPair &other) const; + + //! Unequal operator != + bool operator !=(const CNameVariantPair &other) const; + + //! \copydoc CValueObject::getValueHash + virtual uint getValueHash() const override; + + //! \copydoc CValueObject::toJson + virtual QJsonObject toJson() const override; + + //! \copydoc CValueObject::fromJson + virtual void fromJson(const QJsonObject &json) override; + + //! Register metadata + static void registerMetadata(); + + //! Members + static const QStringList &jsonMembers(); + + //! Properties by index + enum ColumnIndex + { + IndexName = 0, + IndexVariant, + }; + + //! \copydoc CValueObject::propertyByIndex() + virtual QVariant propertyByIndex(int index) const override; + + //! \copydoc CValueObject::setPropertyByIndex(variant, index) + virtual void setPropertyByIndex(const QVariant &variant, int index) override; + + protected: + //! \copydoc CValueObject::convertToQString() + virtual QString convertToQString(bool i18n = false) const override; + + //! \copydoc CValueObject::getMetaTypeId + virtual int getMetaTypeId() const override; + + //! \copydoc CValueObject::isA + virtual bool isA(int metaTypeId) const override; + + //! \copydoc CValueObject::compareImpl + virtual int compareImpl(const CValueObject &other) const override; + + //! \copydoc CValueObject::marshallToDbus() + virtual void marshallToDbus(QDBusArgument &argument) const override; + + //! \copydoc CValueObject::marshallFromDbus() + virtual void unmarshallFromDbus(const QDBusArgument &argument) override; + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CNameVariantPair) + QString m_name; + CVariant m_variant; + }; +} // namespace + +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::CNameVariantPair, (o.m_name, o.m_variant)) +Q_DECLARE_METATYPE(BlackMisc::CNameVariantPair) + +#endif // guard diff --git a/src/blackmisc/namevariantpairlist.cpp b/src/blackmisc/namevariantpairlist.cpp new file mode 100644 index 000000000..2d54cd551 --- /dev/null +++ b/src/blackmisc/namevariantpairlist.cpp @@ -0,0 +1,39 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "namevariantpairlist.h" +#include "predicates.h" + +namespace BlackMisc +{ + /* + * Empty constructor + */ + CNameVariantPairList::CNameVariantPairList() { } + + /* + * Construct from base class object + */ + CNameVariantPairList::CNameVariantPairList(const CSequence &other) : + CSequence(other) + { } + + /* + * Register metadata + */ + void CNameVariantPairList::registerMetadata() + { + qRegisterMetaType>(); + qDBusRegisterMetaType>(); + qRegisterMetaType>(); + qDBusRegisterMetaType>(); + qRegisterMetaType(); + qDBusRegisterMetaType(); + } +} // namespace diff --git a/src/blackmisc/namevariantpairlist.h b/src/blackmisc/namevariantpairlist.h new file mode 100644 index 000000000..dfce8d6e5 --- /dev/null +++ b/src/blackmisc/namevariantpairlist.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_NAMEVARIANPAIRTLIST_H +#define BLACKMISC_NAMEVARIANPAIRTLIST_H + +#include "namevariantpair.h" +#include "collection.h" +#include "sequence.h" + +namespace BlackMisc +{ + /*! + * Value object encapsulating a list of name/variant pairs. + */ + class CNameVariantPairList : public CSequence + { + public: + //! Default constructor. + CNameVariantPairList(); + + //! Construct from a base class object. + CNameVariantPairList(const CSequence &other); + + //! CValueObject::toQVariant() + virtual QVariant toQVariant() const override { return QVariant::fromValue(*this); } + + //! Register metadata + static void registerMetadata(); + + }; +} //namespace + +Q_DECLARE_METATYPE(BlackMisc::CNameVariantPairList) +Q_DECLARE_METATYPE(BlackMisc::CCollection) +Q_DECLARE_METATYPE(BlackMisc::CSequence) + +#endif //guard diff --git a/src/blackmisc/variant.cpp b/src/blackmisc/variant.cpp index 8463ba544..fd83f2b1f 100644 --- a/src/blackmisc/variant.cpp +++ b/src/blackmisc/variant.cpp @@ -1,7 +1,11 @@ -/* Copyright (C) 2014 VATSIM Community / authors - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* Copyright (C) 2013 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ #include "variant.h" #include "blackmiscfreefunctions.h" @@ -23,14 +27,131 @@ namespace BlackMisc if (type() == QVariant::UserType) { const CValueObject *s = CValueObject::fromQVariant(m_v); // FIXME this will return garbage if value is not a CValueObject + Q_ASSERT(s); if (s) { return s->toQString(i18n); } + else + { + return "No CValueObject, no string conversion"; + } } return m_v.toString(); } + QJsonObject CVariant::toJson() const + { + QJsonObject json; + json.insert("type", static_cast(this->type())); // type + json.insert("usertype", this->userType()); // user type + json.insert("typename", this->typeName()); // as tring, mainly for debugging, readablity + json.insert("value", this->toString(false)); + return json; + } + + void CVariant::fromJson(const QJsonObject &json) + { + int type = json.value("type").toInt(-1); + int userType = json.value("usertype").toInt(-1); + QString typeName = json.value("typename").toString(); + QString value = json.value("value").toString(); + + // KB: Not yet implemented, but would be possible IMHO + Q_ASSERT(false); + qDebug() << type << userType << typeName << value; + } + + uint CVariant::getValueHash() const + { + uint h = 0; + if (!this->isValid() || this->isNull()) + { + QString hs; + hs.sprintf("%p", this); + h = ::qHash(hs); + } + else + { + QVariant qv = this->toQVariant(); + switch (qv.type()) + { + case QVariant::Int: + h = ::qHash(qv.toInt()); + break; + case QVariant::UInt: + h = ::qHash(qv.toUInt()); + break; + case QVariant::Bool: + h = ::qHash(qv.toUInt()); + break; + case QVariant::Double: + h = ::qHash(qv.toUInt()); + break; + case QVariant::LongLong: + h = ::qHash(qv.toLongLong()); + break; + case QVariant::ULongLong: + h = ::qHash(qv.toULongLong()); + break; + case QVariant::String: + h = ::qHash(qv.toString()); + break; + case QVariant::Char: + h = ::qHash(qv.toChar()); + break; + case QVariant::StringList: + h = ::qHash(qv.toString()); + break; + case QVariant::ByteArray: + h = ::qHash(qv.toByteArray()); + break; + case QVariant::Date: + case QVariant::Time: + case QVariant::DateTime: + case QVariant::Url: + case QVariant::Locale: + case QVariant::RegExp: + h = ::qHash(qv.toString()); + break; + case QVariant::Map: + case QVariant::List: + case QVariant::BitArray: + case QVariant::Size: + case QVariant::SizeF: + case QVariant::Rect: + case QVariant::LineF: + case QVariant::Line: + case QVariant::RectF: + case QVariant::Point: + case QVariant::PointF: + case QVariant::UserType: + case QVariant::Invalid: + h = 2; // known, but not supported + break; + default: + { + // value object? + const QVariant qv = this->toQVariant(); + const CValueObject *cv = CValueObject::fromQVariant(qv); + if (cv) + { + h = cv->getValueHash(); + } + else + { + // no value object + QString hs; + hs.sprintf("%p", this); + h = ::qHash(hs); + } + } + break; + } + } + return h; + } + QDBusArgument &operator <<(QDBusArgument &arg, const CVariant &var) { arg.beginStructure(); @@ -51,4 +172,5 @@ namespace BlackMisc return arg; } -} // namespace \ No newline at end of file + +} // namespace diff --git a/src/blackmisc/variant.h b/src/blackmisc/variant.h index a03338c47..a5361b373 100644 --- a/src/blackmisc/variant.h +++ b/src/blackmisc/variant.h @@ -14,11 +14,16 @@ #include #include +#include +#include +#include +#include class QDBusArgument; namespace BlackMisc { + // KB: Would it make sense to turn CVariant into an CValueObject? #307 /*! * Wrapper class for QVariant, for more natural and transparent DBus integration. @@ -47,6 +52,9 @@ namespace BlackMisc //! Construct a variant from the given type and opaque pointer. CVariant(int typeId, const void *copy) : m_v(typeId, copy) {} + //! Value hash + uint getValueHash() const; + //! Change the internal QVariant. void reset(const QVariant &var) { m_v = var; } @@ -134,6 +142,12 @@ namespace BlackMisc //! Return the metatype ID of the value in this variant. int userType() const { return m_v.userType(); } + //! To JSON + QJsonObject toJson() const; + + //! From JSON + void fromJson(const QJsonObject &json); + //! Equal operator. bool operator ==(const CVariant &other) const { return m_v == other.m_v; } @@ -165,6 +179,57 @@ namespace BlackMisc //! Unmarshall a variant from DBus. const QDBusArgument &operator >>(const QDBusArgument &arg, CVariant &var); + //! Non member, non friend operator >> for JSON + inline QJsonArray &operator<<(QJsonArray &json, const BlackMisc::CVariant &variant) + { + json.append(variant.toJson()); + return json; + } + + /*! + * \brief Non member, non friend operator << for JSON + * \param json + * \param value as pair name/value + * \return + */ + inline QJsonObject &operator<<(QJsonObject &json, const std::pair &value) + { + json.insert(value.first, QJsonValue(value.second.toJson())); + return json; + } + + //! Non member, non friend operator >> for JSON + inline const QJsonObject &operator>>(const QJsonObject &json, BlackMisc::CVariant &variant) + { + variant.fromJson(json); + return json; + } + + //! Non member, non friend operator >> for JSON + inline const QJsonValue &operator>>(const QJsonValue &json, BlackMisc::CVariant &variant) + { + variant.fromJson(json.toObject()); + return json; + } + + //! Non member, non friend operator >> for JSON + inline const QJsonValueRef &operator>>(const QJsonValueRef &json, BlackMisc::CVariant &variant) + { + variant.fromJson(json.toObject()); + return json; + } + + //! qHash overload, needed for storing CVariant with tupel system + inline uint qHash(const BlackMisc::CVariant &value, uint seed = 0) + { + return ::qHash(value.getValueHash(), seed); + } + + // Needed so that our qHash overload doesn't hide the qHash overloads in the global namespace. + // This will be safe as long as no global qHash has the same signature as ours. + // Alternative would be to qualify all our invokations of the global qHash as ::qHash. + using ::qHash; + } // namespace Q_DECLARE_METATYPE(BlackMisc::CVariant)