mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-23 07:15:35 +08:00
Issue #15 CVariant can convert between CVariantList and our other container classes
This commit is contained in:
@@ -25,6 +25,10 @@ namespace BlackMisc
|
||||
CSequence<CAircraftIcaoCode>(other)
|
||||
{ }
|
||||
|
||||
CAircraftIcaoCodeList::CAircraftIcaoCodeList(std::initializer_list<CAircraftIcaoCode> il) :
|
||||
CSequence<CAircraftIcaoCode>(il)
|
||||
{ }
|
||||
|
||||
CAircraftIcaoCodeList CAircraftIcaoCodeList::findByDesignator(const QString &designator, int fuzzySearch) const
|
||||
{
|
||||
if (!fuzzySearch && !CAircraftIcaoCode::isValidDesignator(designator)) { return CAircraftIcaoCodeList(); }
|
||||
|
||||
@@ -45,6 +45,9 @@ namespace BlackMisc
|
||||
//! Construct from a base class object.
|
||||
CAircraftIcaoCodeList(const CSequence<CAircraftIcaoCode> &other);
|
||||
|
||||
//! Construct from initializer list.
|
||||
CAircraftIcaoCodeList(std::initializer_list<CAircraftIcaoCode> il);
|
||||
|
||||
//! Find by designator
|
||||
CAircraftIcaoCodeList findByDesignator(const QString &designator, int fuzzySearch = -1) const;
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ namespace BlackMisc
|
||||
CSequence<CAirlineIcaoCode>(other)
|
||||
{ }
|
||||
|
||||
CAirlineIcaoCodeList::CAirlineIcaoCodeList(std::initializer_list<CAirlineIcaoCode> il) :
|
||||
CSequence<CAirlineIcaoCode>(il)
|
||||
{ }
|
||||
|
||||
CAirlineIcaoCodeList CAirlineIcaoCodeList::findByDesignator(const QString &designator) const
|
||||
{
|
||||
if (!CAirlineIcaoCode::isValidAirlineDesignator(designator)) { return CAirlineIcaoCodeList(); }
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace BlackMisc
|
||||
//! Construct from a base class object.
|
||||
CAirlineIcaoCodeList(const CSequence<CAirlineIcaoCode> &other);
|
||||
|
||||
//! Construct from initializer list.
|
||||
CAirlineIcaoCodeList(std::initializer_list<CAirlineIcaoCode> il);
|
||||
|
||||
//! Find by designator
|
||||
//! Not unique because of virtual airlines
|
||||
CAirlineIcaoCodeList findByDesignator(const QString &designator) const;
|
||||
|
||||
@@ -80,6 +80,12 @@ namespace BlackMisc
|
||||
//! Destructor.
|
||||
~CSequence() = default;
|
||||
|
||||
//! Copy of internal vector.
|
||||
//! @{
|
||||
QVector<T> toVector() const & { return m_impl; }
|
||||
QVector<T> toVector() && { return std::move(m_impl); }
|
||||
//! @}
|
||||
|
||||
//! Returns iterator at the beginning of the sequence.
|
||||
iterator begin() { return m_impl.begin(); }
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/statusmessage.h"
|
||||
#include "blackmisc/variantlist.h"
|
||||
#include "blackmisc/variant.h"
|
||||
|
||||
#include <QByteArray>
|
||||
@@ -42,6 +43,58 @@ namespace BlackMisc
|
||||
return v.value<IValueObjectMetaInfo *>();
|
||||
}
|
||||
|
||||
bool CVariant::canConvert(int typeId) const
|
||||
{
|
||||
if (m_v.canConvert(typeId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (typeId == qMetaTypeId<CVariantList>())
|
||||
{
|
||||
return m_v.canConvert<QVector<CVariant>>() || m_v.canConvert<QVariantList>();
|
||||
}
|
||||
if (userType() == qMetaTypeId<CVariantList>())
|
||||
{
|
||||
return QVariant::fromValue(QVector<CVariant>()).canConvert(typeId)
|
||||
|| QVariant(typeId, nullptr).canConvert<QVariantList>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVariant::convert(int typeId)
|
||||
{
|
||||
if (!m_v.canConvert(typeId))
|
||||
{
|
||||
if (!canConvert(typeId)) { return false; }
|
||||
if (typeId == qMetaTypeId<CVariantList>())
|
||||
{
|
||||
if (m_v.canConvert<QVector<CVariant>>())
|
||||
{
|
||||
if (!m_v.convert(qMetaTypeId<QVector<CVariant>>())) { return false; }
|
||||
}
|
||||
else if (m_v.canConvert<QVariantList>())
|
||||
{
|
||||
m_v.setValue(CVariantList(m_v.value<QSequentialIterable>()));
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
if (userType() == qMetaTypeId<CVariantList>())
|
||||
{
|
||||
if (QVariant::fromValue(QVector<CVariant>()).canConvert(typeId))
|
||||
{
|
||||
if (!m_v.convert(qMetaTypeId<QVector<CVariant>>())) { return false; }
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
}
|
||||
return m_v.convert(typeId);
|
||||
}
|
||||
|
||||
bool CVariant::isVariantList() const
|
||||
{
|
||||
return userType() == qMetaTypeId<CVariantList>();
|
||||
}
|
||||
|
||||
QString CVariant::convertToQString(bool i18n) const
|
||||
{
|
||||
auto *meta = getValueObjectMetaInfo();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "blackmisc/datastream.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include "blackmisc/json.h"
|
||||
#include "blackmisc/range.h"
|
||||
#include "blackmisc/stringutils.h"
|
||||
#include "blackmisc/variantprivate.h"
|
||||
|
||||
@@ -36,6 +37,7 @@ namespace BlackMisc
|
||||
{
|
||||
class CIcon;
|
||||
class CPropertyIndex;
|
||||
class CVariantList;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
@@ -127,6 +129,8 @@ namespace BlackMisc
|
||||
public Mixin::JsonOperators<CVariant>,
|
||||
public Mixin::String<CVariant>
|
||||
{
|
||||
template <typename> struct tag {};
|
||||
|
||||
public:
|
||||
//! Default constructor.
|
||||
CVariant() {}
|
||||
@@ -212,10 +216,10 @@ namespace BlackMisc
|
||||
template <typename T> void set(T &&value) { m_v.setValue(std::forward<T>(value)); }
|
||||
|
||||
//! Return the value converted to the type T.
|
||||
template <typename T> T value() const { return m_v.value<T>(); }
|
||||
template <typename T> T value() const { return to(tag<T>()); }
|
||||
|
||||
//! Synonym for value().
|
||||
template <typename T> T to() const { return m_v.value<T>(); }
|
||||
template <typename T> T to() const { return to(tag<T>()); }
|
||||
|
||||
//! Returns the value converted to the type T, or a default if it can not be converted.
|
||||
//! \details Parameter is passed by value to avoid odr-using the argument in case it is
|
||||
@@ -226,13 +230,13 @@ namespace BlackMisc
|
||||
const QVariant &getQVariant() const { return m_v; }
|
||||
|
||||
//! True if this variant can be converted to the type with the given metatype ID.
|
||||
bool canConvert(int typeId) const { return m_v.canConvert(typeId); }
|
||||
bool canConvert(int typeId) const;
|
||||
|
||||
//! True if this variant can be converted to the type T.
|
||||
template <typename T> bool canConvert() const { return m_v.canConvert<T>(); }
|
||||
template <typename T> bool canConvert() const { return canConvert(qMetaTypeId<T>()); }
|
||||
|
||||
//! Convert this variant to the type with the given metatype ID and return true if successful.
|
||||
bool convert(int typeId) { return m_v.convert(typeId); }
|
||||
bool convert(int typeId);
|
||||
|
||||
//! \copydoc BlackMisc::Mixin::String::toQString
|
||||
QString convertToQString(bool i18n = false) const;
|
||||
@@ -349,17 +353,53 @@ namespace BlackMisc
|
||||
static int compareImpl(const CVariant &, const CVariant &);
|
||||
uint getValueHash() const;
|
||||
|
||||
template <typename T> T to(tag<T>) const
|
||||
{
|
||||
auto copy = *this; copy.convert(qMetaTypeId<T>()); return *static_cast<const T*>(copy.data());
|
||||
}
|
||||
template <typename T> QList<T> to(tag<QList<T>>) const { return toImpl<QList<T>>(); }
|
||||
template <typename T> QVector<T> to(tag<QVector<T>>) const { return toImpl<QVector<T>>(); }
|
||||
template <typename T> CSequence<T> to(tag<CSequence<T>>) const { return toImpl<CSequence<T>>(); }
|
||||
template <typename T> T toImpl() const
|
||||
{
|
||||
using VT = typename T::value_type;
|
||||
T result;
|
||||
if (isVariantList()) { for (const auto &v : m_v.value<QVector<CVariant>>()) { result.push_back(v.value<VT>()); } }
|
||||
else { for (const auto &v : m_v.value<QSequentialIterable>()) { result.push_back(v.value<VT>()); } }
|
||||
return result;
|
||||
}
|
||||
bool isVariantList() const;
|
||||
|
||||
template <typename F> static CVariant fromResultOfImpl(F &&func, std::true_type) { std::forward<F>(func)(); return {}; }
|
||||
template <typename F> static CVariant fromResultOfImpl(F &&func, std::false_type) { return from(std::forward<F>(func)()); }
|
||||
};
|
||||
|
||||
namespace Private
|
||||
{
|
||||
//! \private Needed so we can copy forward-declared CVariant.
|
||||
inline void assign(CVariant &a, const CVariant &b) { a = b; }
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::CVariant)
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Private
|
||||
{
|
||||
//! \private Needed so we can copy forward-declared CVariant.
|
||||
inline void assign(CVariant &a, const CVariant &b) { a = b; }
|
||||
|
||||
//! \private
|
||||
template <typename T, typename>
|
||||
void maybeRegisterMetaListConvert(int)
|
||||
{
|
||||
if (QMetaType::hasRegisteredConverterFunction(qMetaTypeId<T>(), qMetaTypeId<QVector<CVariant>>())) { return; }
|
||||
|
||||
QMetaType::registerConverter<T, QVector<CVariant>>([](const T &list) -> QVector<CVariant>
|
||||
{
|
||||
return list.transform([](const typename T::value_type &v) { return CVariant::from(v); });
|
||||
});
|
||||
QMetaType::registerConverter<QVector<CVariant>, T>([](const QVector<CVariant> &list) -> T
|
||||
{
|
||||
return makeRange(list).transform([](const CVariant &v) { return v.to<typename T::value_type>(); });
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,9 +7,33 @@
|
||||
*/
|
||||
|
||||
#include "blackmisc/variantlist.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
CVariantList::CVariantList(const CSequence &other) : CSequence(other)
|
||||
{}
|
||||
|
||||
CVariantList::CVariantList(const QVariantList &other)
|
||||
{
|
||||
std::copy(other.begin(), other.end(), std::back_inserter(*this));
|
||||
}
|
||||
|
||||
CVariantList::CVariantList(QVariantList &&other)
|
||||
{
|
||||
std::move(other.begin(), other.end(), std::back_inserter(*this));
|
||||
}
|
||||
|
||||
CVariantList::CVariantList(const QSequentialIterable &other)
|
||||
{
|
||||
for (auto it = other.begin(); it != other.end(); ++it) { push_back(*it); }
|
||||
}
|
||||
|
||||
void CVariantList::registerMetadata()
|
||||
{
|
||||
Mixin::MetaType<CVariantList>::registerMetadata();
|
||||
QMetaType::registerConverter<CVariantList, QVector<CVariant>>([](const CVariantList &list) { return list.toVector(); });
|
||||
QMetaType::registerConverter<QVector<CVariant>, CVariantList>([](const QVector<CVariant> &list) { return CSequence(list); });
|
||||
}
|
||||
} // ns
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
#include "blackmisc/collection.h"
|
||||
#include "blackmisc/sequence.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include <QVariantList>
|
||||
#include <QMetaType>
|
||||
#include <iterator>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
//! Value object encapsulating a list of variants.
|
||||
/*!
|
||||
* Value object encapsulating a list of variants.
|
||||
*
|
||||
* A CVariant containing any registered sequential container type can be converted to a CVariantList.
|
||||
*/
|
||||
class BLACKMISC_EXPORT CVariantList :
|
||||
public CSequence<CVariant>,
|
||||
public BlackMisc::Mixin::MetaType<CVariantList>
|
||||
@@ -33,6 +39,26 @@ namespace BlackMisc
|
||||
|
||||
//! Construct from a base class object.
|
||||
CVariantList(const CSequence &other);
|
||||
|
||||
//! Construct from a QVariantList.
|
||||
CVariantList(const QVariantList &other);
|
||||
|
||||
//! Construct from a moved QVariantList.
|
||||
CVariantList(QVariantList &&other);
|
||||
|
||||
//! Construct from a QSequentialIterable.
|
||||
CVariantList(const QSequentialIterable &other);
|
||||
|
||||
//! Convert to a sequence type by converting all elements.
|
||||
template <typename T>
|
||||
T to() const { return CVariant::from(*this).template to<T>(); }
|
||||
|
||||
//! Convert from a sequence type by converting all elements.
|
||||
template <typename T>
|
||||
static CVariantList from(const T &list) { return CVariant::from(list).template to<CVariantList>(); }
|
||||
|
||||
//! \copydoc BlackMisc::CValueObject::registerMetadata
|
||||
static void registerMetadata();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace BlackMisc
|
||||
class CPropertyIndex;
|
||||
class CIcon;
|
||||
|
||||
template <typename T>
|
||||
class CSequence;
|
||||
|
||||
template <typename T>
|
||||
void registerMetaValueType();
|
||||
|
||||
@@ -234,11 +237,16 @@ namespace BlackMisc
|
||||
IValueObjectMetaInfo *getValueObjectMetaInfo() { return getValueObjectMetaInfo(qMetaTypeId<T>()); }
|
||||
|
||||
//! \cond PRIVATE
|
||||
template <typename T, typename = std::enable_if_t<std::is_base_of<CSequence<typename T::value_type>, T>::value && ! std::is_same<typename T::value_type, CVariant>::value>>
|
||||
void maybeRegisterMetaListConvert(int);
|
||||
template <typename T>
|
||||
void maybeRegisterMetaListConvert(...) {}
|
||||
|
||||
template <typename T, bool IsRegisteredMetaType /* = true */>
|
||||
struct MetaTypeHelperImpl
|
||||
{
|
||||
static constexpr int maybeGetMetaTypeId() { return qMetaTypeId<T>(); }
|
||||
static void maybeRegisterMetaType() { qRegisterMetaType<T>(); qDBusRegisterMetaType<T>(); qRegisterMetaTypeStreamOperators<T>(); registerMetaValueType<T>(); }
|
||||
static void maybeRegisterMetaType() { qRegisterMetaType<T>(); qDBusRegisterMetaType<T>(); qRegisterMetaTypeStreamOperators<T>(); registerMetaValueType<T>(); maybeRegisterMetaListConvert<T>(0); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* \ingroup testblackmisc
|
||||
*/
|
||||
|
||||
#include "blackmisc/aviation/airlineicaocodelist.h"
|
||||
#include "blackmisc/aviation/atcstation.h"
|
||||
#include "blackmisc/aviation/callsign.h"
|
||||
#include "blackmisc/compare.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "blackmisc/pq/units.h"
|
||||
#include "blackmisc/propertyindexvariantmap.h"
|
||||
#include "blackmisc/registermetadata.h"
|
||||
#include "blackmisc/variantlist.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include "test.h"
|
||||
|
||||
@@ -50,6 +52,9 @@ namespace BlackMiscTest
|
||||
//! Basic unit tests for value objects and variants
|
||||
void variant();
|
||||
|
||||
//! Unit tests for variant lists
|
||||
void variantList();
|
||||
|
||||
//! Unit tests for value maps and value objects
|
||||
void valueMap();
|
||||
};
|
||||
@@ -106,6 +111,29 @@ namespace BlackMiscTest
|
||||
QVERIFY2(compare(station1, station3) != 0, "Station should not be equal");
|
||||
}
|
||||
|
||||
void CTestVariantAndMap::variantList()
|
||||
{
|
||||
const CSequence<int> ints { 1, 2, 3 };
|
||||
CVariant variant = CVariant::from(ints);
|
||||
QVERIFY2(variant.canConvert<CVariantList>(), "Variant containing list can convert to CVariantList");
|
||||
QVERIFY2(variant.convert(qMetaTypeId<CVariantList>()), "Variant containing list can convert to CVariantList");
|
||||
const CVariantList variantInts = variant.to<CVariantList>();
|
||||
QVERIFY2(ints.size() == variantInts.size(), "Variant list has same size as original list");
|
||||
QVERIFY2(ints[0] == variantInts[0].to<int>(), "Variant list has same element");
|
||||
QVERIFY2(variant.canConvert<CSequence<int>>(), "Variant containing can convert back");
|
||||
QVERIFY2(ints == variant.to<CSequence<int>>(), "Variant list converted back compares equal");
|
||||
|
||||
const CAirlineIcaoCodeList list { CAirlineIcaoCode("BAW"), CAirlineIcaoCode("DLH"), CAirlineIcaoCode("AAL") };
|
||||
variant = CVariant::from(list);
|
||||
QVERIFY2(variant.canConvert<CVariantList>(), "Variant containing list can convert to CVariantList");
|
||||
QVERIFY2(variant.convert(qMetaTypeId<CVariantList>()), "Variant containing list can convert to CVariantList");
|
||||
CVariantList variantList = variant.to<CVariantList>();
|
||||
QVERIFY2(list.size() == variantList.size(), "Variant list has same size as original list");
|
||||
QVERIFY2(list[0] == variantList[0].to<CAirlineIcaoCode>(), "Variant list has same element");
|
||||
QVERIFY2(variant.canConvert<CAirlineIcaoCodeList>(), "Variant containing can convert back");
|
||||
QVERIFY2(list == variant.to<CAirlineIcaoCodeList>(), "Variant list converted back compares equal");
|
||||
}
|
||||
|
||||
void CTestVariantAndMap::valueMap()
|
||||
{
|
||||
// ATC station
|
||||
|
||||
Reference in New Issue
Block a user