8 #include <QDBusArgument>
9 #include <QDBusVariant>
10 #include <QDataStream>
30 int qMetaTypeId_CVariantList = -1;
32 private_ns::IValueObjectMetaInfo *private_ns::getValueObjectMetaInfo(
int typeId)
34 return getValueObjectMetaInfo(QVariant(QMetaType(typeId),
nullptr));
37 private_ns::IValueObjectMetaInfo *private_ns::getValueObjectMetaInfo(
const QVariant &v)
39 return v.value<IValueObjectMetaInfo *>();
44 if (m_v.canConvert(typeId)) {
return true; }
45 if (typeId == qMetaTypeId_CVariantList)
47 return m_v.canConvert<QVector<CVariant>>() || m_v.canConvert<QVariantList>();
49 if (
userType() == qMetaTypeId_CVariantList)
51 return QVariant::fromValue(QVector<CVariant>()).canConvert(typeId) ||
52 QVariant(QMetaType(typeId),
nullptr).canConvert<QVariantList>();
59 if (!m_v.canConvert(typeId))
62 if (typeId == qMetaTypeId_CVariantList)
64 if (m_v.canConvert<QVector<CVariant>>())
66 if (!m_v.convert(qMetaTypeId<QVector<CVariant>>())) {
return false; }
68 else if (m_v.canConvert<QVariantList>())
70 QVector<CVariant> vec;
71 const auto seqit = m_v.value<QSequentialIterable>();
72 vec.reserve(seqit.size());
73 for (
auto it = seqit.begin(); it != seqit.end(); ++it) { vec.push_back(*it); }
76 else {
return false; }
78 if (
userType() == qMetaTypeId_CVariantList)
80 if (QVariant::fromValue(QVector<CVariant>()).canConvert(typeId))
82 if (!m_v.convert(qMetaTypeId<QVector<CVariant>>())) {
return false; }
84 else {
return false; }
87 return m_v.convert(typeId);
90 bool CVariant::isVariantList()
const {
return userType() == qMetaTypeId_CVariantList; }
94 auto *meta = getValueObjectMetaInfo();
95 if (meta) {
return meta->toQString(data(), i18n); }
96 return m_v.toString();
103 case QMetaType::Bool:
104 case QMetaType::Char:
105 case QMetaType::UChar:
106 case QMetaType::SChar:
107 case QMetaType::Short:
108 case QMetaType::UShort:
110 case QMetaType::UInt:
111 case QMetaType::Long:
112 case QMetaType::ULong:
113 case QMetaType::LongLong:
114 case QMetaType::ULongLong:
return true;
115 default:
return false;
126 if (this->
type() == QMetaType::LongLong) {
return this->
toLongLong(ok); }
127 return this->
toInt(ok);
130 int CVariant::compareImpl(
const CVariant &a,
const CVariant &b)
132 if (a.userType() < b.userType()) {
return -1; }
133 if (a.userType() > b.userType()) {
return 1; }
134 auto *aMeta = a.getValueObjectMetaInfo();
135 auto *bMeta = b.getValueObjectMetaInfo();
140 const void *casted =
nullptr;
141 if ((casted = aMeta->upCastTo(a.data(), bMeta->getMetaTypeId())))
143 return bMeta->compareImpl(casted, b.data());
145 else if ((casted = bMeta->upCastTo(b.data(), aMeta->getMetaTypeId())))
147 return aMeta->compareImpl(a.data(), casted);
151 CLogMessage(&a).warning(
152 u
"Comparing two CVariants containing unrelated value objects: %1 (%2) and %3 (%4)")
153 << a.typeName() << a.userType() << b.typeName() << b.userType();
157 catch (
const private_ns::CVariantException &ex)
159 CLogMessage(&a).debug() << ex.what();
163 const QPartialOrdering order = QVariant::compare(a.m_v, b.m_v);
164 if (order == QPartialOrdering::Less) {
return -1; }
165 if (order == QPartialOrdering::Greater) {
return 1; }
172 json.insert(
"type", this->
typeName());
176 case QVariant::Invalid: json.insert(
"value", 0);
break;
177 case QVariant::Int: json.insert(
"value", m_v.toInt());
break;
178 case QVariant::UInt: json.insert(
"value", m_v.toInt());
break;
179 case QVariant::Bool: json.insert(
"value", m_v.toBool());
break;
180 case QVariant::Double: json.insert(
"value", m_v.toDouble());
break;
181 case QVariant::LongLong: json.insert(
"value", m_v.toLongLong());
break;
182 case QVariant::ULongLong: json.insert(
"value", m_v.toLongLong());
break;
183 case QVariant::String: json.insert(
"value", m_v.toString());
break;
184 case QVariant::Char: json.insert(
"value", m_v.toString());
break;
185 case QVariant::ByteArray: json.insert(
"value", m_v.toString());
break;
186 case QVariant::DateTime: json.insert(
"value", m_v.toDateTime().toString(Qt::ISODate));
break;
187 case QVariant::Date: json.insert(
"value", m_v.toDate().toString(Qt::ISODate));
break;
188 case QVariant::Time: json.insert(
"value", m_v.toTime().toString(Qt::ISODate));
break;
189 case QVariant::StringList: json.insert(
"value", QJsonArray::fromStringList(m_v.toStringList()));
break;
193 auto *meta = getValueObjectMetaInfo();
194 if (meta) { json.insert(
"value", meta->toJson(data())); }
195 else if (m_v.canConvert<QString>()) { json.insert(
"value", m_v.toString()); }
198 CLogMessage(
this).warning(u
"Unsupported CVariant type for toJson: %1 (%2)")
202 catch (
const private_ns::CVariantException &ex)
204 CLogMessage(
this).debug() << ex.what();
212 QJsonDocument jsonDoc(
toJson());
213 return jsonDoc.toJson(format);
220 const QJsonValue typeValue = json.value(
"type");
221 if (typeValue.isUndefined()) {
throw CJsonException(
"Missing 'type'"); }
222 const QString
typeName = typeValue.toString();
228 const int typeId = QMetaType::type(qPrintable(
typeName));
230 const QJsonValue
value = json.value(
"value");
231 if (
value.isUndefined()) {
throw CJsonException(
"Missing 'value'"); }
234 case QVariant::Invalid:
throw CJsonException(
"Type not recognized by QMetaType");
235 case QVariant::Int: m_v.setValue(
value.toInt());
break;
236 case QVariant::UInt: m_v.setValue<uint>(
static_cast<uint
>(
value.toInt()));
break;
237 case QVariant::Bool: m_v.setValue(
value.toBool());
break;
238 case QVariant::Double: m_v.setValue(
value.toDouble());
break;
239 case QVariant::LongLong: m_v.setValue(
static_cast<qlonglong
>(
value.toDouble()));
break;
240 case QVariant::ULongLong: m_v.setValue(
static_cast<qulonglong
>(
value.toDouble()));
break;
241 case QVariant::String: m_v.setValue(
value.toString());
break;
242 case QVariant::Char: m_v.setValue(
value.toString().size() > 0 ?
value.toString().at(0) :
'\0');
break;
243 case QVariant::ByteArray: m_v.setValue(
value.toString().toLatin1());
break;
244 case QVariant::DateTime: m_v.setValue(
fromStringUtc(
value.toString(), Qt::ISODate));
break;
245 case QVariant::Date: m_v.setValue(QDate::fromString(
value.toString(), Qt::ISODate));
break;
246 case QVariant::Time: m_v.setValue(QTime::fromString(
value.toString(), Qt::ISODate));
break;
247 case QVariant::StringList: m_v.setValue(QVariant(
value.toArray().toVariantList()).toStringList());
break;
251 auto *meta = private_ns::getValueObjectMetaInfo(typeId);
254 CJsonScope scope(
"value");
256 m_v = QVariant(QMetaType(typeId),
nullptr);
259 meta->convertFromMemoizedJson(
value.toObject(), data(),
true);
261 else if (QMetaType::hasRegisteredConverterFunction(QMetaType(qMetaTypeId<QString>()),
264 m_v.setValue(
value.toString());
265 if (!m_v.convert(typeId)) {
throw CJsonException(
"Failed to convert from JSON string"); }
267 else {
throw CJsonException(
"Type not supported by convertFromJson"); }
269 catch (
const private_ns::CVariantException &ex)
271 throw CJsonException(ex.what());
277 const QString &prefix)
283 catch (
const CJsonException &ex)
292 auto *meta = getValueObjectMetaInfo();
298 json.insert(
"type", this->
typeName());
299 json.insert(
"value", meta->toMemoizedJson(data()));
302 catch (
const private_ns::CVariantException &ex)
304 CLogMessage(
this).debug() << ex.what();
313 QJsonValue typeValue = json.value(
"type");
314 if (typeValue.isUndefined()) {
throw CJsonException(
"Missing 'type'"); }
315 QString
typeName = typeValue.toString();
321 int typeId = QMetaType::type(qPrintable(
typeName));
323 auto *meta = private_ns::getValueObjectMetaInfo(typeId);
328 QJsonValue
value = json.value(
"value");
329 if (
value.isUndefined()) {
throw CJsonException(
"Missing 'value'"); }
331 CJsonScope scope(
"value");
332 m_v = QVariant(QMetaType(typeId),
nullptr);
333 meta->convertFromMemoizedJson(
value.toObject(), data(), allowFallbackToJson);
335 catch (
const private_ns::CVariantException &ex)
337 throw CJsonException(ex.what());
344 const QString &prefix)
350 catch (
const CJsonException &ex)
357 size_t CVariant::getValueHash()
const
361 case QVariant::Invalid:
return 0;
362 case QVariant::Int:
return qHash(m_v.toInt());
363 case QVariant::UInt:
return qHash(m_v.toUInt());
364 case QVariant::Bool:
return qHash(m_v.toUInt());
365 case QVariant::Double:
return qHash(m_v.toUInt());
366 case QVariant::LongLong:
return qHash(m_v.toLongLong());
367 case QVariant::ULongLong:
return qHash(m_v.toULongLong());
368 case QVariant::String:
return qHash(m_v.toString());
369 case QVariant::Char:
return qHash(m_v.toChar());
370 case QVariant::ByteArray:
return qHash(m_v.toByteArray());
374 auto *meta = getValueObjectMetaInfo();
375 if (meta) {
return meta->getValueHash(data()); }
376 else if (m_v.canConvert<QString>()) {
return qHash(m_v.toString()); }
379 CLogMessage(
this).warning(u
"Unsupported CVariant type for getValueHash: %1 (%2)")
384 catch (
const private_ns::CVariantException &ex)
386 CLogMessage(
this).debug() << ex.what();
395 else { arg << QString() << QDBusVariant(QVariant(0)); }
403 QVariant fixQVariantFromDbusArgument(
const QVariant &variant,
int localUserType,
const QString &typeName);
404 QVariant complexQtTypeFromDbusArgument(
const QDBusArgument &argument,
int type);
410 QDBusVariant dbusVar;
416 *
this = fixQVariantFromDbusArgument(dbusVar.variant(), QMetaType::type(qPrintable(
typeName)),
typeName);
426 auto *meta = getValueObjectMetaInfo();
430 meta->setPropertyByIndex(data(), variant, index);
432 catch (
const private_ns::CVariantException &ex)
434 CLogMessage(
this).debug() << ex.what();
440 auto *meta = getValueObjectMetaInfo();
445 meta->propertyByIndex(data(), result, index);
448 catch (
const private_ns::CVariantException &ex)
450 CLogMessage(
this).debug() << ex.what();
457 auto *meta = getValueObjectMetaInfo();
461 return meta->equalsPropertyByIndex(data(), compareValue, index);
463 catch (
const private_ns::CVariantException &ex)
465 CLogMessage(
this).debug() << ex.what();
472 auto *meta = getValueObjectMetaInfo();
473 if (!meta) {
return {}; }
478 catch (
const private_ns::CVariantException &ex)
480 CLogMessage(
this).debug() << ex.what();
481 return CIcons::StandardIconError16;
487 if (m_v.type() == QVariant::Pixmap) {
return m_v.value<QPixmap>(); }
488 if (m_v.type() == QVariant::Image) {
return QPixmap::fromImage(m_v.value<QImage>()); }
489 if (m_v.type() == QVariant::Icon) {
return iconToPixmap(m_v.value<QIcon>()); }
491 return CIcon(
toIcon()).toPixmap();
502 if (metaTypeId == QMetaType::UnknownType) {
return false; }
509 if (!
isValid()) {
return false; }
510 auto *meta = getValueObjectMetaInfo();
513 CLogMessage(
this).warning(u
"Invalid type for CVariant::matches: %1") <<
typeName();
518 return meta->matches(data(),
value);
520 catch (
const private_ns::CVariantException &ex)
522 CLogMessage(
this).debug() << ex.what();
527 QVariant fixQVariantFromDbusArgument(
const QVariant &variant,
int localUserType,
const QString &typeName)
529 if (localUserType ==
static_cast<int>(QVariant::Invalid))
531 CLogMessage(&variant).warning(u
"Invalid type for unmarshall: %1") << typeName;
535 if (!variant.canConvert<QDBusArgument>()) {
return variant; }
539 const QDBusArgument arg = variant.value<QDBusArgument>();
540 constexpr
int userType =
static_cast<int>(QVariant::UserType);
541 if (localUserType < userType)
544 return complexQtTypeFromDbusArgument(arg, localUserType);
546 else if (QMetaType(localUserType).flags() & QMetaType::IsEnumeration)
548 arg.beginStructure();
553 QVariant valueVariant = QVariant::fromValue(i);
554 bool ok = valueVariant.convert(localUserType);
555 Q_ASSERT_X(ok, Q_FUNC_INFO,
"int could not be converted to enum");
561 QVariant valueVariant(QMetaType(localUserType),
nullptr);
562 auto *meta = private_ns::getValueObjectMetaInfo(valueVariant);
565 meta->unmarshall(arg, valueVariant.data());
568 Q_ASSERT_X(
false, Q_FUNC_INFO,
"no meta");
573 QVariant complexQtTypeFromDbusArgument(
const QDBusArgument &argument,
int type)
579 case QMetaType::QDateTime:
583 return QVariant::fromValue(dt);
585 case QMetaType::QDate:
589 return QVariant::fromValue(date);
591 case QMetaType::QTime:
595 return QVariant::fromValue(time);
599 const char *name = QMetaType::typeName(type);
600 qFatal(
"Type cannot be resolved: %s (%d)", name ? name :
"", type);
IconIndex
Index for each icon, allows to send them via DBus, efficiently store them, etc.
Non-owning reference to a CPropertyIndex with a subset of its features.
static CStatusMessage fromJsonException(const CJsonException &ex, const CLogCategoryList &categories, const QString &prefix)
Object from JSON exception message.
friend size_t qHash(const CVariant &var)
qHash overload, needed for storing value in a QSet.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
void marshallToDbus(QDBusArgument &argument) const
Marshall without begin/endStructure, for when composed within another object.
CStatusMessage convertFromMemoizedJsonNoThrow(const QJsonObject &json, const CLogCategoryList &categories, const QString &prefix)
Call convertFromMemoizedJson, catch any CJsonException that is thrown and return it as CStatusMessage...
T value() const
Return the value converted to the type T.
bool isIntegral() const
True if this variant's type is an integral type.
QJsonObject toMemoizedJson() const
To compact JSON format.
CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
void unmarshalFromDataStream(QDataStream &stream)
Unmarshal a value from a QDataStream.
static void registerMetadata()
Register metadata.
qint64 toQInt64(bool *ok=nullptr) const
COnvert to qint64, which is used for all timestamps.
bool canConvert() const
True if this variant can be converted to the type T.
QString getClassName() const
Class name.
void convertFromMemoizedJson(const QJsonObject &json, bool allowFallbackToJson)
From compact JSON format.
void unmarshallFromDbus(const QDBusArgument &argument)
Unmarshall without begin/endStructure, for when composed within another object.
bool convert(int typeId)
Convert this variant to the type with the given metatype ID and return true if successful.
int userType() const
Return the metatype ID of the value in this variant.
bool isValid() const
True if this variant is valid.
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
bool equalsPropertyByIndex(const CVariant &compareValue, CPropertyIndexRef index) const
Is given variant equal to value of property index?
const char * typeName() const
Return the typename of the value in this variant.
bool isArithmetic() const
True if this variant's type is an integral or floating-point type.
const QVariant & getQVariant() const
Return the internal QVariant.
bool matches(const CVariant &event) const
If this is an event subscription, return true if it matches the given event.
QMetaType::Type type() const
Return the metatype ID of the value in this variant, or QMetaType::User if it is a user type.
qlonglong toLongLong(bool *ok=nullptr) const
Convert this variant to a longlong integer.
void marshalToDataStream(QDataStream &stream) const
Marshal a value to a QDataStream.
CVariant()
Default constructor.
QString convertToQString(bool i18n=false) const
Cast as QString.
CStatusMessage convertFromJsonNoThrow(const QJsonObject &json, const CLogCategoryList &categories, const QString &prefix)
Call convertFromJson, catch any CJsonException that is thrown and return it as CStatusMessage.
int toInt(bool *ok=nullptr) const
Convert this variant to an integer.
QPixmap toPixmap() const
Corresponding pixmap.
int getMetaTypeId() const
Returns the Qt meta type ID of this object.
bool isA(int metaTypeId) const
Returns true if this object is an instance of the class with the given meta type ID,...
QJsonObject toJson() const
Cast to JSON object.
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
Free functions in swift::misc.
SWIFT_MISC_EXPORT QPixmap iconToPixmap(const QIcon &icon)
Icon to pixmap.
SWIFT_MISC_EXPORT QDateTime fromStringUtc(const QString &dateTimeString, const QString &format)
Same as QDateTime::fromString but QDateTime will be set to UTC.