File indexing completed on 2025-01-05 04:26:49
0001 /* 0002 * Replacement fot QT Bindings that were removed from QT5 0003 * Copyright (C) 2020 Pedro de Carvalho Gomes <pedrogomes81@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 #ifndef QTBINDING_H 0020 #define QTBINDING_H 0021 0022 #include <QJSEngine> 0023 #include <QMetaMethod> 0024 #include <QRegularExpression> 0025 #include <QSet> 0026 0027 namespace QtBindings { 0028 /** Base template for QT bindings 0029 * IMPORTANT: for methods do be correctly exported, static methods must be 0030 * annotated with Q_INVOKABLE, and object methods must be declared as public slots 0031 * */ 0032 template<class T> class Base 0033 { 0034 public: 0035 /** 0036 * Export type to the JS engine 0037 * @param engine 0038 * @param parentObject 0039 */ 0040 static void installJSType( QJSEngine *engine ) 0041 { 0042 if (!engine) return; 0043 0044 // Install type only once along program execution 0045 if ( !QMetaType::isRegistered( QMetaType::type( typeName ) ) ) { 0046 qRegisterMetaType<T>( typeName ); 0047 qRegisterMetaType<T>( typeNameRef ); 0048 qRegisterMetaType<T*>( typeNamePtr ); 0049 qRegisterMetaType<T>( "const " + typeName ); 0050 qRegisterMetaType<T>( "const " + typeNameRef ); 0051 qRegisterMetaType<T*>( "const " + typeNamePtr ); 0052 0053 /* Converter allows passing parameters to C++ via value and const-ref */ 0054 bool conv = QMetaType::registerConverter<QObject*,T>( [] (QObject* qObjPtr) { 0055 const T* dataPtr = qobject_cast<T*>( qObjPtr ); 0056 return (dataPtr == nullptr) ? T() : T( *dataPtr ) ; 0057 }); 0058 Q_ASSERT(conv); 0059 } 0060 0061 QJSValue scopeObj = engine->globalObject(); 0062 0063 // Export type to each JS engine only once - Test if not defined yet 0064 if ( scopeObj.property( qTypeName ).isUndefined() ) { 0065 scopeObj.setProperty( qTypeName, engine->newQMetaObject<T>()); 0066 0067 QJSValue classObj = engine->newQObject( new T() ); 0068 // Add static methods to the associated JS object 0069 for ( const QString& methodName : getStaticMethods() ) { 0070 scopeObj.property( qTypeName ) 0071 .setProperty( methodName, classObj.property( methodName ) ); 0072 } 0073 } 0074 } 0075 0076 static QSet<QString> getStaticMethods() 0077 { 0078 const QMetaObject classObj = T::staticMetaObject; 0079 QSet<QString> methodList; 0080 for (int i = classObj.methodOffset(); i < classObj.methodCount(); i++) { 0081 /* TODO - non-static methods are filtered out by being slots since 0082 * tags do not work for Q_INVOKABLE. Change this to tags if fixed */ 0083 if (classObj.method(i).methodType() == QMetaMethod::Method) 0084 methodList << classObj.method(i).name(); 0085 } 0086 return methodList; 0087 } 0088 0089 protected: 0090 static const QByteArray typeName; 0091 static const QByteArray typeNamePtr; 0092 static const QByteArray typeNameRef; 0093 static const QString qTypeName; 0094 0095 /** 0096 * Mirrors a QObject tree into a JS object 0097 * 0098 * @param rootObject top object in the tree 0099 * @param engine javascript engine object that the tree belongs to 0100 * @return a Javascript object with the top QObject of the tree 0101 */ 0102 QJSValue mirrorObjectTree( QObject* rootObject, QJSEngine* engine ) { 0103 0104 QJSValue rootJSValue = engine->newQObject( rootObject ); 0105 0106 for (QObject* childObject : rootObject->findChildren<QObject*>( QString(), Qt::FindDirectChildrenOnly ) ) { 0107 QJSValue childJSValue = mirrorObjectTree( childObject, engine ) ; 0108 rootJSValue.setProperty( childObject->objectName(), childJSValue ); 0109 } 0110 return rootJSValue; 0111 } 0112 }; 0113 0114 // Remove namespace 0115 template<class T> const QByteArray Base<T>::typeName = QString( T::staticMetaObject.className() ) 0116 .remove( QRegularExpression( "^.*::" ) ).toLatin1(); 0117 template<class T> const QByteArray Base<T>::typeNamePtr = typeName + "*"; 0118 template<class T> const QByteArray Base<T>::typeNameRef = typeName + "&"; 0119 template<class T> const QString Base<T>::qTypeName( "Q" + typeName ); 0120 } 0121 0122 0123 #endif //QTBINDING_H