File indexing completed on 2025-02-09 04:28:38
0001 /* 0002 This file is part of the KTextTemplate library 0003 0004 SPDX-FileCopyrightText: 2010 Michael Jansen <kde@michael-jansen.biz> 0005 SPDX-FileCopyrightText: 2010 Stephen Kelly <steveire@gmail.com> 0006 0007 SPDX-License-Identifier: LGPL-2.1-or-later 0008 0009 */ 0010 0011 #include "metatype.h" 0012 0013 #include "customtyperegistry_p.h" 0014 #include "metaenumvariable_p.h" 0015 0016 #include <QAssociativeIterable> 0017 #include <QDebug> 0018 #include <QSequentialIterable> 0019 0020 using namespace KTextTemplate; 0021 0022 Q_GLOBAL_STATIC(CustomTypeRegistry, customTypes) 0023 0024 void KTextTemplate::MetaType::internalLock() 0025 { 0026 return customTypes()->mutex.lock(); 0027 } 0028 0029 void KTextTemplate::MetaType::internalUnlock() 0030 { 0031 return customTypes()->mutex.unlock(); 0032 } 0033 0034 void KTextTemplate::MetaType::registerLookUpOperator(int id, LookupFunction f) 0035 { 0036 Q_ASSERT(id > 0); 0037 Q_ASSERT(f); 0038 0039 customTypes()->registerLookupOperator(id, f); 0040 } 0041 0042 static QVariant doQobjectLookUp(const QObject *const object, const QString &property) 0043 { 0044 if (!object) 0045 return {}; 0046 if (property == QStringLiteral("children")) { 0047 const auto &childList = object->children(); 0048 if (childList.isEmpty()) 0049 return {}; 0050 QVariantList children; 0051 0052 auto it = childList.constBegin(); 0053 const auto end = childList.constEnd(); 0054 for (; it != end; ++it) 0055 children.append(QVariant::fromValue(*it)); 0056 return children; 0057 } 0058 0059 if (property == QStringLiteral("objectName")) { 0060 return object->objectName(); 0061 } 0062 // Can't be const because of invokeMethod. 0063 auto metaObj = object->metaObject(); 0064 0065 QMetaProperty mp; 0066 for (auto i = 0; i < metaObj->propertyCount(); ++i) { 0067 // TODO only read-only properties should be allowed here. 0068 // This might also handle the variant messing I hit before. 0069 mp = metaObj->property(i); 0070 0071 if (QString::fromUtf8(mp.name()) != property) 0072 continue; 0073 0074 if (mp.isEnumType()) { 0075 MetaEnumVariable mev(mp.enumerator(), mp.read(object).value<int>()); 0076 return QVariant::fromValue(mev); 0077 } 0078 0079 return mp.read(object); 0080 } 0081 QMetaEnum me; 0082 for (auto i = 0; i < metaObj->enumeratorCount(); ++i) { 0083 me = metaObj->enumerator(i); 0084 0085 if (QLatin1String(me.name()) == property) { 0086 MetaEnumVariable mev(me); 0087 return QVariant::fromValue(mev); 0088 } 0089 0090 const auto value = me.keyToValue(property.toLatin1().constData()); 0091 0092 if (value < 0) 0093 continue; 0094 0095 const MetaEnumVariable mev(me, value); 0096 0097 return QVariant::fromValue(mev); 0098 } 0099 return object->property(property.toUtf8().constData()); 0100 } 0101 0102 QVariant KTextTemplate::MetaType::lookup(const QVariant &object, const QString &property) 0103 { 0104 if (object.canConvert<QObject *>()) { 0105 return doQobjectLookUp(object.value<QObject *>(), property); 0106 } 0107 if (object.canConvert<QVariantList>()) { 0108 auto iter = object.value<QSequentialIterable>(); 0109 if (property == QStringLiteral("size") || property == QStringLiteral("count")) { 0110 return iter.size(); 0111 } 0112 0113 auto ok = false; 0114 const auto listIndex = property.toInt(&ok); 0115 0116 if (!ok || listIndex >= iter.size()) { 0117 return {}; 0118 } 0119 0120 return iter.at(listIndex); 0121 } 0122 if (object.canConvert<QVariantHash>()) { 0123 auto iter = object.value<QAssociativeIterable>(); 0124 0125 if (iter.find(property) != iter.end()) { 0126 return iter.value(property); 0127 } 0128 0129 if (property == QStringLiteral("size") || property == QStringLiteral("count")) { 0130 return iter.size(); 0131 } 0132 0133 if (property == QStringLiteral("items")) { 0134 auto it = iter.begin(); 0135 const auto end = iter.end(); 0136 QVariantList list; 0137 for (; it != end; ++it) { 0138 list.push_back(QVariantList{it.key(), it.value()}); 0139 } 0140 return list; 0141 } 0142 0143 if (property == QStringLiteral("keys")) { 0144 auto it = iter.begin(); 0145 const auto end = iter.end(); 0146 QVariantList list; 0147 for (; it != end; ++it) { 0148 list.push_back(it.key()); 0149 } 0150 return list; 0151 } 0152 0153 if (property == QStringLiteral("values")) { 0154 auto it = iter.begin(); 0155 const auto end = iter.end(); 0156 QVariantList list; 0157 for (; it != end; ++it) { 0158 list.push_back(it.value()); 0159 } 0160 return list; 0161 } 0162 0163 return {}; 0164 } 0165 auto mo = QMetaType(object.userType()).metaObject(); 0166 if (mo) { 0167 QMetaType mt(object.userType()); 0168 if (mt.flags().testFlag(QMetaType::IsGadget)) { 0169 const auto idx = mo->indexOfProperty(property.toUtf8().constData()); 0170 if (idx >= 0) { 0171 const auto mp = mo->property(idx); 0172 0173 if (mp.isEnumType()) { 0174 MetaEnumVariable mev(mp.enumerator(), mp.readOnGadget(object.constData()).value<int>()); 0175 return QVariant::fromValue(mev); 0176 } 0177 0178 return mp.readOnGadget(object.constData()); 0179 } 0180 0181 QMetaEnum me; 0182 for (auto i = 0; i < mo->enumeratorCount(); ++i) { 0183 me = mo->enumerator(i); 0184 0185 if (QLatin1String(me.name()) == property) { 0186 MetaEnumVariable mev(me); 0187 return QVariant::fromValue(mev); 0188 } 0189 0190 const auto value = me.keyToValue(property.toLatin1().constData()); 0191 0192 if (value < 0) { 0193 continue; 0194 } 0195 0196 MetaEnumVariable mev(me, value); 0197 return QVariant::fromValue(mev); 0198 } 0199 } 0200 } 0201 0202 return customTypes()->lookup(object, property); 0203 } 0204 0205 bool KTextTemplate::MetaType::lookupAlreadyRegistered(int id) 0206 { 0207 return customTypes()->lookupAlreadyRegistered(id); 0208 }