From cb9ae04826bbee940325bfe462153d05e93ef63f Mon Sep 17 00:00:00 2001 From: David Beck Date: Fri, 29 Mar 2024 15:46:36 +0100 Subject: [PATCH] Implement Qt property access --- inc/finalmq/Qt/qt.h | 238 ++++++++++++++++++++++++++++---------- inc/finalmq/Qt/qtdata.fmq | 8 +- 2 files changed, 178 insertions(+), 68 deletions(-) diff --git a/inc/finalmq/Qt/qt.h b/inc/finalmq/Qt/qt.h index 431e9b2d..ad834156 100644 --- a/inc/finalmq/Qt/qt.h +++ b/inc/finalmq/Qt/qt.h @@ -157,10 +157,10 @@ class FillObjectTree : public IObjectVisitor { QLayout* layout = (QLayout*)&object; QRect rect = layout->geometry(); - objectData->properties.push_back({ "x", std::to_string(rect.x()) }); - objectData->properties.push_back({ "y", std::to_string(rect.y()) }); - objectData->properties.push_back({ "width", std::to_string(rect.width()) }); - objectData->properties.push_back({ "height", std::to_string(rect.height()) }); + objectData->properties.push_back({ "left", std::to_string(rect.left()) }); + objectData->properties.push_back({ "top", std::to_string(rect.top()) }); + objectData->properties.push_back({ "right", std::to_string(rect.right()) }); + objectData->properties.push_back({ "bottom", std::to_string(rect.bottom()) }); objectData->properties.push_back({ "enabled", std::to_string(layout->isEnabled()) }); } @@ -197,7 +197,7 @@ class FillObjectTree : public IObjectVisitor if (value.canConvert()) { QRect rect = value.toRect(); - v = "{\"x\":" + QString::number(rect.x()) + ",\"y\":" + QString::number(rect.y()) + ",\"width\":" + QString::number(rect.width()) + ",\"height\":" + QString::number(rect.height()) + "}"; + v = "{\"left\":" + QString::number(rect.left()) + ",\"top\":" + QString::number(rect.top()) + ",\"right\":" + QString::number(rect.right()) + ",\"bottom\":" + QString::number(rect.bottom()) + "}"; } else if (value.canConvert()) { @@ -311,66 +311,128 @@ class QtInvoker : public RemoteEntity const std::string* methodName = requestContext->getMetainfo("PATH_method"); if (objId && methodName) { - ZeroCopyBuffer buffer; - SerializerQt serializerQt(buffer, SerializerQt::Mode::WRAPPED_BY_QVARIANTLIST); - ParserProto parserProto(serializerQt, request->data.data(), request->data.size()); - parserProto.parseStruct(request->type); - - QByteArray bufferByteArray; - bufferByteArray.reserve(static_cast(buffer.size())); - const std::list& chunks = buffer.chunks(); - for (const auto& chunk : chunks) + QObject* obj; + QMetaMethod metaMethod; + QMetaProperty metaProperty; + bool propertySet = false; + const std::string& typeName = getTypeName(*objId, *methodName, obj, metaMethod, metaProperty, propertySet); + if ((obj != nullptr) && (typeName == request->type)) { - bufferByteArray.append(chunk.data(), static_cast(chunk.size())); - } + if (metaMethod.isValid()) + { + found = true; - QVariantList parameters; - QDataStream s(bufferByteArray); - s >> parameters; + ZeroCopyBuffer buffer; + SerializerQt serializerQt(buffer, SerializerQt::Mode::WRAPPED_BY_QVARIANTLIST); + ParserProto parserProto(serializerQt, request->data.data(), request->data.size()); + parserProto.parseStruct(request->type); - std::array genericArguments; - for (int i = 0; i < parameters.length(); ++i) - { - const QVariant& parameter = parameters[i]; - genericArguments[i] = QGenericArgument(parameter.typeName(), parameter.constData()); - } + QByteArray bufferByteArray; + bufferByteArray.reserve(static_cast(buffer.size())); + const std::list& chunks = buffer.chunks(); + for (const auto& chunk : chunks) + { + bufferByteArray.append(chunk.data(), static_cast(chunk.size())); + } - QObject* obj; - QMetaMethod metaMethod; - const std::string& typeName = getTypeName(*objId, *methodName, obj, metaMethod); - if ((obj != nullptr) && metaMethod.isValid() && (typeName == request->type)) - { - found = true; - QVariant returnValue(QMetaType::type(metaMethod.typeName()), - static_cast(NULL)); - - QGenericReturnArgument returnArgument( - metaMethod.typeName(), - const_cast(returnValue.constData()) - ); - metaMethod.invoke(obj, returnArgument, - genericArguments[0], genericArguments[1], genericArguments[2], - genericArguments[3], genericArguments[4], genericArguments[5], - genericArguments[6], genericArguments[7], genericArguments[8], genericArguments[9]); - - QByteArray retQtBuffer; - QDataStream s(&retQtBuffer, QIODevice::WriteOnly); - s << returnValue; - - std::string retTypeName = getReturnTypeName(metaMethod.typeName()); - - GeneralMessage replyMessage; - if (!retTypeName.empty()) + QVariantList parameters; + QDataStream streamInParams(bufferByteArray); + streamInParams >> parameters; + + std::array genericArguments; + for (int i = 0; i < parameters.length(); ++i) + { + const QVariant& parameter = parameters[i]; + genericArguments[i] = QGenericArgument(parameter.typeName(), parameter.constData()); + } + + QVariant returnValue(QMetaType::type(metaMethod.typeName()), + static_cast(NULL)); + + QGenericReturnArgument returnArgument( + metaMethod.typeName(), + const_cast(returnValue.constData()) + ); + metaMethod.invoke(obj, returnArgument, + genericArguments[0], genericArguments[1], genericArguments[2], + genericArguments[3], genericArguments[4], genericArguments[5], + genericArguments[6], genericArguments[7], genericArguments[8], genericArguments[9]); + + QByteArray retQtBuffer; + QDataStream streamRetParam(&retQtBuffer, QIODevice::WriteOnly); + streamRetParam << returnValue; + + std::string retTypeName = getReturnTypeName(metaMethod.typeName()); + + GeneralMessage replyMessage; + if (!retTypeName.empty()) + { + ZeroCopyBuffer bufferRet; + SerializerProto serializerProto(bufferRet); + ParserQt parserQt(serializerProto, retQtBuffer.data(), retQtBuffer.size(), ParserQt::Mode::WRAPPED_BY_QVARIANT); + parserQt.parseStruct(retTypeName); + + replyMessage.type = retTypeName; + bufferRet.copyData(replyMessage.data); + } + requestContext->reply(replyMessage); + } + else if (metaProperty.isValid()) { - ZeroCopyBuffer bufferRet; - SerializerProto serializerProto(bufferRet); - ParserQt parserQt(serializerProto, retQtBuffer.data(), retQtBuffer.size(), ParserQt::Mode::WRAPPED_BY_QVARIANT); - parserQt.parseStruct(retTypeName); + found = true; + if (propertySet) + { + ZeroCopyBuffer buffer; + SerializerQt serializerQt(buffer, SerializerQt::Mode::WRAPPED_BY_QVARIANT); + ParserProto parserProto(serializerQt, request->data.data(), request->data.size()); + parserProto.parseStruct(request->type); + + QByteArray bufferByteArray; + bufferByteArray.reserve(static_cast(buffer.size())); + const std::list& chunks = buffer.chunks(); + for (const auto& chunk : chunks) + { + bufferByteArray.append(chunk.data(), static_cast(chunk.size())); + } - replyMessage.type = retTypeName; - bufferRet.copyData(replyMessage.data); + QVariant value; + QDataStream streamInParam(bufferByteArray); + streamInParam >> value; + + const bool result = metaProperty.write(obj, value); + if (result) + { + GeneralMessage replyMessage; + requestContext->reply(replyMessage); + } + else + { + requestContext->reply(finalmq::Status::STATUS_REQUEST_PROCESSING_ERROR); + } + } + else + { + QVariant value = metaProperty.read(obj); + + QByteArray retQtBuffer; + QDataStream streamRetParam(&retQtBuffer, QIODevice::WriteOnly); + streamRetParam << value; + + std::string retTypeName = getReturnTypeName(metaProperty.typeName()); + + GeneralMessage replyMessage; + + ZeroCopyBuffer bufferRet; + SerializerProto serializerProto(bufferRet); + ParserQt parserQt(serializerProto, retQtBuffer.data(), retQtBuffer.size(), ParserQt::Mode::WRAPPED_BY_QVARIANT); + parserQt.parseStruct(retTypeName); + + replyMessage.type = retTypeName; + bufferRet.copyData(replyMessage.data); + + requestContext->reply(replyMessage); + } } - requestContext->reply(replyMessage); } } if (!found) @@ -491,12 +553,14 @@ class QtInvoker : public RemoteEntity { QObject* obj; QMetaMethod metaMethod; - return getTypeName(objId, methodName, obj, metaMethod); + QMetaProperty metaProperty; + bool propertySet = false; + return getTypeName(objId, methodName, obj, metaMethod, metaProperty, propertySet); } std::string getReturnTypeName(const std::string& type) { - std::string typeName = "ret_" + type; + std::string typeName = type + "_v"; const MetaStruct* struFound = MetaDataGlobal::instance().getStruct(typeName); if (struFound == nullptr) { @@ -504,7 +568,7 @@ class QtInvoker : public RemoteEntity const auto it = m_typesToField.find(type); if (it != m_typesToField.end()) { - static const std::string& name = "ret"; + static const std::string& name = "v"; const MetaField& field = it->second; stru.addField(MetaField(field.typeId, field.typeName, name, field.description, field.flags, field.attrs)); MetaDataGlobal::instance().addStruct(stru); @@ -517,14 +581,14 @@ class QtInvoker : public RemoteEntity return typeName; } - std::string getTypeName(const std::string& objId, const std::string& methodName, QObject*& obj, QMetaMethod& metaMethod) + std::string getTypeName(const std::string& objId, const std::string& methodName, QObject*& obj, QMetaMethod& metaMethod, QMetaProperty& metaProperty, bool& propertySet) { + propertySet = false; std::string typeOfGeneralMessage{}; obj = findObject(QString::fromUtf8(objId.c_str())); if (obj) { const QMetaObject* metaObject = obj->metaObject(); - QMetaProperty metaProperty; if (metaObject) { int ix = metaObject->indexOfMethod(methodName.c_str()); @@ -544,7 +608,15 @@ class QtInvoker : public RemoteEntity if (!metaMethod.isValid()) { - ix = metaObject->indexOfProperty(methodName.c_str()); + if (methodName.substr(0, 4) == "set_") + { + propertySet = true; + ix = metaObject->indexOfProperty(methodName.substr(4).c_str()); + } + else + { + ix = metaObject->indexOfProperty(methodName.c_str()); + } if (ix != -1) { metaProperty = metaObject->property(ix); @@ -627,6 +699,44 @@ class QtInvoker : public RemoteEntity } } } + else if (metaProperty.isValid()) + { + std::string typeName = metaProperty.typeName(); + typeName += "_v"; + + // no parameters? + if (!propertySet) + { + typeName = '_'; + } + + bool ok = true; + const MetaStruct* struFound = MetaDataGlobal::instance().getStruct(typeName); + if (struFound == nullptr) + { + MetaStruct stru{ typeName, "", {}, 0, {} }; + const std::string& type = metaProperty.typeName(); + const auto it = m_typesToField.find(type); + if (it != m_typesToField.end()) + { + static const std::string name = "v"; + const MetaField& field = it->second; + stru.addField(MetaField(field.typeId, field.typeName, name, field.description, field.flags, field.attrs)); + } + else + { + ok = false; + } + if (ok) + { + MetaDataGlobal::instance().addStruct(stru); + } + } + if (ok) + { + typeOfGeneralMessage = typeName; + } + } } } return typeOfGeneralMessage; diff --git a/inc/finalmq/Qt/qtdata.fmq b/inc/finalmq/Qt/qtdata.fmq index 0b04e5b5..518e9d08 100644 --- a/inc/finalmq/Qt/qtdata.fmq +++ b/inc/finalmq/Qt/qtdata.fmq @@ -122,10 +122,10 @@ {"tid":"int32", "type":"","name":"height","desc":"","flags":[]} ]}, {"type":"FmqQRect","attrs":["qttype:QRect"],"desc":"","fields":[ - {"tid":"int32", "type":"","name":"x","desc":"","flags":[]}, - {"tid":"int32", "type":"","name":"y","desc":"","flags":[]}, - {"tid":"int32", "type":"","name":"width","desc":"","flags":[]}, - {"tid":"int32", "type":"","name":"height","desc":"","flags":[]} + {"tid":"int32", "type":"","name":"left","desc":"","flags":[]}, + {"tid":"int32", "type":"","name":"top","desc":"","flags":[]}, + {"tid":"int32", "type":"","name":"right","desc":"","flags":[]}, + {"tid":"int32", "type":"","name":"bottom","desc":"","flags":[]} ]}, {"type":"FmqQColor","attrs":["qttype:QColor"],"desc":"","fields":[ {"tid":"enum", "type":"FmqQColorSpec","name":"cspec","desc":"","flags":[]},