mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-02 23:25:53 +08:00
refs #413 Breaking circular dependencies by moving mixin classes from valueobject.h to the files where they fit best:
* DBus mixins moved to dbus.h * Json mixins moved to json.h * Icon mixin moved to icon.h * Comparison mixins moved to compare.h * Hash and string mixins moved to blackmiscfreefunctions.h * Index mixin moved to propertyindexvariantmap.h * MetaType mixins moved to variant.h * registerMetaValueType moved to variant.h * valueobject_private.h renamed to variant_private.h
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "blackmisc/icons.h"
|
||||
#include "blackmisc/worker.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include <QTableView>
|
||||
#include <QWizardPage>
|
||||
#include <QHeaderView>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
//! \file
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/valueobject.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
#include <QString>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define BLACKMISC_AVIATION_AIRCRAFTICAO_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/valueobject.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace BlackMisc
|
||||
switch (i)
|
||||
{
|
||||
case IndexEngines:
|
||||
this->m_engines.setPropertyByIndex(variant, index.copyFrontRemoved());
|
||||
this->m_engines = variant.to<decltype(this->m_engines)>();
|
||||
break;
|
||||
case IndexFlapsPercentage:
|
||||
this->m_flapsPercentage = variant.toInt();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define BLACKMISC_AVIATION_CALLSIGN_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/valueobject.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/icon.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define BLACKMISC_FREEFUNCTIONS_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/tuple.h"
|
||||
#include "blackmisc/inheritance_traits.h"
|
||||
#include <QDir> // for Q_INIT_RESOURCE
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
@@ -111,6 +113,103 @@ namespace BlackMisc
|
||||
//! Init resources
|
||||
BLACKMISC_EXPORT void initResources();
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class HashByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! qHash overload, needed for storing value in a QSet.
|
||||
friend uint qHash(const Derived &value, uint seed = 0)
|
||||
{
|
||||
return ::qHash(hashImpl(value), seed);
|
||||
}
|
||||
|
||||
private:
|
||||
static uint hashImpl(const Derived &value)
|
||||
{
|
||||
return BlackMisc::qHash(toMetaTuple(value)) ^ baseHash(static_cast<const BaseOfT<Derived> *>(&value));
|
||||
}
|
||||
|
||||
template <typename T> static uint baseHash(const T *base) { return qHash(*base); }
|
||||
static uint baseHash(const void *) { return 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit string streaming operations.
|
||||
*/
|
||||
template <class Derived>
|
||||
class String
|
||||
{
|
||||
public:
|
||||
//! Stream << overload to be used in debugging messages
|
||||
friend QDebug operator<<(QDebug debug, const Derived &obj)
|
||||
{
|
||||
debug << obj.stringForStreaming();
|
||||
return debug;
|
||||
}
|
||||
|
||||
//! Operator << when there is no debug stream
|
||||
friend QNoDebug operator<<(QNoDebug nodebug, const Derived &obj)
|
||||
{
|
||||
Q_UNUSED(obj);
|
||||
return nodebug;
|
||||
}
|
||||
|
||||
//! Operator << based on text stream
|
||||
friend QTextStream &operator<<(QTextStream &stream, const Derived &obj)
|
||||
{
|
||||
stream << obj.stringForStreaming();
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Operator << for QDataStream
|
||||
friend QDataStream &operator<<(QDataStream &stream, const Derived &obj)
|
||||
{
|
||||
stream << obj.stringForStreaming();
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Stream operator << for std::cout
|
||||
friend std::ostream &operator<<(std::ostream &ostr, const Derived &obj)
|
||||
{
|
||||
ostr << obj.stringForStreaming().toStdString();
|
||||
return ostr;
|
||||
}
|
||||
|
||||
//! Cast as QString
|
||||
QString toQString(bool i18n = false) const { return derived()->convertToQString(i18n); }
|
||||
|
||||
//! Cast to pretty-printed QString
|
||||
QString toFormattedQString(bool i18n = false) const { return derived()->toQString(i18n); }
|
||||
|
||||
//! To std string
|
||||
std::string toStdString(bool i18n = false) const { return derived()->convertToQString(i18n).toStdString(); }
|
||||
|
||||
//! String for streaming operators
|
||||
QString stringForStreaming() const { return derived()->convertToQString(); }
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::String,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_STRING(DERIVED) \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toFormattedQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toStdString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::stringForStreaming;
|
||||
|
||||
} // Mixin
|
||||
|
||||
//! Checked version from QVariant
|
||||
template <class T> void setFromQVariant(T *value, const QVariant &variant)
|
||||
{
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_COLLECTION_H
|
||||
#define BLACKMISC_COLLECTION_H
|
||||
|
||||
|
||||
132
src/blackmisc/compare.h
Normal file
132
src/blackmisc/compare.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* Copyright (C) 2015
|
||||
* 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_COMPARE_H
|
||||
#define BLACKMISC_COMPARE_H
|
||||
|
||||
#include "blackmisc/tuple.h"
|
||||
#include "blackmisc/inheritance_traits.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator== implemented using its compare function.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByCompare
|
||||
{
|
||||
public:
|
||||
//! Equals
|
||||
friend bool operator ==(const Derived &a, const Derived &b) { return compare(a, b) == 0; }
|
||||
|
||||
//! Not equal
|
||||
friend bool operator !=(const Derived &a, const Derived &b) { return compare(a, b) != 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator== implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Equals
|
||||
friend bool operator ==(const Derived &a, const Derived &b) { return equals(a, b); }
|
||||
|
||||
//! Not equal
|
||||
friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); }
|
||||
|
||||
private:
|
||||
static bool equals(const Derived &a, const Derived &b)
|
||||
{
|
||||
return toMetaTuple(a) == toMetaTuple(b) && baseEquals(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
|
||||
}
|
||||
template <typename T> static bool baseEquals(const T *a, const T *b) { return *a == *b; }
|
||||
static bool baseEquals(const void *, const void *) { return true; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented using its compare function.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByCompare
|
||||
{
|
||||
public:
|
||||
//! Less than
|
||||
friend bool operator <(const Derived &a, const Derived &b) { return compare(a, b) < 0; }
|
||||
|
||||
//! Greater than
|
||||
friend bool operator >(const Derived &a, const Derived &b) { return compare(a, b) > 0; }
|
||||
|
||||
//! Less than or equal
|
||||
friend bool operator <=(const Derived &a, const Derived &b) { return compare(a, b) <= 0; }
|
||||
|
||||
//! Greater than or equal
|
||||
friend bool operator >=(const Derived &a, const Derived &b) { return compare(a, b) >= 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Less than
|
||||
friend bool operator <(const Derived &a, const Derived &b) { return less(a, b); }
|
||||
|
||||
//! Greater than
|
||||
friend bool operator >(const Derived &a, const Derived &b) { return less(b, a); }
|
||||
|
||||
//! Less than or equal
|
||||
friend bool operator <=(const Derived &a, const Derived &b) { return ! less(b, a); }
|
||||
|
||||
//! Greater than or equal
|
||||
friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); }
|
||||
|
||||
private:
|
||||
static bool less(const Derived &a, const Derived &b)
|
||||
{
|
||||
if (baseLess(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b))) { return true; }
|
||||
return toMetaTuple(a) < toMetaTuple(b);
|
||||
}
|
||||
template <typename T> static bool baseLess(const T *a, const T *b) { return *a < *b; }
|
||||
static bool baseLess(const void *, const void *) { return false; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit non-member compare() implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class CompareByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Return negative, zero, or positive if a is less than, equal to, or greater than b.
|
||||
friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); }
|
||||
|
||||
private:
|
||||
static int compareImpl(const Derived &a, const Derived &b)
|
||||
{
|
||||
int baseCmp = baseCompare(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
|
||||
if (baseCmp) { return baseCmp; }
|
||||
return BlackMisc::compare(toMetaTuple(a), toMetaTuple(b));
|
||||
}
|
||||
template <typename T> static int baseCompare(const T *a, const T *b) { return compare(*a, *b); }
|
||||
static int baseCompare(const void *, const void *) { return 0; }
|
||||
};
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "blackmiscfreefunctions.h"
|
||||
#include "predicates.h"
|
||||
#include "json.h"
|
||||
#include "variant.h"
|
||||
#include "dbus.h"
|
||||
#include "icon.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace BlackMisc
|
||||
@@ -51,7 +54,6 @@ namespace BlackMisc
|
||||
public Mixin::DBusOperators<C<T>>,
|
||||
public Mixin::JsonOperators<C<T>>,
|
||||
public Mixin::String<C<T>>,
|
||||
public Mixin::Index<C<T>>,
|
||||
public Mixin::Icon<C<T>>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -12,9 +12,86 @@
|
||||
#ifndef BLACKMISC_DBUS_H
|
||||
#define BLACKMISC_DBUS_H
|
||||
|
||||
#include "blackmisc/tuple.h"
|
||||
#include "blackmisc/inheritance_traits.h"
|
||||
#include <QDBusArgument>
|
||||
#include <type_traits>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*/
|
||||
template <class Derived>
|
||||
class DBusOperators
|
||||
{
|
||||
public:
|
||||
//! Unmarshalling operator >>, DBus to object
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &arg, Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.unmarshallFromDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
//! Marshalling operator <<, object to DBus
|
||||
friend QDBusArgument &operator<<(QDBusArgument &arg, const Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.marshallToDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class DBusByTuple : public DBusOperators<Derived>, private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Marshall without begin/endStructure, for when composed within another object
|
||||
void marshallToDbus(QDBusArgument &arg) const
|
||||
{
|
||||
baseMarshall(static_cast<const BaseOfT<Derived> *>(derived()), arg);
|
||||
using BlackMisc::operator<<;
|
||||
arg << Private::EncapsulationBreaker::toMetaTuple(*derived());
|
||||
}
|
||||
|
||||
//! Unmarshall without begin/endStructure, for when composed within another object
|
||||
void unmarshallFromDbus(const QDBusArgument &arg)
|
||||
{
|
||||
baseUnmarshall(static_cast<BaseOfT<Derived> *>(derived()), arg);
|
||||
using BlackMisc::operator>>;
|
||||
arg >> Private::EncapsulationBreaker::toMetaTuple(*derived());
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg); }
|
||||
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg); }
|
||||
static void baseMarshall(const void *, QDBusArgument &) {}
|
||||
static void baseUnmarshall(void *, const QDBusArgument &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::DBusByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_DBUS(DERIVED) \
|
||||
using ::BlackMisc::Mixin::DBusByTuple<DERIVED>::marshallToDbus; \
|
||||
using ::BlackMisc::Mixin::DBusByTuple<DERIVED>::unmarshallFromDbus;
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
/*!
|
||||
* Non-member non-friend operator for streaming enums to QDBusArgument.
|
||||
*
|
||||
@@ -31,4 +108,5 @@ operator>>(const QDBusArgument &argument, ENUM &enumType)
|
||||
enumType = static_cast<ENUM>(e);
|
||||
return argument;
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/valueobject.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
#include <QStringList>
|
||||
#include <QKeySequence>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "blackmiscexport.h"
|
||||
#include "propertyindex.h"
|
||||
#include "valueobject.h"
|
||||
#include "blackmiscfreefunctions.h"
|
||||
|
||||
namespace BlackMisc
|
||||
|
||||
@@ -9,25 +9,66 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_ICON_H
|
||||
#define BLACKMISC_ICON_H
|
||||
|
||||
#include "blackmiscexport.h"
|
||||
#include "icons.h"
|
||||
#include "variant.h"
|
||||
#include "tuple.h"
|
||||
#include "inheritance_traits.h"
|
||||
#include <QIcon>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CIcon;
|
||||
|
||||
namespace PhysicalQuantities
|
||||
{
|
||||
class CAngle;
|
||||
}
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit icon-related functions.
|
||||
*/
|
||||
template <class Derived, CIcons::IconIndex IconIndex = CIcons::StandardIconUnknown16>
|
||||
class Icon
|
||||
{
|
||||
public:
|
||||
//! As icon, not implemented by all classes
|
||||
CIcon toIcon() const;
|
||||
|
||||
//! As pixmap, required for most GUI views
|
||||
QPixmap toPixmap() const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::Icon,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_ICON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toIcon; \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toPixmap;
|
||||
} // Mixin
|
||||
|
||||
//! Value object for icons. An icon is stored in the global icon repository and
|
||||
//! identified by its index. It contains no(!) pyhsical data for the icon itself.
|
||||
class BLACKMISC_EXPORT CIcon : public CValueObject<CIcon>
|
||||
class BLACKMISC_EXPORT CIcon :
|
||||
public Mixin::MetaType<CIcon>,
|
||||
public Mixin::HashByTuple<CIcon>,
|
||||
public Mixin::DBusByTuple<CIcon>,
|
||||
public Mixin::JsonByTuple<CIcon>,
|
||||
public Mixin::EqualsByTuple<CIcon>,
|
||||
public Mixin::LessThanByTuple<CIcon>,
|
||||
public Mixin::CompareByTuple<CIcon>,
|
||||
public Mixin::String<CIcon>,
|
||||
public Mixin::Icon<CIcon>
|
||||
{
|
||||
public:
|
||||
//! Default constructor.
|
||||
@@ -85,6 +126,20 @@ namespace BlackMisc
|
||||
//! \private Needed so we can copy forward-declared CIcon.
|
||||
inline void assign(CIcon &a, const CIcon &b) { a = b; }
|
||||
}
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
template <class Derived, CIcons::IconIndex IconIndex>
|
||||
CIcon Icon<Derived, IconIndex>::toIcon() const
|
||||
{
|
||||
return CIcon::iconByIndex(IconIndex);
|
||||
}
|
||||
template <class Derived, CIcons::IconIndex IconIndex>
|
||||
QPixmap Icon<Derived, IconIndex>::toPixmap() const
|
||||
{
|
||||
return derived()->toIcon().toPixmap();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::CIcon, (o.m_index, o.m_descriptiveText))
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_ICONLIST_H
|
||||
#define BLACKMISC_ICONLIST_H
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#ifndef BLACKMISC_JSON_H
|
||||
#define BLACKMISC_JSON_H
|
||||
|
||||
#include "blackmiscexport.h"
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/tuple.h"
|
||||
#include "blackmisc/inheritance_traits.h"
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonValueRef>
|
||||
@@ -113,6 +115,7 @@ namespace BlackMisc
|
||||
{
|
||||
namespace Json
|
||||
{
|
||||
|
||||
//! \brief Append to first JSON object (concatenate)
|
||||
//! \ingroup JSON
|
||||
inline QJsonObject &appendJsonObject(QJsonObject &target, const QJsonObject &toBeAppended)
|
||||
@@ -125,7 +128,95 @@ namespace BlackMisc
|
||||
}
|
||||
return target;
|
||||
}
|
||||
} // ns
|
||||
} // ns
|
||||
|
||||
} // Json
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonOperators
|
||||
{
|
||||
public:
|
||||
//! operator >> for JSON
|
||||
friend const QJsonObject &operator>>(const QJsonObject &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json);
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend const QJsonValue &operator>>(const QJsonValue &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend const QJsonValueRef &operator>>(const QJsonValueRef &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonArray &operator<<(QJsonArray &json, const Derived &obj)
|
||||
{
|
||||
json.append(obj.toJson());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const Derived &> &value)
|
||||
{
|
||||
json.insert(value.first, QJsonValue(value.second.toJson()));
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonByTuple : public JsonOperators<Derived>, private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Cast to JSON object
|
||||
QJsonObject toJson() const
|
||||
{
|
||||
QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived()));
|
||||
return Json::appendJsonObject(json, baseToJson(static_cast<const BaseOfT<Derived> *>(derived())));
|
||||
}
|
||||
|
||||
//! Assign from JSON object
|
||||
void convertFromJson(const QJsonObject &json)
|
||||
{
|
||||
baseConvertFromJson(static_cast<BaseOfT<Derived> *>(derived()), json);
|
||||
BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived()));
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T> static QJsonObject baseToJson(const T *base) { return base->toJson(); }
|
||||
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); }
|
||||
static QJsonObject baseToJson(const void *) { return {}; }
|
||||
static void baseConvertFromJson(void *, const QJsonObject &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::JsonByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_JSON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::JsonByTuple<DERIVED>::toJson; \
|
||||
using ::BlackMisc::Mixin::JsonByTuple<DERIVED>::convertFromJson;
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
//! \file
|
||||
|
||||
#include "blackmiscexport.h"
|
||||
#include "valueobject.h"
|
||||
#include "sequence.h"
|
||||
|
||||
namespace BlackMisc
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_PROPERTYINDEX_H
|
||||
#define BLACKMISC_PROPERTYINDEX_H
|
||||
|
||||
#include "blackmiscexport.h"
|
||||
#include "blackmiscfreefunctions.h"
|
||||
#include "variant.h"
|
||||
#include "dbus.h"
|
||||
#include "json.h"
|
||||
#include "compare.h"
|
||||
#include <initializer_list>
|
||||
|
||||
namespace BlackMisc
|
||||
@@ -25,7 +27,15 @@ namespace BlackMisc
|
||||
* Property index. The index can be nested, that's why it is a sequence
|
||||
* (e.g. PropertyIndexPilot, PropertyIndexRealname).
|
||||
*/
|
||||
class BLACKMISC_EXPORT CPropertyIndex : public CValueObject<CPropertyIndex>
|
||||
class BLACKMISC_EXPORT CPropertyIndex :
|
||||
public Mixin::MetaType<CPropertyIndex>,
|
||||
public Mixin::HashByTuple<CPropertyIndex>,
|
||||
public Mixin::DBusByTuple<CPropertyIndex>,
|
||||
public Mixin::JsonByTuple<CPropertyIndex>,
|
||||
public Mixin::EqualsByTuple<CPropertyIndex>,
|
||||
public Mixin::LessThanByTuple<CPropertyIndex>,
|
||||
public Mixin::CompareByTuple<CPropertyIndex>,
|
||||
public Mixin::String<CPropertyIndex>
|
||||
{
|
||||
// In the first trial I have used CSequence<int> as base class
|
||||
// This has created too much circular dependencies of the headers
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_PROPERTYINDEXLIST_H
|
||||
#define BLACKMISC_PROPERTYINDEXLIST_H
|
||||
|
||||
|
||||
@@ -13,15 +13,57 @@
|
||||
#define BLACKMISC_PROPERTYINDEXVARIANTMAP_H
|
||||
|
||||
#include "variant.h"
|
||||
#include "valueobject.h"
|
||||
#include "propertyindexlist.h"
|
||||
#include "blackmiscexport.h"
|
||||
#include "tuple.h"
|
||||
#include "inheritance_traits.h"
|
||||
#include <QVariantMap>
|
||||
#include <QDBusArgument>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
|
||||
class CPropertyIndexVariantMap;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit property indexing functions.
|
||||
*/
|
||||
template <class Derived>
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
//! Base class enums
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexPixmap = 10, // manually set to avoid circular dependencies
|
||||
IndexIcon,
|
||||
IndexString
|
||||
};
|
||||
|
||||
//! Update by variant map
|
||||
//! \return number of values changed, with skipEqualValues equal values will not be changed
|
||||
CPropertyIndexList apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues = false);
|
||||
|
||||
//! Set property by index
|
||||
void setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index);
|
||||
|
||||
//! Property by index
|
||||
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
|
||||
|
||||
//! Property by index as String
|
||||
QString propertyByIndexAsString(const CPropertyIndex &index, bool i18n = false) const;
|
||||
|
||||
//! Is given variant equal to value of property index?
|
||||
bool equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
} // Mixin
|
||||
|
||||
/*!
|
||||
* Specialized value object compliant map for variants,
|
||||
* based on indexes
|
||||
@@ -29,9 +71,7 @@ namespace BlackMisc
|
||||
class BLACKMISC_EXPORT CPropertyIndexVariantMap :
|
||||
public Mixin::MetaType<CPropertyIndexVariantMap>,
|
||||
public Mixin::DBusOperators<CPropertyIndexVariantMap>,
|
||||
public Mixin::Index<CPropertyIndexVariantMap>,
|
||||
public Mixin::String<CPropertyIndexVariantMap>,
|
||||
public Mixin::Icon<CPropertyIndexVariantMap>
|
||||
public Mixin::String<CPropertyIndexVariantMap>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
@@ -155,6 +195,81 @@ namespace BlackMisc
|
||||
//! \copydoc CValueObject::unmarshallFromDbus
|
||||
void unmarshallFromDbus(const QDBusArgument &argument);
|
||||
};
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
template <class Derived>
|
||||
CPropertyIndexList Index<Derived>::apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues)
|
||||
{
|
||||
if (indexMap.isEmpty()) return {};
|
||||
|
||||
CPropertyIndexList changed;
|
||||
const auto &map = indexMap.map();
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
const CVariant value = it.value().toCVariant();
|
||||
const CPropertyIndex index = it.key();
|
||||
if (skipEqualValues)
|
||||
{
|
||||
bool equal = derived()->equalsPropertyByIndex(value, index);
|
||||
if (equal) { continue; }
|
||||
}
|
||||
derived()->setPropertyByIndex(value, index);
|
||||
changed.push_back(index);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
template <class Derived>
|
||||
void Index<Derived>::setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index)
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
derived()->convertFromCVariant(variant);
|
||||
return;
|
||||
}
|
||||
|
||||
// not all classes have implemented nesting
|
||||
const QString m = QString("Property by index not found (setter), index: ").append(index.toQString());
|
||||
qFatal("%s", qPrintable(m));
|
||||
}
|
||||
template <class Derived>
|
||||
CVariant Index<Derived>::propertyByIndex(const CPropertyIndex &index) const
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
return derived()->toCVariant();
|
||||
}
|
||||
auto i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexIcon:
|
||||
return CVariant::from(derived()->toIcon());
|
||||
case IndexPixmap:
|
||||
return CVariant::from(derived()->toPixmap());
|
||||
case IndexString:
|
||||
return CVariant(derived()->toQString());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// not all classes have implemented nesting
|
||||
const QString m = QString("Property by index not found, index: ").append(index.toQString());
|
||||
qFatal("%s", qPrintable(m));
|
||||
return {};
|
||||
}
|
||||
template <class Derived>
|
||||
QString Index<Derived>::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const
|
||||
{
|
||||
// default implementation, requires propertyByIndex
|
||||
return derived()->propertyByIndex(index).toQString(i18n);
|
||||
}
|
||||
template <class Derived>
|
||||
bool Index<Derived>::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const
|
||||
{
|
||||
return derived()->propertyByIndex(index) == compareValue;
|
||||
}
|
||||
} // Mixin
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::CPropertyIndexVariantMap)
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_SEQUENCE_H
|
||||
#define BLACKMISC_SEQUENCE_H
|
||||
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#include "dbus.h"
|
||||
#include "tuple.h"
|
||||
#include "json.h"
|
||||
#include "icons.h"
|
||||
#include "compare.h"
|
||||
#include "variant.h"
|
||||
#include "propertyindexvariantmap.h"
|
||||
#include "iconlist.h"
|
||||
#include "blackmiscfreefunctions.h"
|
||||
#include "valueobject_private.h"
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
@@ -33,30 +35,6 @@
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CPropertyIndex;
|
||||
class CPropertyIndexList;
|
||||
class CPropertyIndexVariantMap;
|
||||
class CIcon;
|
||||
class CVariant;
|
||||
class CEmpty;
|
||||
|
||||
/*!
|
||||
* This registers the value type T with the BlackMisc meta type system,
|
||||
* making it available for use with the extended feature set of BlackMisc::CVariant.
|
||||
*
|
||||
* The implementation (ab)uses the QMetaType converter function registration mechanism
|
||||
* to store a type-erased representation of the set of operations supported by T.
|
||||
* Unlike the singleton pattern, this approach means that CVariant can be used in plugins.
|
||||
*/
|
||||
template <typename T>
|
||||
void registerMetaValueType()
|
||||
{
|
||||
if (QMetaType::hasRegisteredConverterFunction<T, Private::IValueObjectMetaInfo *>()) { return; }
|
||||
auto converter = [](const T &) { static Private::CValueObjectMetaInfo<T> info; return &info; };
|
||||
bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(converter);
|
||||
Q_ASSERT(ok);
|
||||
Q_UNUSED(ok);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Default base class for CValueObject.
|
||||
@@ -81,512 +59,6 @@ namespace BlackMisc
|
||||
~CEmpty() = default;
|
||||
};
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with the metatype of the class.
|
||||
*/
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
class MetaType
|
||||
{
|
||||
public:
|
||||
//! Register metadata
|
||||
static void registerMetadata()
|
||||
{
|
||||
Private::MetaTypeHelper<Derived>::maybeRegisterMetaType();
|
||||
|
||||
[](...){}((qRegisterMetaType<AdditionalTypes>(), qDBusRegisterMetaType<AdditionalTypes>(), 0)...);
|
||||
}
|
||||
|
||||
//! Returns the Qt meta type ID of this object.
|
||||
int getMetaTypeId() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
|
||||
}
|
||||
|
||||
//! Returns true if this object is an instance of the class with the given meta type ID, or one of its subclasses.
|
||||
bool isA(int metaTypeId) const
|
||||
{
|
||||
if (metaTypeId == QMetaType::UnknownType) { return false; }
|
||||
if (metaTypeId == getMetaTypeId()) { return true; }
|
||||
return baseIsA(static_cast<const MetaBaseOfT<Derived> *>(derived()), metaTypeId);
|
||||
}
|
||||
|
||||
//! Method to return CVariant
|
||||
//! \deprecated Use CVariant::to() instead.
|
||||
CVariant toCVariant() const;
|
||||
|
||||
//! Set from CVariant
|
||||
//! \deprecated Use CVariant::from() instead.
|
||||
void convertFromCVariant(const CVariant &variant);
|
||||
|
||||
//! Return QVariant, used with DBus QVariant lists
|
||||
//! \deprecated Use QVariant::fromValue() instead.
|
||||
QVariant toQVariant() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeToQVariant(*derived());
|
||||
}
|
||||
|
||||
//! Set from QVariant
|
||||
//! \deprecated Use QVariant::value() instead.
|
||||
void convertFromQVariant(const QVariant &variant)
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeConvertFromQVariant(*derived(), variant);
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); }
|
||||
static bool baseIsA(const void *, int) { return false; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* Variant of MetaType mixin which also registers QList<Derived> with the type system.
|
||||
*/
|
||||
template <class Derived>
|
||||
class MetaTypeAndQList : public MetaType<Derived, QList<Derived>>
|
||||
{};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_METATYPE(DERIVED) \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::registerMetadata; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::getMetaTypeId; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::isA; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::toCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::toQVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::convertFromCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::convertFromQVariant;
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_METATYPE_AND_QLIST(DERIVED) \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::registerMetadata; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::getMetaTypeId; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::isA; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::toCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::toQVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::convertFromCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::convertFromQVariant;
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class HashByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! qHash overload, needed for storing value in a QSet.
|
||||
friend uint qHash(const Derived &value, uint seed = 0)
|
||||
{
|
||||
return ::qHash(hashImpl(value), seed);
|
||||
}
|
||||
|
||||
private:
|
||||
static uint hashImpl(const Derived &value)
|
||||
{
|
||||
return BlackMisc::qHash(toMetaTuple(value)) ^ baseHash(static_cast<const BaseOfT<Derived> *>(&value));
|
||||
}
|
||||
|
||||
template <typename T> static uint baseHash(const T *base) { return qHash(*base); }
|
||||
static uint baseHash(const void *) { return 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*/
|
||||
template <class Derived>
|
||||
class DBusOperators
|
||||
{
|
||||
public:
|
||||
//! Unmarshalling operator >>, DBus to object
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &arg, Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.unmarshallFromDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
//! Marshalling operator <<, object to DBus
|
||||
friend QDBusArgument &operator<<(QDBusArgument &arg, const Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.marshallToDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class DBusByTuple : public DBusOperators<Derived>, private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Marshall without begin/endStructure, for when composed within another object
|
||||
void marshallToDbus(QDBusArgument &arg) const
|
||||
{
|
||||
baseMarshall(static_cast<const BaseOfT<Derived> *>(derived()), arg);
|
||||
using BlackMisc::operator<<;
|
||||
arg << Private::EncapsulationBreaker::toMetaTuple(*derived());
|
||||
}
|
||||
|
||||
//! Unmarshall without begin/endStructure, for when composed within another object
|
||||
void unmarshallFromDbus(const QDBusArgument &arg)
|
||||
{
|
||||
baseUnmarshall(static_cast<BaseOfT<Derived> *>(derived()), arg);
|
||||
using BlackMisc::operator>>;
|
||||
arg >> Private::EncapsulationBreaker::toMetaTuple(*derived());
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg); }
|
||||
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg); }
|
||||
static void baseMarshall(const void *, QDBusArgument &) {}
|
||||
static void baseUnmarshall(void *, const QDBusArgument &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::DBusByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_DBUS(DERIVED) \
|
||||
using ::BlackMisc::Mixin::DBusByTuple<DERIVED>::marshallToDbus; \
|
||||
using ::BlackMisc::Mixin::DBusByTuple<DERIVED>::unmarshallFromDbus;
|
||||
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonOperators
|
||||
{
|
||||
public:
|
||||
//! operator >> for JSON
|
||||
friend const QJsonObject &operator>>(const QJsonObject &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json);
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend const QJsonValue &operator>>(const QJsonValue &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend const QJsonValueRef &operator>>(const QJsonValueRef &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonArray &operator<<(QJsonArray &json, const Derived &obj)
|
||||
{
|
||||
json.append(obj.toJson());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const Derived &> &value)
|
||||
{
|
||||
json.insert(value.first, QJsonValue(value.second.toJson()));
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonByTuple : public JsonOperators<Derived>, private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Cast to JSON object
|
||||
QJsonObject toJson() const
|
||||
{
|
||||
QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived()));
|
||||
return Json::appendJsonObject(json, baseToJson(static_cast<const BaseOfT<Derived> *>(derived())));
|
||||
}
|
||||
|
||||
//! Assign from JSON object
|
||||
void convertFromJson(const QJsonObject &json)
|
||||
{
|
||||
baseConvertFromJson(static_cast<BaseOfT<Derived> *>(derived()), json);
|
||||
BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived()));
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T> static QJsonObject baseToJson(const T *base) { return base->toJson(); }
|
||||
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); }
|
||||
static QJsonObject baseToJson(const void *) { return {}; }
|
||||
static void baseConvertFromJson(void *, const QJsonObject &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::JsonByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_JSON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::JsonByTuple<DERIVED>::toJson; \
|
||||
using ::BlackMisc::Mixin::JsonByTuple<DERIVED>::convertFromJson;
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator== implemented using its compare function.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByCompare
|
||||
{
|
||||
public:
|
||||
//! Equals
|
||||
friend bool operator ==(const Derived &a, const Derived &b) { return compare(a, b) == 0; }
|
||||
|
||||
//! Not equal
|
||||
friend bool operator !=(const Derived &a, const Derived &b) { return compare(a, b) != 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator== implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Equals
|
||||
friend bool operator ==(const Derived &a, const Derived &b) { return equals(a, b); }
|
||||
|
||||
//! Not equal
|
||||
friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); }
|
||||
|
||||
private:
|
||||
static bool equals(const Derived &a, const Derived &b)
|
||||
{
|
||||
return toMetaTuple(a) == toMetaTuple(b) && baseEquals(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
|
||||
}
|
||||
template <typename T> static bool baseEquals(const T *a, const T *b) { return *a == *b; }
|
||||
static bool baseEquals(const void *, const void *) { return true; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented using its compare function.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByCompare
|
||||
{
|
||||
public:
|
||||
//! Less than
|
||||
friend bool operator <(const Derived &a, const Derived &b) { return compare(a, b) < 0; }
|
||||
|
||||
//! Greater than
|
||||
friend bool operator >(const Derived &a, const Derived &b) { return compare(a, b) > 0; }
|
||||
|
||||
//! Less than or equal
|
||||
friend bool operator <=(const Derived &a, const Derived &b) { return compare(a, b) <= 0; }
|
||||
|
||||
//! Greater than or equal
|
||||
friend bool operator >=(const Derived &a, const Derived &b) { return compare(a, b) >= 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Less than
|
||||
friend bool operator <(const Derived &a, const Derived &b) { return less(a, b); }
|
||||
|
||||
//! Greater than
|
||||
friend bool operator >(const Derived &a, const Derived &b) { return less(b, a); }
|
||||
|
||||
//! Less than or equal
|
||||
friend bool operator <=(const Derived &a, const Derived &b) { return ! less(b, a); }
|
||||
|
||||
//! Greater than or equal
|
||||
friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); }
|
||||
|
||||
private:
|
||||
static bool less(const Derived &a, const Derived &b)
|
||||
{
|
||||
if (baseLess(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b))) { return true; }
|
||||
return toMetaTuple(a) < toMetaTuple(b);
|
||||
}
|
||||
template <typename T> static bool baseLess(const T *a, const T *b) { return *a < *b; }
|
||||
static bool baseLess(const void *, const void *) { return false; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit non-member compare() implemented by metatuple.
|
||||
*/
|
||||
template <class Derived>
|
||||
class CompareByTuple : private Private::EncapsulationBreaker
|
||||
{
|
||||
public:
|
||||
//! Return negative, zero, or positive if a is less than, equal to, or greater than b.
|
||||
friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); }
|
||||
|
||||
private:
|
||||
static int compareImpl(const Derived &a, const Derived &b)
|
||||
{
|
||||
int baseCmp = baseCompare(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
|
||||
if (baseCmp) { return baseCmp; }
|
||||
return BlackMisc::compare(toMetaTuple(a), toMetaTuple(b));
|
||||
}
|
||||
template <typename T> static int baseCompare(const T *a, const T *b) { return compare(*a, *b); }
|
||||
static int baseCompare(const void *, const void *) { return 0; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit string streaming operations.
|
||||
*/
|
||||
template <class Derived>
|
||||
class String
|
||||
{
|
||||
public:
|
||||
//! Stream << overload to be used in debugging messages
|
||||
friend QDebug operator<<(QDebug debug, const Derived &obj)
|
||||
{
|
||||
debug << obj.stringForStreaming();
|
||||
return debug;
|
||||
}
|
||||
|
||||
//! Operator << when there is no debug stream
|
||||
friend QNoDebug operator<<(QNoDebug nodebug, const Derived &obj)
|
||||
{
|
||||
Q_UNUSED(obj);
|
||||
return nodebug;
|
||||
}
|
||||
|
||||
//! Operator << based on text stream
|
||||
friend QTextStream &operator<<(QTextStream &stream, const Derived &obj)
|
||||
{
|
||||
stream << obj.stringForStreaming();
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Operator << for QDataStream
|
||||
friend QDataStream &operator<<(QDataStream &stream, const Derived &obj)
|
||||
{
|
||||
stream << obj.stringForStreaming();
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Stream operator << for std::cout
|
||||
friend std::ostream &operator<<(std::ostream &ostr, const Derived &obj)
|
||||
{
|
||||
ostr << obj.stringForStreaming().toStdString();
|
||||
return ostr;
|
||||
}
|
||||
|
||||
//! Cast as QString
|
||||
QString toQString(bool i18n = false) const { return derived()->convertToQString(i18n); }
|
||||
|
||||
//! Cast to pretty-printed QString
|
||||
QString toFormattedQString(bool i18n = false) const { return derived()->toQString(i18n); }
|
||||
|
||||
//! To std string
|
||||
std::string toStdString(bool i18n = false) const { return derived()->convertToQString(i18n).toStdString(); }
|
||||
|
||||
//! String for streaming operators
|
||||
QString stringForStreaming() const { return derived()->convertToQString(); }
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::String,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_STRING(DERIVED) \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toFormattedQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toStdString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::stringForStreaming;
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit property indexing functions.
|
||||
*/
|
||||
template <class Derived>
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
//! Base class enums
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexPixmap = 10, // manually set to avoid circular dependencies
|
||||
IndexIcon,
|
||||
IndexString
|
||||
};
|
||||
|
||||
//! Update by variant map
|
||||
//! \return number of values changed, with skipEqualValues equal values will not be changed
|
||||
CPropertyIndexList apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues = false); // implemented later due to cyclic include dependency
|
||||
|
||||
//! Set property by index
|
||||
void setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index); // implemented later due to cyclic include dependency
|
||||
|
||||
//! Property by index
|
||||
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; // implemented later due to cyclic include dependency
|
||||
|
||||
//! Property by index as String
|
||||
QString propertyByIndexAsString(const CPropertyIndex &index, bool i18n = false) const; // implemented later due to cyclic include dependency
|
||||
|
||||
//! Is given variant equal to value of property index?
|
||||
bool equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const; // implemented later due to cyclic include dependency
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit icon-related functions.
|
||||
*/
|
||||
template <class Derived, CIcons::IconIndex IconIndex = CIcons::StandardIconUnknown16>
|
||||
class Icon
|
||||
{
|
||||
public:
|
||||
//! As icon, not implemented by all classes
|
||||
CIcon toIcon() const; // implemented later due to cyclic include dependency
|
||||
|
||||
//! As pixmap, required for most GUI views
|
||||
QPixmap toPixmap() const; // implemented later due to cyclic include dependency
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::Icon,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_ICON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toIcon; \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toPixmap;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* Standard implementation of CValueObject using meta tuple system.
|
||||
*
|
||||
@@ -702,108 +174,4 @@ namespace BlackMisc
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO Includes due to cyclic dependencies can be removed when CValueObject is split into parts along policy boundaries.
|
||||
#include "variant.h"
|
||||
#include "propertyindex.h"
|
||||
#include "propertyindexlist.h"
|
||||
#include "iconlist.h"
|
||||
|
||||
// TODO Implementations of templates that must appear after those includes, should be moved at the same time that policies are refactored.
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
CVariant MetaType<Derived, AdditionalTypes...>::toCVariant() const
|
||||
{
|
||||
return CVariant(derived()->toQVariant());
|
||||
}
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
void MetaType<Derived, AdditionalTypes...>::convertFromCVariant(const CVariant &variant)
|
||||
{
|
||||
derived()->convertFromQVariant(variant.getQVariant());
|
||||
}
|
||||
template <class Derived>
|
||||
CPropertyIndexList Index<Derived>::apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues)
|
||||
{
|
||||
if (indexMap.isEmpty()) return {};
|
||||
|
||||
CPropertyIndexList changed;
|
||||
const auto &map = indexMap.map();
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
const CVariant value = it.value().toCVariant();
|
||||
const CPropertyIndex index = it.key();
|
||||
if (skipEqualValues)
|
||||
{
|
||||
bool equal = derived()->equalsPropertyByIndex(value, index);
|
||||
if (equal) { continue; }
|
||||
}
|
||||
derived()->setPropertyByIndex(value, index);
|
||||
changed.push_back(index);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
template <class Derived>
|
||||
void Index<Derived>::setPropertyByIndex(const CVariant &variant, const CPropertyIndex &index)
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
derived()->convertFromCVariant(variant);
|
||||
return;
|
||||
}
|
||||
|
||||
// not all classes have implemented nesting
|
||||
const QString m = QString("Property by index not found (setter), index: ").append(index.toQString());
|
||||
qFatal("%s", qPrintable(m));
|
||||
}
|
||||
template <class Derived>
|
||||
CVariant Index<Derived>::propertyByIndex(const CPropertyIndex &index) const
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
return derived()->toCVariant();
|
||||
}
|
||||
auto i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexIcon:
|
||||
return CVariant::from(derived()->toIcon());
|
||||
case IndexPixmap:
|
||||
return CVariant::from(derived()->toPixmap());
|
||||
case IndexString:
|
||||
return CVariant(derived()->toQString());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// not all classes have implemented nesting
|
||||
const QString m = QString("Property by index not found, index: ").append(index.toQString());
|
||||
qFatal("%s", qPrintable(m));
|
||||
return {};
|
||||
}
|
||||
template <class Derived>
|
||||
QString Index<Derived>::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const
|
||||
{
|
||||
// default implementation, requires propertyByIndex
|
||||
return derived()->propertyByIndex(index).toQString(i18n);
|
||||
}
|
||||
template <class Derived>
|
||||
bool Index<Derived>::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const
|
||||
{
|
||||
return derived()->propertyByIndex(index) == compareValue;
|
||||
}
|
||||
template <class Derived, CIcons::IconIndex IconIndex>
|
||||
CIcon Icon<Derived, IconIndex>::toIcon() const
|
||||
{
|
||||
return CIconList::iconByIndex(IconIndex);
|
||||
}
|
||||
template <class Derived, CIcons::IconIndex IconIndex>
|
||||
QPixmap Icon<Derived, IconIndex>::toPixmap() const
|
||||
{
|
||||
return derived()->toIcon().toPixmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -9,12 +9,16 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#include "valueobject.h" // outside include guard due to cyclic dependency hack (MS)
|
||||
|
||||
#ifndef BLACKMISC_VARIANT_H
|
||||
#define BLACKMISC_VARIANT_H
|
||||
|
||||
#include "variant_private.h"
|
||||
#include "blackmiscexport.h"
|
||||
#include "blackmiscfreefunctions.h"
|
||||
#include "tuple.h"
|
||||
#include "compare.h"
|
||||
#include "dbus.h"
|
||||
#include "json.h"
|
||||
#include <QVariant>
|
||||
#include <QDateTime>
|
||||
#include <QJsonValueRef>
|
||||
@@ -22,12 +26,126 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
class QDBusArgument;
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CPropertyIndex;
|
||||
class CIcon;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with the metatype of the class.
|
||||
*/
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
class MetaType
|
||||
{
|
||||
public:
|
||||
//! Register metadata
|
||||
static void registerMetadata()
|
||||
{
|
||||
Private::MetaTypeHelper<Derived>::maybeRegisterMetaType();
|
||||
|
||||
[](...){}((qRegisterMetaType<AdditionalTypes>(), qDBusRegisterMetaType<AdditionalTypes>(), 0)...);
|
||||
}
|
||||
|
||||
//! Returns the Qt meta type ID of this object.
|
||||
int getMetaTypeId() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
|
||||
}
|
||||
|
||||
//! Returns true if this object is an instance of the class with the given meta type ID, or one of its subclasses.
|
||||
bool isA(int metaTypeId) const
|
||||
{
|
||||
if (metaTypeId == QMetaType::UnknownType) { return false; }
|
||||
if (metaTypeId == getMetaTypeId()) { return true; }
|
||||
return baseIsA(static_cast<const MetaBaseOfT<Derived> *>(derived()), metaTypeId);
|
||||
}
|
||||
|
||||
//! Method to return CVariant
|
||||
//! \deprecated Use CVariant::to() instead.
|
||||
CVariant toCVariant() const;
|
||||
|
||||
//! Set from CVariant
|
||||
//! \deprecated Use CVariant::from() instead.
|
||||
void convertFromCVariant(const CVariant &variant);
|
||||
|
||||
//! Return QVariant, used with DBus QVariant lists
|
||||
//! \deprecated Use QVariant::fromValue() instead.
|
||||
QVariant toQVariant() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeToQVariant(*derived());
|
||||
}
|
||||
|
||||
//! Set from QVariant
|
||||
//! \deprecated Use QVariant::value() instead.
|
||||
void convertFromQVariant(const QVariant &variant)
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeConvertFromQVariant(*derived(), variant);
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); }
|
||||
static bool baseIsA(const void *, int) { return false; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* Variant of MetaType mixin which also registers QList<Derived> with the type system.
|
||||
*/
|
||||
template <class Derived>
|
||||
class MetaTypeAndQList : public MetaType<Derived, QList<Derived>>
|
||||
{};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_METATYPE(DERIVED) \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::registerMetadata; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::getMetaTypeId; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::isA; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::toCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::toQVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::convertFromCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::convertFromQVariant;
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_METATYPE_AND_QLIST(DERIVED) \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::registerMetadata; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::getMetaTypeId; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::isA; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::toCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::toQVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::convertFromCVariant; \
|
||||
using ::BlackMisc::Mixin::MetaTypeAndQList<DERIVED>::convertFromQVariant;
|
||||
|
||||
} // Mixin
|
||||
|
||||
/*!
|
||||
* This registers the value type T with the BlackMisc meta type system,
|
||||
* making it available for use with the extended feature set of BlackMisc::CVariant.
|
||||
*
|
||||
* The implementation (ab)uses the QMetaType converter function registration mechanism
|
||||
* to store a type-erased representation of the set of operations supported by T.
|
||||
* Unlike the singleton pattern, this approach means that CVariant can be used in plugins.
|
||||
*/
|
||||
template <typename T>
|
||||
void registerMetaValueType()
|
||||
{
|
||||
if (QMetaType::hasRegisteredConverterFunction<T, Private::IValueObjectMetaInfo *>()) { return; }
|
||||
auto converter = [](const T &) { static Private::CValueObjectMetaInfo<T> info; return &info; };
|
||||
bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(converter);
|
||||
Q_ASSERT(ok);
|
||||
Q_UNUSED(ok);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Wrapper around QVariant which provides transparent access to CValueObject methods
|
||||
* of the contained object if it is registered with BlackMisc::registerMetaValueType.
|
||||
@@ -38,9 +156,7 @@ namespace BlackMisc
|
||||
public Mixin::LessThanByCompare<CVariant>,
|
||||
public Mixin::DBusOperators<CVariant>,
|
||||
public Mixin::JsonOperators<CVariant>,
|
||||
public Mixin::Index<CVariant>,
|
||||
public Mixin::String<CVariant>,
|
||||
public Mixin::Icon<CVariant>
|
||||
public Mixin::String<CVariant>
|
||||
{
|
||||
public:
|
||||
//! Default constructor.
|
||||
@@ -252,6 +368,21 @@ namespace BlackMisc
|
||||
//! \private Needed so we can copy forward-declared CVariant.
|
||||
inline void assign(CVariant &a, const CVariant &b) { a = b; }
|
||||
}
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
CVariant MetaType<Derived, AdditionalTypes...>::toCVariant() const
|
||||
{
|
||||
return CVariant(derived()->toQVariant());
|
||||
}
|
||||
template <class Derived, class... AdditionalTypes>
|
||||
void MetaType<Derived, AdditionalTypes...>::convertFromCVariant(const CVariant &variant)
|
||||
{
|
||||
derived()->convertFromQVariant(variant.getQVariant());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::CVariant)
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_VALUEOBJECT_PRIVATE_H
|
||||
#define BLACKMISC_VALUEOBJECT_PRIVATE_H
|
||||
#ifndef BLACKMISC_VARIANT_PRIVATE_H
|
||||
#define BLACKMISC_VARIANT_PRIVATE_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
#include "blackmisc/inheritance_traits.h"
|
||||
#include <QString>
|
||||
#include <QMetaType>
|
||||
Reference in New Issue
Block a user