mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-30 20:15:35 +08:00
refs #247 CVariant uses our new metadata system to provide access to CValueObject operations in a safe manner.
This commit is contained in:
@@ -337,27 +337,25 @@ QVariant BlackMisc::fixQVariantFromDbusArgument(const QVariant &variant, int loc
|
||||
// complex, user type
|
||||
// it has to be made sure, that the cast works
|
||||
const QDBusArgument arg = variant.value<QDBusArgument>();
|
||||
QVariant fixedVariant;
|
||||
if (localUserType < static_cast<int>(QVariant::UserType))
|
||||
{
|
||||
// complex Qt type, e.g. QDateTime
|
||||
fixedVariant = BlackMisc::complexQtTypeFromDbusArgument(arg, localUserType);
|
||||
return BlackMisc::complexQtTypeFromDbusArgument(arg, localUserType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// http://qt-project.org/doc/qt-5.0/qtcore/qmetatype.html#create
|
||||
void *obByMetaId = QMetaType::create(localUserType);
|
||||
|
||||
// own types, send as QDBusArgument
|
||||
CValueObject *streamable = static_cast<CValueObject *>(obByMetaId);
|
||||
arg >> (*streamable);
|
||||
fixedVariant = streamable->toQVariant();
|
||||
QMetaType::destroy(localUserType, obByMetaId);
|
||||
QVariant valueVariant(localUserType, nullptr);
|
||||
auto *meta = Private::getValueObjectMetaInfo(valueVariant);
|
||||
if (meta)
|
||||
{
|
||||
meta->unmarshall(arg, valueVariant.data());
|
||||
return valueVariant;
|
||||
}
|
||||
}
|
||||
return fixedVariant;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "fixQVariantFromDbusArgument called with unsupported type";
|
||||
return variant;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,42 +34,116 @@ namespace BlackMisc
|
||||
|
||||
QString CVariant::toString(bool i18n) const
|
||||
{
|
||||
if (type() == QVariant::UserType)
|
||||
auto *meta = getValueObjectMetaInfo();
|
||||
if (meta)
|
||||
{
|
||||
const CValueObject *s = CValueObject::fromQVariant(m_v); // FIXME this will return garbage if value is not a CValueObject
|
||||
Q_ASSERT(s);
|
||||
if (s)
|
||||
return meta->toQString(data(), i18n);
|
||||
}
|
||||
return m_v.toString();
|
||||
}
|
||||
|
||||
int BlackMisc::compare(const CVariant &a, const CVariant &b)
|
||||
{
|
||||
if (a.userType() < b.userType()) { return -1; }
|
||||
if (a.userType() > b.userType()) { return 1; }
|
||||
auto *metaA = a.getValueObjectMetaInfo();
|
||||
auto *metaB = b.getValueObjectMetaInfo();
|
||||
if (metaA && metaB)
|
||||
{
|
||||
const void *casted = nullptr;
|
||||
if ((casted = metaA->upCastTo(a.data(), metaB->getMetaTypeId())))
|
||||
{
|
||||
return s->toQString(i18n);
|
||||
return metaB->compare(casted, b.data());
|
||||
}
|
||||
else if ((casted = metaB->upCastTo(b.data(), metaA->getMetaTypeId())))
|
||||
{
|
||||
return metaA->compare(a.data(), casted);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "No CValueObject, no string conversion";
|
||||
qWarning() << "Comparing two CVariants containing unrelated value objects";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return m_v.toString();
|
||||
if (a.m_v < b.m_v) { return -1; }
|
||||
if (a.m_v > b.m_v) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
QJsonObject CVariant::toJson() const
|
||||
{
|
||||
QJsonObject json;
|
||||
json.insert("type", static_cast<int>(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));
|
||||
json.insert("type", this->typeName());
|
||||
|
||||
switch (m_v.type())
|
||||
{
|
||||
case QVariant::Int: json.insert("value", m_v.toInt());
|
||||
case QVariant::UInt: json.insert("value", m_v.toInt());
|
||||
case QVariant::Bool: json.insert("value", m_v.toBool());
|
||||
case QVariant::Double: json.insert("value", m_v.toDouble());
|
||||
case QVariant::LongLong: json.insert("value", m_v.toLongLong());
|
||||
case QVariant::ULongLong: json.insert("value", m_v.toLongLong());
|
||||
case QVariant::String: json.insert("value", m_v.toString());
|
||||
case QVariant::Char: json.insert("value", m_v.toString());
|
||||
case QVariant::ByteArray: json.insert("value", m_v.toString());
|
||||
default:
|
||||
{
|
||||
auto *meta = getValueObjectMetaInfo();
|
||||
if (meta)
|
||||
{
|
||||
json.insert("value", meta->toJson(data()));
|
||||
}
|
||||
else if (m_v.canConvert<QString>())
|
||||
{
|
||||
json.insert("value", m_v.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Unsupported CVariant type for toJson";
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
QString typeName = json.value("type").toString();
|
||||
int typeId = QMetaType::type(qPrintable(typeName));
|
||||
|
||||
// KB: Not yet implemented, but would be possible IMHO
|
||||
Q_ASSERT(false);
|
||||
qDebug() << type << userType << typeName << value;
|
||||
switch (typeId)
|
||||
{
|
||||
case QVariant::Int: m_v.setValue(json.value("value").toInt());
|
||||
case QVariant::UInt: m_v.setValue<uint>(json.value("value").toInt());
|
||||
case QVariant::Bool: m_v.setValue(json.value("value").toBool());
|
||||
case QVariant::Double: m_v.setValue(json.value("value").toDouble());
|
||||
case QVariant::LongLong: m_v.setValue<qlonglong>(json.value("value").toInt()); // QJsonValue has no toLongLong() method???
|
||||
case QVariant::ULongLong: m_v.setValue<qulonglong>(json.value("value").toInt());
|
||||
case QVariant::String: m_v.setValue(json.value("value").toString());
|
||||
case QVariant::Char: m_v.setValue(json.value("value").toString().size() > 0 ? json.value("value").toString().at(0) : '\0');
|
||||
case QVariant::ByteArray: m_v.setValue(json.value("value").toString().toLatin1());
|
||||
default:
|
||||
{
|
||||
auto *meta = Private::getValueObjectMetaInfo(typeId);
|
||||
if (meta)
|
||||
{
|
||||
m_v = QVariant(typeId, nullptr);
|
||||
meta->convertFromJson(json.value("value").toObject(), data());
|
||||
}
|
||||
else if (QMetaType::hasRegisteredConverterFunction(qMetaTypeId<QString>(), typeId))
|
||||
{
|
||||
m_v.setValue(json.value("value").toString());
|
||||
if (! m_v.convert(typeId))
|
||||
{
|
||||
qWarning() << "Failed to convert from JSON string";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Unsupported CVariant type for fromJson";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint CVariant::getValueHash() const
|
||||
@@ -87,10 +161,10 @@ namespace BlackMisc
|
||||
case QVariant::ByteArray: return qHash(m_v.toByteArray());
|
||||
default:
|
||||
{
|
||||
const CValueObject *cv = CValueObject::fromQVariant(m_v);
|
||||
if (cv)
|
||||
auto *meta = getValueObjectMetaInfo();
|
||||
if (meta)
|
||||
{
|
||||
return cv->getValueHash();
|
||||
return meta->getValueHash(data());
|
||||
}
|
||||
else if (m_v.canConvert<QString>())
|
||||
{
|
||||
|
||||
@@ -25,7 +25,8 @@ namespace BlackMisc
|
||||
{
|
||||
|
||||
/*!
|
||||
* Wrapper class for QVariant, for more natural and transparent DBus integration.
|
||||
* Wrapper around QVariant which provides transparent access to CValueObject methods
|
||||
* of the contained object if it is registered with BlackMisc::registerMetaValueType.
|
||||
*/
|
||||
class CVariant
|
||||
{
|
||||
@@ -133,8 +134,7 @@ namespace BlackMisc
|
||||
bool isValid() const { return m_v.isValid(); }
|
||||
|
||||
//! Return the metatype ID of the value in this variant, or QMetaType::User if it is a user type.
|
||||
// KB we should think about returning QMetaType::Type directly, as QVariant::Type is deprecated
|
||||
QVariant::Type type() const { return m_v.type(); }
|
||||
QMetaType::Type type() const { return static_cast<QMetaType::Type>(m_v.type()); }
|
||||
|
||||
//! Return the typename of the value in this variant.
|
||||
const char *typeName() const { return m_v.typeName(); }
|
||||
@@ -149,28 +149,35 @@ namespace BlackMisc
|
||||
void fromJson(const QJsonObject &json);
|
||||
|
||||
//! Equal operator.
|
||||
bool operator ==(const CVariant &other) const { return m_v == other.m_v; }
|
||||
friend bool operator ==(const CVariant &a, const CVariant &b) { return compare(a, b) == 0; }
|
||||
|
||||
//! Not equal operator.
|
||||
bool operator !=(const CVariant &other) const { return m_v != other.m_v; }
|
||||
friend bool operator !=(const CVariant &a, const CVariant &b) { return !(a == b); }
|
||||
|
||||
//! Less than operator.
|
||||
bool operator <(const CVariant &other) const { return m_v < other.m_v; }
|
||||
friend bool operator <(const CVariant &a, const CVariant &b) { return compare(a, b) < 0; }
|
||||
|
||||
//! Less than or equal operator.
|
||||
bool operator <=(const CVariant &other) const { return m_v <= other.m_v; }
|
||||
friend bool operator <=(const CVariant &a, const CVariant &b) { return !(b < a); }
|
||||
|
||||
//! Greater than operator.
|
||||
bool operator >(const CVariant &other) const { return m_v > other.m_v; }
|
||||
friend bool operator >(const CVariant &a, const CVariant &b) { return b < a; }
|
||||
|
||||
//! Greater than or equal operator.
|
||||
bool operator >=(const CVariant &other) const { return m_v >= other.m_v; }
|
||||
friend bool operator >=(const CVariant &a, const CVariant &b) { return !(a < b); }
|
||||
|
||||
//! Arbitrary comparison
|
||||
friend int compare(const CVariant &a, const CVariant &b);
|
||||
|
||||
//! Register metadata.
|
||||
static void registerMetadata();
|
||||
|
||||
private:
|
||||
QVariant m_v;
|
||||
|
||||
Private::IValueObjectMetaInfo *getValueObjectMetaInfo() const { return Private::getValueObjectMetaInfo(m_v); }
|
||||
void *data() { return m_v.data(); }
|
||||
const void *data() const { return m_v.data(); }
|
||||
};
|
||||
|
||||
//! Marshall a variant to DBus.
|
||||
@@ -234,4 +241,4 @@ namespace BlackMisc
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::CVariant)
|
||||
|
||||
#endif // guard
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user