CValueMap generic representation of a value object as a map of QVariants

refs #81
This commit is contained in:
Klaus Basan
2013-12-22 20:47:01 +00:00
committed by Mathew Sutcliffe
parent a280d239e6
commit bf1837b414
6 changed files with 466 additions and 0 deletions

View File

@@ -8,6 +8,7 @@
#include "pqallquantities.h"
#include "mathallclasses.h"
#include "geoallclasses.h"
#include "valuemap.h"
/*
* Metadata for PQs
@@ -68,12 +69,24 @@ void BlackMisc::Geo::registerMetadata()
*/
void BlackMisc::registerMetadata()
{
// !! make sure the first id is correctly returned by
// !! firstBlackMetaType
CValueMap::registerMetadata();
PhysicalQuantities::registerMetadata();
Aviation::registerMetadata();
Math::registerMetadata();
Geo::registerMetadata();
}
/*
* First of our ids
*/
int BlackMisc::firstBlackMetaType()
{
// must be the first registered above
return qMetaTypeId<CValueMap>();
}
/*
* Init resources
*/
@@ -279,3 +292,15 @@ QVariant BlackMisc::complexQtTypeFromDbusArgument(const QDBusArgument &argument,
return QVariant(); // suppress compiler warning
}
/*
* Dump all user types
*/
void BlackMisc::displayAllUserMetatypesTypes()
{
for (int mt = QMetaType::User; mt < QMetaType::User + 1000; mt++)
{
if (!QMetaType::isRegistered(mt)) continue;
QMetaType metaType(mt);
qDebug() << "type:" << mt << "name:" << QMetaType::typeName(mt) << QMetaType::sizeOf(mt) << BlackMisc::heapSizeOf(metaType);
}
}

View File

@@ -77,6 +77,20 @@ namespace BlackMisc
*/
void registerMetadata();
/*!
* Deals with the issue that the BlackMisc metatype does not always start with
* the same id, e.g. with GUI enabled:
* type: 1024 name: QPaintBufferCacheEntry
* type: 1025 .... some classes I cannot foresee
* type: 1027 name: BlackMisc::CValueMap
*
* This is important when marshalling Variants via DBus among different
* binaries, as the offset has to be considered
*
* \return
*/
int firstBlackMetaType();
/*!
* \brief Init resources
*/
@@ -125,6 +139,11 @@ namespace BlackMisc
// TODO: To be removed if a better solution is found
QVariant complexQtTypeFromDbusArgument(const QDBusArgument &argument, int type);
/*!
* \brief displayAllUserTypes
*/
void displayAllUserMetatypesTypes();
/*!
* \brief Add several hash values
* \param values

119
src/blackmisc/valuemap.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include "valuemap.h"
#include "blackmiscfreefunctions.h"
#include "avaltitude.h"
namespace BlackMisc
{
/*
* Constructor
*/
CValueMap::CValueMap(bool wildcard) : m_wildcard(wildcard) {}
/*
* Constructor single value
*/
CValueMap::CValueMap(int index, const QVariant &value)
{
this->addValue(index, value);
}
/*
* Convert to string
*/
QString CValueMap::convertToQString(bool i18n) const
{
if (this->isEmpty()) return "{}";
QString s;
foreach(int index, this->m_values.keys())
{
QVariant qv = this->m_values.value(index);
s.isEmpty() ? s.append("{") : s.append(", ");
s.append('{').append(QString::number(index)).append(": ");
s.append("(").append(QString::number(qv.userType())).append(") ");
QString qvs = BlackMisc::qVariantToString(qv, i18n);
s.append(qvs);
s.append('}');
}
s = s.append("}");
return s;
}
/*
* Marshall to DBus
*/
void CValueMap::marshallToDbus(QDBusArgument &argument) const
{
// remark, tried both sending as QDbusVariant and QVariant
// does not make a difference
QList<int> unifiedBlackTypeIds;
QList<QDBusVariant> dbusVariants;
foreach(QVariant qv, m_values.values())
{
unifiedBlackTypeIds << qv.userType() - BlackMisc::firstBlackMetaType();
dbusVariants << QDBusVariant(qv);
}
argument << this->m_values.keys(); // indexes
argument << dbusVariants;
argument << unifiedBlackTypeIds;
}
/*
* Unmarshall from DBus
*/
void CValueMap::unmarshallFromDbus(const QDBusArgument &argument)
{
QList<int> indexes;
QList<QDBusVariant> values;
QList<int> unifiedBlackTypeIds;
argument >> indexes;
argument >> values;
argument >> unifiedBlackTypeIds;
QMap<int, QVariant> newMap;
for (int i = 0; i < indexes.size(); i++)
{
QVariant qv = values.at(i).variant();
int index = indexes.at(i);
if (qv.canConvert<QDBusArgument>())
{
int userType = unifiedBlackTypeIds.at(i) + BlackMisc::firstBlackMetaType();
QVariant concrete = BlackMisc::fixQVariantFromDbusArgument(qv, userType);
newMap.insert(index, concrete);
}
else
{
// value already OK
newMap.insert(index, qv);
}
}
// replace values in one step
this->m_values.clear();
this->m_values.unite(newMap);
}
/*
* Add value
*/
void CValueMap::addValue(int index, const QVariant &value)
{
this->m_values.insert(index, value);
}
/*
* Register metadata
*/
void CValueMap::registerMetadata()
{
qRegisterMetaType<CValueMap>();
qDBusRegisterMetaType<CValueMap>();
}
/*
* Hash
*/
uint CValueMap::getValueHash() const
{
return qHash(this);
}
} // namespace

150
src/blackmisc/valuemap.h Normal file
View File

@@ -0,0 +1,150 @@
/* Copyright (C) 2013 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/. */
/*!
\file
*/
#include "valueobject.h"
#include <QVariantMap>
#include <QDBusArgument>
#ifndef BLACKMISC_VALUEMAP_H
#define BLACKMISC_VALUEMAP_H
namespace BlackMisc
{
/*!
* \brief Value map
*/
class CValueMap : public CValueObject
{
public:
/*!
* \brief Constructor
* \param wildcard when used in search, for setting values irrelevant
*/
CValueMap(bool wildcard = false);
/*!
* \brief Single value constructor
* \param index
* \param value
*/
CValueMap(int index, const QVariant &value);
/*!
* \brief QVariant, required for DBus QVariant lists
* \return
*/
virtual QVariant toQVariant() const
{
return QVariant::fromValue(*this);
}
/*!
* \brief Destructor
*/
virtual ~CValueMap() {}
/*!
* \brief Add a value
* \param index
* \param value
*/
void addValue(int index, const QVariant &value);
/*!
* \brief Add a value as non QVariant
* \param index
* \param value
*/
template<class T> void addValue(int index, const T &value)
{
this->m_values.insert(index, QVariant::fromValue(value));
}
/*!
* \brief Is empty
* \return
*/
bool isEmpty() const { return this->m_values.isEmpty(); }
/*!
* \brief Value
* \param index
* \return
*/
QVariant value(int index) const { return this->m_values.value(index); }
/*!
* \brief Indexes
* \return
*/
QList<int> indexes() const { return this->m_values.keys(); }
/*!
* \brief values
* \return
*/
QList<QVariant> values() const { return this->m_values.values(); }
/*!
* \brief Wildcard, only relevant when used in search
* \return
*/
bool isWildcard() const { return this->m_wildcard; }
/*!
* \brief clear
*/
void clear() { this->m_values.clear(); }
/*!
* \brief Map
* \return
*/
const QMap<int, QVariant> &map() const { return this->m_values; }
/*!
* \brief Value hash
*/
virtual uint getValueHash() const;
/*!
* \brief Metadata
*/
static void registerMetadata();
protected:
QMap<int, QVariant> m_values; /*!< values */
bool m_wildcard;
/*!
* \brief Meaningful string representation
* \param i18n
* \return
*/
virtual QString convertToQString(bool i18n = false) const;
/*!
* \brief Stream to DBus <<
* \param argument
*/
virtual void marshallToDbus(QDBusArgument &argument) const;
/*!
* \brief Stream from DBus >>
* \param argument
*/
virtual void unmarshallFromDbus(const QDBusArgument &argument);
};
}
Q_DECLARE_METATYPE(BlackMisc::CValueMap)
#endif // guard

View File

@@ -43,6 +43,35 @@ namespace BlackMisc
return this->convertToQString();
}
/*
* Setter for property by index
*/
void CValueObject::setPropertyByIndex(const QVariant & /** variant **/, int /** index **/)
{
// not all classes have to implement this
qFatal("Property by index setter not implemented");
}
/*
* By index
*/
QVariant CValueObject::propertyByIndex(int /** index **/) const
{
// not all classes have to implement this
qFatal("Property by index not implemented");
return QVariant("boom"); // avoid compiler warning
}
/*
* By index as string
*/
QString CValueObject::propertyByIndexAsString(int /** index **/, bool /** i18n **/) const
{
// not all classes have to implement this
qFatal("Property by index as string not implemented");
return QString("boom"); // avoid compiler warning
}
/*
* Return backing streamable object (if any)
*/
@@ -70,6 +99,65 @@ namespace BlackMisc
return -1; // avoid compiler warning
}
/*!
* Variant map
*/
int CValueObject::apply(const BlackMisc::CValueMap &valueMap)
{
if (valueMap.isEmpty()) return 0;
int c = 0;
QMap<int, QVariant>::const_iterator it;
const QMap<int, QVariant> &map = valueMap.map();
for (it = map.begin(); it != map.end(); ++it)
{
this->setPropertyByIndex(it.value(), it.key());
}
return c;
}
/*
* Compare with value map
*/
bool operator==(const CValueMap &valueMap, const CValueObject &uc)
{
if (valueMap.isEmpty()) return valueMap.isWildcard();
QMap<int, QVariant>::const_iterator it;
const QMap<int, QVariant> &map = valueMap.map();
for (it = map.begin(); it != map.end(); ++it)
{
// QVariant cannot be compared directly
QVariant p = uc.propertyByIndex(it.key()); // from value object
QVariant v = it.value(); // from map
if (!BlackMisc::equalQVariants(p, v)) return false;
}
return true;
}
/*
* Compare with value map
*/
bool operator!=(const CValueMap &valueMap, const CValueObject &uc)
{
return !(valueMap == uc);
}
/*
* Compare with value map
*/
bool operator==(const CValueObject &uc, const CValueMap &valueMap)
{
return valueMap == uc;
}
/*
* Compare with value map
*/
bool operator!=(const CValueObject &uc, const CValueMap &valueMap)
{
return !(valueMap == uc);
}
/*
* from DBus
*/

View File

@@ -109,6 +109,38 @@ namespace BlackMisc
*/
friend QDBusArgument &operator<<(QDBusArgument &argument, const CValueObject &uc);
/*!
* \brief Operator == with value map
* \param valueMap
* \param uc
* \return
*/
friend bool operator==(const CValueMap &valueMap, const CValueObject &uc);
/*!
* \brief Operator != with value map
* \param valueMap
* \param uc
* \return
*/
friend bool operator!=(const CValueMap &valueMap, const CValueObject &uc);
/*!
* \brief Operator == with value map
* \param uc
* \param valueMap
* \return
*/
friend bool operator==(const CValueObject &uc, const CValueMap &valueMap);
/*!
* \brief Operator != with value map
* \param uc
* \param valueMap
* \return
*/
friend bool operator!=(const CValueObject &uc, const CValueMap &valueMap);
public:
/*!
* \brief Virtual destructor
@@ -134,6 +166,13 @@ namespace BlackMisc
*/
std::string toStdString(bool i18n = false) const;
/*!
* \brief Update by variant map
* \param valueMap
* \return
*/
int apply(const BlackMisc::CValueMap &valueMap);
/*!
* \brief Value hash, allows comparisons between QVariants
* \return
@@ -155,6 +194,32 @@ namespace BlackMisc
*/
virtual QVariant toQVariant() const = 0;
/*!
* \brief Set property by index
* \remarks Intentionally not abstract, avoiding all classes need to implement this method
* \param index
* \return
*/
virtual void setPropertyByIndex(const QVariant &variant, int index);
/*!
* \brief Property by index
* \remarks Intentionally not abstract, avoiding all classes need to implement this method
* \param index
* \return
*/
virtual QVariant propertyByIndex(int index) const;
/*!
* \brief Property by index as String
* \remarks Intentionally not abstract, avoiding all classes need to implement this method
* \param index
* \param i18n
* \return
*/
virtual QString propertyByIndexAsString(int index, bool i18n = false) const;
/*!
* \brief The stored object as CValueObject
* \param qv