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 }