Remove modules not compiled by this branch's release build
Lts/Common: drop the 17 submodules excluded from the RELEASE_BUILD branch of Lts/Common/CMakeLists.txt (CodeGen, LtsAppManager, LtsBotan, LtsCoordinate, LtsElevation, LtsLogin, LtsMultiMonitor, LtsPluginManager, LtsPrinting, LtsProjectionWorkstation, LtsScriptTimeline, LtsSession, LtsTimeline, LtsTimelineClassic, LtsVirtualKeyboard, LtsWidgets, TopicEditorBase). Only the 13 subdirectories actually built remain. TrainingAreaBase: drop sources of targets excluded by IF(NOT RELEASE_BUILD) / IF(BUILD_RTI) (svcTabClient, svcTabServer, svcTrainingAreaBase exe, RecordReplayPlugin customization) and the 7 plugin directories not added in the release path (AdlerJson, ApacheHlaJson, DebugJsonDir, HlaJson, Nmea, UAS, WlsTetra). Only tabTelegrams, svcTabCommon and the TetraJson plugin are compiled. Cross-checked: no kept compiled source includes headers from the removed modules (GuiPluginInterface - the only LtsWidgets consumer - is itself NOT RELEASE_BUILD-guarded).
This commit is contained in:
1 parent
eb4d067365
commit
855b0a6101
765 files changed
-128732
No files matched your search
@@ -1,173 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# Make ${Qt6_Widgets} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Widgets)
|
||||
set(Qt6_Widgets ${Qt6_Widgets})
|
||||
else()
|
||||
set(Qt6_Widgets "")
|
||||
endif()
|
||||
|
||||
|
||||
FIND_PACKAGE(RTI)
|
||||
|
||||
# KTextTemplate is Qt6-compatible replacement for Grantlee5
|
||||
IF(BUILD_GRANTLEE)
|
||||
FIND_PACKAGE(KF6TextTemplate REQUIRED)
|
||||
ENDIF()
|
||||
|
||||
NGL_ADD_LIBRARY2(ALL codegen_base SHARED
|
||||
codegen_export.h
|
||||
SqlGenerator.cpp
|
||||
SqlGenerator.h
|
||||
StructBuilder.cpp
|
||||
StructBuilder.h
|
||||
XmlReader.cpp
|
||||
XmlReader.h
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_base
|
||||
PRIVATE
|
||||
Qt6::Xml
|
||||
NGLLogger
|
||||
ngltools
|
||||
PUBLIC
|
||||
Qt6::Core
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(codegen_base
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
# If RTI target is available, propagate its include dirs/compile defs
|
||||
if (TARGET RTI::nddscpp2)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(codegen_base
|
||||
PUBLIC
|
||||
$<TARGET_PROPERTY:RTI::nddscpp2,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(codegen_base
|
||||
PUBLIC
|
||||
$<TARGET_PROPERTY:RTI::nddscpp2,INTERFACE_COMPILE_DEFINITIONS>
|
||||
RTI_DDS_AVAILABLE
|
||||
)
|
||||
message(STATUS "RTI found; building codegen_base with RTI support")
|
||||
else()
|
||||
message(STATUS "RTI not found; building codegen_base without RTI support")
|
||||
endif()
|
||||
NGL_INSTALL_TARGET(codegen_base)
|
||||
|
||||
# KTextTemplate is Qt6-compatible replacement for Grantlee5
|
||||
IF(BUILD_GRANTLEE AND TARGET KF6::TextTemplate)
|
||||
NGL_ADD_LIBRARY(ALL codegen_grantlee STATIC
|
||||
CppTopicGeneratorGrantlee.cpp
|
||||
CppTopicGeneratorGrantlee.h
|
||||
DaoGeneratorGrantlee.cpp
|
||||
DaoGeneratorGrantlee.h
|
||||
DatabaseGeneratorGrantlee.cpp
|
||||
DatabaseGeneratorGrantlee.h
|
||||
GeneratorGrantleeBase.cpp
|
||||
GeneratorGrantleeBase.h
|
||||
GrantleeWrappers.cpp
|
||||
GrantleeWrappers.h
|
||||
|
||||
svc.idl.grantlee
|
||||
svc_enums.idl.grantlee
|
||||
|
||||
svc_translation.cpp.grantlee
|
||||
svc_translation.h.grantlee
|
||||
|
||||
svc_dao.cpp.grantlee
|
||||
svc_dao.h.grantlee
|
||||
|
||||
svc_db.h.grantlee
|
||||
svc_db_impl.h.grantlee
|
||||
svc_db_impl.cpp.grantlee
|
||||
|
||||
svc_dtc.h.grantlee
|
||||
svc_dtc_impl.cpp.grantlee
|
||||
svc_dtc_impl.h.grantlee
|
||||
|
||||
svc_dts.h.grantlee
|
||||
svc_dts_impl.cpp.grantlee
|
||||
svc_dts_impl.h.grantlee
|
||||
|
||||
svc_ftc.h.grantlee
|
||||
svc_ftc_impl.cpp.grantlee
|
||||
svc_ftc_impl.h.grantlee
|
||||
|
||||
svc_fts.h.grantlee
|
||||
svc_fts_impl.cpp.grantlee
|
||||
svc_fts_impl.h.grantlee
|
||||
|
||||
svc_json.cpp.grantlee
|
||||
svc_json.h.grantlee
|
||||
|
||||
svc_topic_type_plugin.cpp.grantlee
|
||||
svc_topic_type_plugin.h.grantlee
|
||||
|
||||
svc_record_replay_plugin.cpp.grantlee
|
||||
svc_record_replay_plugin.h.grantlee
|
||||
|
||||
codegen_simple.py
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_grantlee
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
ProjectConfig
|
||||
PUBLIC
|
||||
codegen_base
|
||||
KF6::TextTemplate
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(codegen_grantlee
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_BINARY_DIR}/Z/src/NGLLogger
|
||||
)
|
||||
|
||||
# Smoke-test: parse all .grantlee templates in this directory to detect parse/render regressions
|
||||
find_package(Qt6 COMPONENTS Core QUIET)
|
||||
if (Qt6_FOUND)
|
||||
set(QTCORE_TARGET Qt6::Core)
|
||||
else()
|
||||
find_package(Qt6 COMPONENTS Core REQUIRED)
|
||||
set(QTCORE_TARGET Qt6::Core)
|
||||
endif()
|
||||
|
||||
add_executable(grantlee_parser_smoke tests/GrantleeParserSmoke.cpp)
|
||||
target_link_libraries(grantlee_parser_smoke PRIVATE KF6::TextTemplate ${QTCORE_TARGET})
|
||||
add_test(NAME GrantleeParserSmoke COMMAND grantlee_parser_smoke ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
NGL_ADD_EXECUTABLE(ALL ngl_codegen
|
||||
main_grantlee.cpp
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(ngl_codegen
|
||||
codegen_grantlee
|
||||
LtsCommandLineParser
|
||||
nglcoreapplication
|
||||
Qt6::Core
|
||||
KF6::TextTemplate
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(codegen_gui_uics
|
||||
main_grantlee_gui.ui
|
||||
)
|
||||
NGL_ADD_EXECUTABLE(WS AAR SV NO_TRANSLATION codegen_gui
|
||||
${codegen_gui_uics}
|
||||
main_grantlee_gui.cpp
|
||||
main_grantlee_gui.ui
|
||||
)
|
||||
if(QT6_GUI_AVAILABLE)
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_gui
|
||||
codegen_grantlee
|
||||
LtsCommandLineParser
|
||||
nglapplication
|
||||
${Qt6_Widgets}
|
||||
KF6::TextTemplate
|
||||
)
|
||||
endif()
|
||||
ELSE()
|
||||
message(STATUS "BUILD_GRANTLEE disabled or Grantlee not found; skipping codegen_grantlee, ngl_codegen, and codegen_gui targets")
|
||||
ENDIF()
|
||||
@@ -1,330 +0,0 @@
|
||||
|
||||
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
|
||||
#include "StructBuilder.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <ktexttemplate/context.h>
|
||||
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
#include <dds/core/xtypes/EnumType.hpp>
|
||||
#endif
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
CppTopicGeneratorGrantlee::CppTopicGeneratorGrantlee() : GeneratorGrantleeBase("CodeGen.CppTopicGeneratorGrantlee") {}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::init(const XmlReader* reader, StructBuilder* structBuilder)
|
||||
{
|
||||
m_reader = reader;
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
addCustomFunctions(reader->getCustomFunctions());
|
||||
|
||||
return initDataTopics() && initFunctionTopics() && initIdlStructs();
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::initDataTopics()
|
||||
{
|
||||
DataTopicsWrapper* dataTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
||||
const auto dataTopics = m_reader->getIdlStructInformation();
|
||||
QVector<IdlData> keyColumns;
|
||||
QVector<IdlData> trColumns;
|
||||
for (const CodeGen::TopicTypeInformation& tti : dataTopics)
|
||||
{
|
||||
if (!tti.isDataObject)
|
||||
continue;
|
||||
|
||||
keyColumns.clear();
|
||||
trColumns.clear();
|
||||
const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(tti.name);
|
||||
if (!ctti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << tti.name;
|
||||
continue;
|
||||
}
|
||||
DataTopicWrapper* dtw = dataTopicsWrapper->addDataTopic(ctti);
|
||||
getSpecialColumns(ctti, keyColumns, trColumns);
|
||||
if (keyColumns.size() == 1)
|
||||
dtw->setKeyColumnData(keyColumns.first());
|
||||
dtw->setTrColumns(trColumns);
|
||||
if (ctti.recordTopic)
|
||||
{
|
||||
const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name));
|
||||
if (!cti.isEmpty())
|
||||
dtw->setRecordTableInformation(cti);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctti.isDataObject)
|
||||
m_structBuilder->buildJSonStructureInformationFromIdlData(ctti);
|
||||
}
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("dataTopics"), dataTopicsWrapper);
|
||||
|
||||
QSet<QString> exportedSubTopics;
|
||||
DataTopicsWrapper* subTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
||||
const QVector<QSharedPointer<DataTypeInfo>> serializeTopics = m_structBuilder->getSerializeFromToJsonTopics();
|
||||
for (const QSharedPointer<DataTypeInfo>& dti : serializeTopics)
|
||||
{
|
||||
if (exportedSubTopics.contains(dti->idlType()))
|
||||
continue;
|
||||
if (dti->isStructure())
|
||||
{
|
||||
const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(dti->idlType());
|
||||
if (!ctti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType();
|
||||
continue;
|
||||
}
|
||||
const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name));
|
||||
if (cti.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType();
|
||||
continue;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Adding substruct topic " << ctti.name;
|
||||
DataTopicWrapper* dtw = subTopicsWrapper->addDataTopic(ctti);
|
||||
dtw->setRecordTableInformation(cti);
|
||||
exportedSubTopics += dti->idlType();
|
||||
}
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("serializeTopics"), subTopicsWrapper);
|
||||
|
||||
QVector<MemberInformationListWrapper*> jsonTopics;
|
||||
const QMap<QString, QVector<MemberInformation>> jsonExport = m_structBuilder->jsonStructureInformation();
|
||||
for (auto it = jsonExport.begin(); it != jsonExport.end(); ++it)
|
||||
{
|
||||
MemberInformationListWrapper* mil = new MemberInformationListWrapper(it.key(), it.value(), this);
|
||||
jsonTopics += mil;
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("jsonTopics"), QVariant::fromValue(jsonTopics));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::getSpecialColumns(const CompleteTopicTypeInformation& tti, QVector<IdlData>& keyColumns,
|
||||
QVector<IdlData>& trColumns) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Get special columns for " << tti.name << " - base is " << tti.baseValueType;
|
||||
if (!tti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "tti is not valid ...";
|
||||
return false;
|
||||
}
|
||||
for (const IdlData& ci : tti.members)
|
||||
{
|
||||
if (ci.isKey)
|
||||
keyColumns += ci;
|
||||
if (ci.isTranslatable)
|
||||
trColumns += ci;
|
||||
}
|
||||
if (tti.baseValueType.isEmpty())
|
||||
return true;
|
||||
return getSpecialColumns(topicTypeInformationByDerivedTopic(tti), keyColumns, trColumns);
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::initFunctionTopics()
|
||||
{
|
||||
|
||||
const QVector<FunctionTopic> functionTopics = m_reader->getFunctionTopics();
|
||||
FunctionTopicsWrapper* functionTopicsWrapper(new FunctionTopicsWrapper(QStringLiteral("functionTopics"), this));
|
||||
for (const FunctionTopic& ft : functionTopics)
|
||||
{
|
||||
if (!handleStruct(ft, functionTopicsWrapper))
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ctx->insert(QStringLiteral("functionTopics"), functionTopicsWrapper);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::handleStruct(const FunctionTopic& ft, FunctionTopicsWrapper* functionTopicsWrapper)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "handling FunctionTopic: " << ft.name;
|
||||
|
||||
const CompleteTopicTypeInformation siRequest =
|
||||
m_structBuilder->topicTypeInformationByStructType(ft.requestTopicType);
|
||||
if (!siRequest.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about request topic " << ft.requestTopicName;
|
||||
return false;
|
||||
}
|
||||
|
||||
const CompleteTopicTypeInformation siReply = m_structBuilder->topicTypeInformationByStructType(ft.replyTopicType);
|
||||
if (!siReply.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about reply topic " << ft.replyTopicType;
|
||||
return false;
|
||||
}
|
||||
|
||||
FunctionTopicWrapper* ftw = functionTopicsWrapper->addFunctionTopic(ft, siRequest, siReply);
|
||||
const QByteArray hash =
|
||||
QCryptographicHash::hash(ft.requestTopicName.toUtf8(), QCryptographicHash::Sha3_512).toHex().left(16);
|
||||
ftw->setReplyHandlerHash(QStringLiteral("0x") + QString::fromLatin1(hash) + QStringLiteral("LL"));
|
||||
if (!addRequesterRequestParams(ft.name, siRequest, ftw) || !addRequesterReplyParams(ft.name, siReply, ftw))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::addRequesterRequestParams(const QString& request_name,
|
||||
const CompleteTopicTypeInformation& request,
|
||||
FunctionTopicWrapper* ftw)
|
||||
{
|
||||
if (request.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation siBase =
|
||||
m_structBuilder->topicTypeInformationByStructType(request.baseValueType);
|
||||
if (!siBase.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about base request topic "
|
||||
<< request.baseValueType;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addRequesterRequestParams(request_name, siBase, ftw))
|
||||
return false;
|
||||
}
|
||||
ftw->addRequestParams(request.members);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::addRequesterReplyParams(const QString& request_name,
|
||||
const CompleteTopicTypeInformation& reply,
|
||||
FunctionTopicWrapper* ftw)
|
||||
{
|
||||
if (reply.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation siBase =
|
||||
m_structBuilder->topicTypeInformationByStructType(reply.baseValueType);
|
||||
if (!siBase.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about base reply topic " << reply.baseValueType;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addRequesterReplyParams(request_name, siBase, ftw))
|
||||
return false;
|
||||
}
|
||||
ftw->addReplyParams(reply.members);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::handleIdlStruct(const CompleteTopicTypeInformation& csi, QSet<QString>& idlStructNames,
|
||||
QVector<IdlStructWrapper*>& idlStructs)
|
||||
{
|
||||
if (!csi.isValid())
|
||||
return true;
|
||||
|
||||
if (idlStructNames.contains(csi.name))
|
||||
return true;
|
||||
|
||||
if (csi.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation ctti =
|
||||
m_structBuilder->topicTypeInformationByStructType(csi.baseValueType, false);
|
||||
if (ctti.isValid())
|
||||
{
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
if (ctti.extensibility == dds::core::xtypes::ExtensibilityKind_def::FINAL)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Base struct (" << ctti.name
|
||||
<< ") has final extensibility - this is not allowed";
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// RTI not available - skip extensibility check (assume EXTENSIBLE)
|
||||
Q_UNUSED(ctti.extensibility);
|
||||
#endif
|
||||
if (!idlStructNames.contains(csi.baseValueType))
|
||||
{
|
||||
if (!handleIdlStruct(ctti, idlStructNames, idlStructs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int idx = csi.baseValueType.indexOf(QLatin1String("::"));
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "idlStruct '" << csi.baseValueType << "' not found in idl-file";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const IdlData& idlData : csi.members)
|
||||
{
|
||||
QString idlType;
|
||||
DEBUG_LOG(m_logger) << "member: " << idlData.type << " - " << idlData.name << " "
|
||||
<< idlData.dataTypeInfo->isStructure() << " " << idlData.dataTypeInfo->isSequence();
|
||||
if (idlData.dataTypeInfo->isStructure())
|
||||
idlType = idlData.dataTypeInfo->idlType();
|
||||
else if (idlData.dataTypeInfo->isSequence())
|
||||
{
|
||||
if (idlData.dataTypeInfo->innerDataType()->isStructure())
|
||||
idlType = idlData.dataTypeInfo->innerDataType()->idlType();
|
||||
}
|
||||
if (idlType.isEmpty())
|
||||
continue;
|
||||
if (!handleIdlStruct(m_structBuilder->topicTypeInformationByStructType(idlType, false), idlStructNames,
|
||||
idlStructs))
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Current structName: " << csi.name;
|
||||
idlStructs += new IdlStructWrapper(csi, this);
|
||||
|
||||
idlStructNames.insert(csi.name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::initIdlStructs()
|
||||
{
|
||||
|
||||
const QVector<CompleteTopicTypeInformation> csiData = m_structBuilder->topicTypeInformations();
|
||||
|
||||
QSet<QString> idlStructNames;
|
||||
QVector<IdlStructWrapper*> idlStructs;
|
||||
idlStructs.reserve(csiData.size());
|
||||
for (const CompleteTopicTypeInformation& csi : csiData)
|
||||
{
|
||||
if (!handleIdlStruct(csi, idlStructNames, idlStructs))
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ctx->insert(QStringLiteral("idl_structs"), QVariant::fromValue(idlStructs));
|
||||
|
||||
const QVector<EnumInformation> enumerations = m_structBuilder->enumInformations();
|
||||
QVector<IdlEnumWrapper*> idlEnumerations;
|
||||
idlEnumerations.reserve(enumerations.size());
|
||||
for (const EnumInformation& ei : enumerations)
|
||||
idlEnumerations += new IdlEnumWrapper(ei, this);
|
||||
m_ctx->insert(QStringLiteral("idl_enums"), QVariant::fromValue(idlEnumerations));
|
||||
|
||||
exportUsedServices(m_reader);
|
||||
return true;
|
||||
}
|
||||
|
||||
CompleteTopicTypeInformation
|
||||
CppTopicGeneratorGrantlee::topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation& tti) const
|
||||
{
|
||||
if (tti.baseValueType.isEmpty())
|
||||
return CompleteTopicTypeInformation();
|
||||
QString baseValueType = tti.baseValueType;
|
||||
|
||||
if (tti.name.contains(QLatin1String("::")) && !tti.baseValueType.contains(QLatin1String("::")))
|
||||
{
|
||||
const QStringList sl = tti.name.split(QStringLiteral("::"));
|
||||
baseValueType = sl.at(0) + QLatin1String("::") + tti.baseValueType;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "topicTypeInformationByStructName(" << baseValueType << ")";
|
||||
return m_structBuilder->topicTypeInformationByStructType(baseValueType);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "StructBuilder.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
|
||||
class CppTopicGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CppTopicGeneratorGrantlee();
|
||||
|
||||
bool init(const XmlReader* reader, StructBuilder* structBuilder) override;
|
||||
|
||||
private:
|
||||
bool initDataTopics();
|
||||
bool getSpecialColumns(const CompleteTopicTypeInformation& tti, QVector<IdlData>& keyColumns,
|
||||
QVector<IdlData>& trColumns) const;
|
||||
|
||||
bool initFunctionTopics();
|
||||
bool handleStruct(const FunctionTopic& ft, FunctionTopicsWrapper* functionTopicsWrapper);
|
||||
bool addRequesterRequestParams(const QString& request_name, const CompleteTopicTypeInformation& request,
|
||||
FunctionTopicWrapper* ftw);
|
||||
bool addRequesterReplyParams(const QString& request_name, const CompleteTopicTypeInformation& reply,
|
||||
FunctionTopicWrapper* ftw);
|
||||
|
||||
bool handleIdlStruct(const CompleteTopicTypeInformation& csi, QSet<QString>& idlStructNames,
|
||||
QVector<IdlStructWrapper*>& idlStructs);
|
||||
bool initIdlStructs();
|
||||
|
||||
CompleteTopicTypeInformation topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation& tti) const;
|
||||
|
||||
const XmlReader* m_reader = nullptr;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id: DaoGeneratorGrantlee.cpp 50446 2020-03-18 10:29:57Z ehrlicher $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/DaoGeneratorGrantlee.cpp $
|
||||
* $Author: ehrlicher $
|
||||
*/
|
||||
|
||||
#include "DaoGeneratorGrantlee.h"
|
||||
#include "StructBuilder.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <grantlee/context.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
DaoGeneratorGrantlee::DaoGeneratorGrantlee()
|
||||
: GeneratorGrantleeBase("CodeGen.DaoGeneratorGrantlee")
|
||||
{}
|
||||
|
||||
bool DaoGeneratorGrantlee::init(const XmlReader *reader,
|
||||
StructBuilder *structBuilder)
|
||||
{
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
// Is Service exercise-independent?
|
||||
if (reader->isServiceExerciseIndependent())
|
||||
m_ctx->insert(QStringLiteral("isExerciseIndependent"), QLatin1String("1"));
|
||||
|
||||
bool bHasDbNotifications = false;
|
||||
QVector<DbStructWrapper *> vlServiceStructs;
|
||||
QVector<DbStructWrapper *> vlStaticDataStructs;
|
||||
const QVector<CompleteStructInformation> csiData = structBuilder->structInformations();
|
||||
vlServiceStructs.reserve(csiData.size());
|
||||
vlStaticDataStructs.reserve(csiData.size());
|
||||
for (const CompleteStructInformation &csi : csiData)
|
||||
{
|
||||
DbStructWrapper *dbStructWrapper(new DbStructWrapper(csi, this));
|
||||
|
||||
if (csi.hasStaticContent)
|
||||
vlStaticDataStructs += dbStructWrapper;
|
||||
else
|
||||
vlServiceStructs += dbStructWrapper;
|
||||
if (!csi.dbNotifications.isEmpty())
|
||||
bHasDbNotifications = true;
|
||||
}
|
||||
|
||||
if (structBuilder->needPoint3d())
|
||||
m_ctx->insert(QStringLiteral("need_point3d"), QLatin1String("1"));
|
||||
if (structBuilder->needPgArrayInclude())
|
||||
m_ctx->insert(QStringLiteral("need_pgarray"), QLatin1String("1"));
|
||||
m_ctx->insert(QStringLiteral("cpp_structs"), QVariant::fromValue(vlServiceStructs));
|
||||
m_ctx->insert(QStringLiteral("data_structs"), QVariant::fromValue(vlStaticDataStructs));
|
||||
if (bHasDbNotifications)
|
||||
m_ctx->insert(QStringLiteral("has_db_notifications"), QLatin1String("1"));
|
||||
|
||||
m_ctx->insert(QStringLiteral("library_target"), QStringLiteral("COMMON"));
|
||||
|
||||
exportUsedServices(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id: DaoGeneratorGrantlee.h 50446 2020-03-18 10:29:57Z ehrlicher $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/DaoGeneratorGrantlee.h $
|
||||
* $Author: ehrlicher $
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct CompleteStructInformation;
|
||||
class StructBuilder;
|
||||
class XmlReader;
|
||||
|
||||
|
||||
class DaoGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DaoGeneratorGrantlee();
|
||||
|
||||
bool init(const XmlReader *reader, StructBuilder *structBuilder) override;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -1,59 +0,0 @@
|
||||
|
||||
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
|
||||
#include "StructBuilder.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <ktexttemplate/context.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
DatabaseGeneratorGrantlee::DatabaseGeneratorGrantlee(bool targetIsServer)
|
||||
: GeneratorGrantleeBase("CodeGen.CppStructGeneratorGrantlee"), m_targetIsServer(targetIsServer)
|
||||
{
|
||||
}
|
||||
|
||||
bool DatabaseGeneratorGrantlee::init(const XmlReader* reader, StructBuilder* structBuilder)
|
||||
{
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
if (reader->isServiceExerciseIndependent())
|
||||
m_ctx->insert(QStringLiteral("isExerciseIndependent"), QLatin1String("1"));
|
||||
|
||||
bool bHasDbNotifications = false;
|
||||
QVector<DbStructWrapper*> vlServiceStructs;
|
||||
QVector<DbStructWrapper*> vlStaticDataStructs;
|
||||
const QVector<CompleteStructInformation> csiData = structBuilder->structInformations();
|
||||
vlServiceStructs.reserve(csiData.size());
|
||||
vlStaticDataStructs.reserve(csiData.size());
|
||||
for (const CompleteStructInformation& csi : csiData)
|
||||
{
|
||||
DbStructWrapper* dbStructWrapper(new DbStructWrapper(csi, this));
|
||||
|
||||
if (csi.hasStaticContent)
|
||||
vlStaticDataStructs += dbStructWrapper;
|
||||
else
|
||||
vlServiceStructs += dbStructWrapper;
|
||||
if (!csi.dbNotifications.isEmpty())
|
||||
bHasDbNotifications = true;
|
||||
}
|
||||
addCustomFunctions(reader->getCustomFunctions());
|
||||
|
||||
if (structBuilder->needPoint3d())
|
||||
m_ctx->insert(QStringLiteral("need_point3d"), QLatin1String("1"));
|
||||
if (structBuilder->needPgArrayInclude())
|
||||
m_ctx->insert(QStringLiteral("need_pgarray"), QLatin1String("1"));
|
||||
m_ctx->insert(QStringLiteral("cpp_structs"), QVariant::fromValue(vlServiceStructs));
|
||||
m_ctx->insert(QStringLiteral("data_structs"), QVariant::fromValue(vlStaticDataStructs));
|
||||
if (bHasDbNotifications)
|
||||
m_ctx->insert(QStringLiteral("has_db_notifications"), QLatin1String("1"));
|
||||
|
||||
m_ctx->insert(QStringLiteral("library_target"),
|
||||
m_targetIsServer ? QStringLiteral("SERVER") : QStringLiteral("COMMON"));
|
||||
|
||||
exportUsedServices(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "StructBuilder.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct CompleteStructInformation;
|
||||
class StructBuilder;
|
||||
class XmlReader;
|
||||
|
||||
class DatabaseGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DatabaseGeneratorGrantlee(bool targetIsServer);
|
||||
|
||||
bool init(const XmlReader* reader, StructBuilder* structBuilder) override;
|
||||
|
||||
private:
|
||||
bool m_targetIsServer;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -1,200 +0,0 @@
|
||||
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
GeneratorGrantleeBase::GeneratorGrantleeBase(const char* loggerName)
|
||||
: m_engine(new KTextTemplate::Engine)
|
||||
, m_ctx(new KTextTemplate::Context)
|
||||
, m_structBuilder(nullptr)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{
|
||||
// Add KTextTemplate plugin path for loading default tags/filters
|
||||
// KTextTemplate plugins are in /usr/lib/x86_64-linux-gnu/qt6/plugins/kf6/ktexttemplate
|
||||
// QT_PLUGIN_PATH should point to the parent directory containing the category folders
|
||||
m_engine->addPluginPath(QStringLiteral("/usr/lib/x86_64-linux-gnu/qt6/plugins"));
|
||||
}
|
||||
|
||||
GeneratorGrantleeBase::~GeneratorGrantleeBase()
|
||||
{
|
||||
delete m_engine;
|
||||
delete m_ctx;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::initInternal(const XmlReader* reader, StructBuilder* structBuilder)
|
||||
{
|
||||
m_structBuilder = structBuilder;
|
||||
|
||||
if (reader)
|
||||
{
|
||||
m_ctx->insert(QStringLiteral("namespace"), reader->getServiceNamespace());
|
||||
m_ctx->insert(QStringLiteral("namespace_abbr"), reader->getServiceAbbr().toLower());
|
||||
m_ctx->insert(QStringLiteral("namespace_abbr_upper"), reader->getServiceAbbr().toUpper());
|
||||
if (reader->getServiceNamespace() == QLatin1String("Core"))
|
||||
m_ctx->insert(QStringLiteral("include_prefix"),
|
||||
QStringLiteral("DDS/%1").arg(reader->getServiceNamespace()));
|
||||
else
|
||||
m_ctx->insert(QStringLiteral("include_prefix"), reader->getServiceNamespace());
|
||||
m_ctx->insert(QStringLiteral("custom_record_replay"), reader->hasCustomRecordReplayPlugin());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::setTemplate(const QString& templateName, const QString& tmpl)
|
||||
{
|
||||
m_template = m_engine->newTemplate(tmpl, QStringLiteral("myTemplate"));
|
||||
if (m_template->error())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error parsing template '" << templateName << "': " << m_template->errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GeneratorGrantleeBase::render() const
|
||||
{
|
||||
QString out = m_template->render(m_ctx);
|
||||
const QRegularExpression rx(QLatin1String(";\\n([ ]+\\n)*"));
|
||||
out = out.replace(rx, QStringLiteral(";\n"));
|
||||
return out;
|
||||
}
|
||||
|
||||
QString GeneratorGrantleeBase::errorString() const
|
||||
{
|
||||
return m_template->errorString();
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::generateData(const QString& templateName, const QString& outDirectory)
|
||||
{
|
||||
QString content;
|
||||
if (!readFile(templateName, content))
|
||||
return false;
|
||||
if (!setTemplate(templateName, content))
|
||||
return false;
|
||||
|
||||
content = render();
|
||||
|
||||
QString outFilename;
|
||||
if (!getFilenameFromData(content, outFilename))
|
||||
return false;
|
||||
|
||||
QFile f(outDirectory + QLatin1Char('/') + outFilename);
|
||||
if (!f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << f.fileName() << "' for writing: " << f.errorString() << "("
|
||||
<< f.error() << ")";
|
||||
return false;
|
||||
}
|
||||
const QByteArray outData = content.toUtf8();
|
||||
f.write(outData);
|
||||
f.close();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Written data to " << f.fileName();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::readFile(const QString& filename, QString& data) const
|
||||
{
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file " << filename << " - error: " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
data = QString::fromUtf8(f.readAll());
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::getFilenameFromData(const QString& dataToParse, QString& filename) const
|
||||
{
|
||||
|
||||
const QString filenameMarker(QStringLiteral("// filename:"));
|
||||
int idx = dataToParse.indexOf(filenameMarker);
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find marker '" << filenameMarker << "' in data!";
|
||||
return false;
|
||||
}
|
||||
idx += filenameMarker.length() + 1;
|
||||
int endIdx = dataToParse.indexOf(QLatin1Char('\n'), idx);
|
||||
if (endIdx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find end marker '\\n' in data!";
|
||||
return false;
|
||||
}
|
||||
filename = dataToParse.mid(idx, endIdx - idx).trimmed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeneratorGrantleeBase::addCustomFunctions(const QVector<CustomServiceFunctionInformation>& customFunctions)
|
||||
{
|
||||
|
||||
QVariantList vlCustomDbFunctions;
|
||||
QVariantList vlCustomDtcFunctions;
|
||||
vlCustomDbFunctions.reserve(customFunctions.size());
|
||||
vlCustomDtcFunctions.reserve(customFunctions.size());
|
||||
for (const CustomServiceFunctionInformation& csfi : customFunctions)
|
||||
{
|
||||
const QString signature(csfi.returnValue + QLatin1Char(' ') + csfi.methodName + QLatin1Char('(') +
|
||||
csfi.signature + QLatin1Char(')') +
|
||||
(csfi.isConst ? QStringLiteral(" const") : QString()));
|
||||
CustomFunctionWrapper* customFunctionWrapper(new CustomFunctionWrapper(signature, this));
|
||||
switch (csfi.type)
|
||||
{
|
||||
case CustomServiceFunctionInformation::Type::Db:
|
||||
vlCustomDbFunctions += QVariant::fromValue(customFunctionWrapper);
|
||||
break;
|
||||
case CustomServiceFunctionInformation::Type::Dtc:
|
||||
vlCustomDtcFunctions += QVariant::fromValue(customFunctionWrapper);
|
||||
break;
|
||||
case CustomServiceFunctionInformation::Type::DbNotify:
|
||||
|
||||
WARNING_LOG(m_logger) << "Internal error - Trying to handle DbNotify in addCustomFunctions(): "
|
||||
<< csfi.methodName;
|
||||
delete customFunctionWrapper;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Added custom db function " << csfi.methodName;
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("custom_dtc_procs"), vlCustomDtcFunctions);
|
||||
m_ctx->insert(QStringLiteral("custom_db_procs"), vlCustomDbFunctions);
|
||||
}
|
||||
|
||||
void GeneratorGrantleeBase::exportUsedServices(const XmlReader* reader)
|
||||
{
|
||||
IdlServicesWrapper* idlServicesWrapper(new IdlServicesWrapper(QString(), this));
|
||||
const QMap<QString, bool> usedServices = reader->usedServices();
|
||||
for (auto it = usedServices.begin(); it != usedServices.end(); ++it)
|
||||
{
|
||||
|
||||
if (!it.value())
|
||||
continue;
|
||||
const QString& svc = it.key();
|
||||
const QString fullPath = reader->idlFileForService(svc);
|
||||
const int idx = fullPath.lastIndexOf(QLatin1Char('.'));
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not parse file path: " << fullPath;
|
||||
continue;
|
||||
}
|
||||
const QString idlFile = fullPath.left(idx);
|
||||
if (idlFile.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find idl file for service " << svc;
|
||||
continue;
|
||||
}
|
||||
idlServicesWrapper->addService(svc, idlFile);
|
||||
DEBUG_LOG(m_logger) << "Added service " << svc;
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("ext_services"), idlServicesWrapper);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
|
||||
#ifndef GENERATORGRANTLEEBASE_H
|
||||
#define GENERATORGRANTLEEBASE_H
|
||||
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include <ktexttemplate/template.h>
|
||||
#include <ktexttemplate/context.h>
|
||||
#include <ktexttemplate/engine.h>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class StructBuilder;
|
||||
|
||||
class GeneratorGrantleeBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~GeneratorGrantleeBase();
|
||||
virtual bool init(const XmlReader* reader, StructBuilder* structBuilder) = 0;
|
||||
bool setTemplate(const QString& templateName, const QString& tmpl);
|
||||
QString render() const;
|
||||
QString errorString() const;
|
||||
bool generateData(const QString& templateName, const QString& outDirectory);
|
||||
|
||||
protected:
|
||||
explicit GeneratorGrantleeBase(const char* loggerName);
|
||||
|
||||
bool initInternal(const XmlReader* reader, StructBuilder* structBuilder);
|
||||
bool readFile(const QString& filename, QString& data) const;
|
||||
bool getFilenameFromData(const QString& dataToParse, QString& filename) const;
|
||||
void addCustomFunctions(const QVector<CustomServiceFunctionInformation>& customFunctions);
|
||||
void exportUsedServices(const XmlReader* reader);
|
||||
|
||||
protected:
|
||||
KTextTemplate::Engine* m_engine;
|
||||
KTextTemplate::Context* m_ctx;
|
||||
KTextTemplate::Template m_template;
|
||||
StructBuilder* m_structBuilder;
|
||||
NGL::INGLLogger& m_logger;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
|
||||
#endif // GENERATORGRANTLEEBASE_H
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef GRANTLEEPARSERSMOKE_H
|
||||
#define GRANTLEEPARSERSMOKE_H
|
||||
|
||||
/**
|
||||
* @brief GrantleeParserSmoke - Minimal header for test compilation
|
||||
*
|
||||
* This header exists solely to allow test_GrantleeParserSmoke.cpp to compile.
|
||||
* The actual Grantlee parser smoke test is implemented in
|
||||
* Lts/Common/CodeGen/tests/GrantleeParserSmoke.cpp as a standalone executable.
|
||||
*
|
||||
* This file was accidentally deleted and needs to be restored for BUILD_TESTING.
|
||||
*/
|
||||
|
||||
namespace GrantleeParserSmoke
|
||||
{
|
||||
// Placeholder namespace for test compilation
|
||||
// Actual implementation is in Lts/Common/CodeGen/tests/GrantleeParserSmoke.cpp
|
||||
}
|
||||
|
||||
#endif // GRANTLEEPARSERSMOKE_H
|
||||
@@ -1,203 +0,0 @@
|
||||
|
||||
|
||||
#include "GrantleeWrappers.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <utility>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
QString IdlStructWrapper::extensibility2String(dds::core::xtypes::ExtensibilityKind extensiblity)
|
||||
{
|
||||
switch (extensiblity.underlying())
|
||||
{
|
||||
case dds::core::xtypes::ExtensibilityKind_def::type::FINAL:
|
||||
return QStringLiteral("FINAL_EXTENSIBILITY");
|
||||
case dds::core::xtypes::ExtensibilityKind_def::type::MUTABLE:
|
||||
return QStringLiteral("MUTABLE_EXTENSIBILITY");
|
||||
case dds::core::xtypes::ExtensibilityKind_def::type::EXTENSIBLE:
|
||||
return QStringLiteral("EXTENSIBLE_EXTENSIBILITY");
|
||||
}
|
||||
Q_ASSERT_X(false, "IdlStructWrapper::extensibility2String", "Unknown extensiblity kind");
|
||||
return QString();
|
||||
}
|
||||
#else
|
||||
QString IdlStructWrapper::extensibility2String(int /*extensiblity*/)
|
||||
{
|
||||
// RTI not available - return placeholder
|
||||
return QStringLiteral("EXTENSIBLE_EXTENSIBILITY");
|
||||
}
|
||||
#endif
|
||||
|
||||
QString DataTopicWrapper::typeFq() const
|
||||
{
|
||||
const QString& t = type();
|
||||
const QString& s = serviceName();
|
||||
if (s.isEmpty())
|
||||
return t;
|
||||
if (t.startsWith(s))
|
||||
return t;
|
||||
return s + QStringLiteral("::") + t;
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::ddsToQVariant() const
|
||||
{
|
||||
// rtiddsgen 7.7 generates plain public members - access them directly.
|
||||
return QStringLiteral("toQVariant(data.") + cppMemberName() + QStringLiteral(")");
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::qVariantToDds() const
|
||||
{
|
||||
const QString ddsType =
|
||||
isOptional() ? (QStringLiteral("dds::core::optional<") + cppDdsType() + QLatin1Char('>')) : (cppDdsType());
|
||||
|
||||
return QStringLiteral("data.") + cppMemberName() + QStringLiteral(" = fromQVariant<") + ddsType +
|
||||
QStringLiteral(">(q.value(i++))");
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::ddsToJsonElement() const
|
||||
{
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppType() + QStringLiteral("\")] = element;");
|
||||
|
||||
// rtiddsgen 7.7 generates plain public members for every kind of
|
||||
// member (struct or not), so no getter call is emitted.
|
||||
const QString memberAccess = cppMemberName();
|
||||
if (!isOptional())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") + cppToJsonPre() +
|
||||
QStringLiteral("element.") + memberAccess + cppToJsonPost();
|
||||
|
||||
const QString optionalAccess = cppMemberName() + QStringLiteral(".is_set()");
|
||||
const QString getValue = cppMemberName();
|
||||
return QStringLiteral("if (element.") + optionalAccess + QStringLiteral(") ") +
|
||||
QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") + cppToJsonPre() +
|
||||
QStringLiteral("*element.") + getValue + cppToJsonPost();
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::jsonElementToDds() const
|
||||
{
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("element = ") + cppFromQvPre2() + QStringLiteral("objElement.value(QStringLiteral(\"") +
|
||||
cppType() + QStringLiteral("\"))") + cppFromJsonPost();
|
||||
|
||||
QString ret(QStringLiteral("const QJsonValue val(objElement.value(QStringLiteral(\"") + cppMemberName() +
|
||||
QStringLiteral("\"))); "));
|
||||
if (isOptional())
|
||||
ret += QStringLiteral("if (!val.isNull()) ");
|
||||
|
||||
// rtiddsgen 7.7 generates plain public members - assign instead of
|
||||
// calling a setter.
|
||||
ret += QStringLiteral("element.") + cppMemberName() + QStringLiteral(" = ") + cppFromJsonPre2() +
|
||||
QStringLiteral("val") + cppFromJsonPost();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::dbToJsonElement() const
|
||||
{
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppType() + QStringLiteral("\")] = element;");
|
||||
|
||||
if (isOptional() || cppType() == QStringLiteral("QDateTime"))
|
||||
{
|
||||
QString ret = QStringLiteral("if (") +
|
||||
((cppType() == QStringLiteral("QDateTime")) ? QString() : QStringLiteral("!")) +
|
||||
QStringLiteral("element.") + cppMemberName() +
|
||||
((cppType() == QStringLiteral("QDateTime")) ? QStringLiteral(".isValid()) ")
|
||||
: QStringLiteral(".isNull()) ")) +
|
||||
QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ");
|
||||
if (isOptional())
|
||||
return ret += cppFromQvPre2() + QStringLiteral("element.") + cppMemberName() + cppFromQvPost();
|
||||
}
|
||||
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") + cppToJsonPre() +
|
||||
QStringLiteral("element.") + cppMemberName() + cppToJsonPost();
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::jsonElementToDb() const
|
||||
{
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("element = ") + cppFromQvPre2() + QStringLiteral("objElement.value(QStringLiteral(\"") +
|
||||
cppType() + QStringLiteral("\"))") + cppFromJsonPost();
|
||||
|
||||
QString ret(QStringLiteral("const QJsonValue val(objElement.value(QStringLiteral(\"") + cppMemberName() +
|
||||
QStringLiteral("\"))); "));
|
||||
if (isOptional())
|
||||
ret += QStringLiteral("if (!val.isUndefined()) ");
|
||||
|
||||
ret += QStringLiteral("element.") + cppMemberName() + QStringLiteral(" = ") + cppFromJsonPre2() +
|
||||
QStringLiteral("val") + cppFromJsonPost();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantList DbStructWrapper::insertStructures()
|
||||
{
|
||||
|
||||
QStringList tableNames;
|
||||
QMap<QString, QVector<MemberInformationWrapper*>> structures;
|
||||
QMap<QString, MemberInformationWrapper*> primaryKeys;
|
||||
QMap<QString, MemberInformationWrapper*> fkComplexTableKeys;
|
||||
|
||||
tableNames.reserve(5);
|
||||
for (const QVariant& v : std::as_const(m_member))
|
||||
{
|
||||
MemberInformationWrapper* mi = v.value<MemberInformationWrapper*>();
|
||||
const QString& tableName = mi->info().db.table;
|
||||
if (mi->info().db.usedForInsert)
|
||||
{
|
||||
auto& tnStructure = structures[tableName];
|
||||
tnStructure.append(mi);
|
||||
if (!tableNames.contains(tableName))
|
||||
tableNames.push_back(tableName);
|
||||
}
|
||||
if (mi->info().fk)
|
||||
fkComplexTableKeys[mi->info().fk->destination.tableName] = mi;
|
||||
if (mi->info().db.isPrimaryKey)
|
||||
{
|
||||
if (!primaryKeys.contains(tableName))
|
||||
primaryKeys[tableName] = mi;
|
||||
}
|
||||
if (mi->info().db.isAssignmentForPrimaryTablePk)
|
||||
fkComplexTableKeys[mi->info().db.table] = mi;
|
||||
}
|
||||
|
||||
QVariantList vl;
|
||||
vl.reserve(tableNames.size());
|
||||
for (int i = 0; i < tableNames.size(); ++i)
|
||||
{
|
||||
const QString& tn = tableNames.at(i);
|
||||
MemberInformationWrapper* serialMember = fkComplexTableKeys.value(tn);
|
||||
MemberInformationWrapper* baseId = nullptr;
|
||||
MemberInformationWrapper* primaryKey = primaryKeys.value(tn);
|
||||
if (i == 0 && tableNames.size() > 1)
|
||||
baseId = primaryKeys.value(tn);
|
||||
|
||||
if (tableNames.size() == 1)
|
||||
{
|
||||
baseId = nullptr;
|
||||
|
||||
if (!primaryKey)
|
||||
{
|
||||
NGL::INGLLogger& logger = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("DbStructWrapper");
|
||||
WARNING_LOG(logger) << "Table " << tn << " has no primary key!";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (primaryKey->dbHasSequence())
|
||||
serialMember = primaryKey;
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<MemberInformationWrapper*> members = structures.value(tn);
|
||||
TableWrapper* tw = new TableWrapper(tn, members, serialMember, baseId, primaryKey, this);
|
||||
vl += QVariant::fromValue(tw);
|
||||
}
|
||||
|
||||
return vl;
|
||||
}
|
||||
@@ -1,932 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StructBuilder.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVariant>
|
||||
#include <utility>
|
||||
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
#include <dds/core/xtypes/EnumType.hpp>
|
||||
#endif
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class NameWrapper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ name)
|
||||
Q_PROPERTY(QString nameCc READ nameCc)
|
||||
Q_PROPERTY(QString nameFlc READ nameFlc)
|
||||
public:
|
||||
NameWrapper(const QString& name, QObject* parent) : QObject(parent), m_name(name) {}
|
||||
|
||||
QString name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString nameCc() const
|
||||
{
|
||||
return StructBuilder::camelCaseString(name(), true);
|
||||
}
|
||||
|
||||
QString nameFlc() const
|
||||
{
|
||||
return StructBuilder::firstCharLowercase(nameCc());
|
||||
}
|
||||
|
||||
private:
|
||||
const QString m_name;
|
||||
};
|
||||
|
||||
class VariantListWrapper : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList member READ member)
|
||||
public:
|
||||
using NameWrapper::NameWrapper;
|
||||
|
||||
~VariantListWrapper()
|
||||
{
|
||||
for (const QVariant& v : std::as_const(m_member))
|
||||
{
|
||||
auto ptr = v.value<QObject*>();
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList member() const
|
||||
{
|
||||
return m_member;
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariantList m_member;
|
||||
};
|
||||
|
||||
class MemberInformationWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString cppMemberName READ cppMemberName)
|
||||
Q_PROPERTY(QString cppMemberNameCc READ cppMemberNameCc)
|
||||
Q_PROPERTY(QString cppStructName READ cppStructName)
|
||||
Q_PROPERTY(QString cppType READ cppType)
|
||||
Q_PROPERTY(QString cppToQvPre READ cppToQvPre)
|
||||
Q_PROPERTY(QString cppToQvPost READ cppToQvPost)
|
||||
Q_PROPERTY(QString cppFromQvPre1 READ cppFromQvPre1)
|
||||
Q_PROPERTY(QString cppFromQvPre2 READ cppFromQvPre2)
|
||||
Q_PROPERTY(QString cppFromQvPost READ cppFromQvPost)
|
||||
Q_PROPERTY(QString cppDefault READ cppDefault)
|
||||
Q_PROPERTY(QString dbTableName READ dbTableName)
|
||||
Q_PROPERTY(QString dbColumnName READ dbColumnName)
|
||||
Q_PROPERTY(QString dbColumnNameView READ dbColumnNameView)
|
||||
Q_PROPERTY(QString ddsToQVariant READ ddsToQVariant)
|
||||
Q_PROPERTY(QString qVariantToDds READ qVariantToDds)
|
||||
Q_PROPERTY(QString ddsToJsonElement READ ddsToJsonElement)
|
||||
Q_PROPERTY(QString jsonElementToDds READ jsonElementToDds)
|
||||
Q_PROPERTY(QString dbToJsonElement READ dbToJsonElement)
|
||||
Q_PROPERTY(QString jsonElementToDb READ jsonElementToDb)
|
||||
Q_PROPERTY(bool dbHasSequence READ dbHasSequence)
|
||||
Q_PROPERTY(bool isOptional READ isOptional)
|
||||
Q_PROPERTY(bool isCppStruct READ isCppStruct)
|
||||
public:
|
||||
MemberInformationWrapper(const MemberInformation& mi, QObject* parent) : QObject(parent), m_mi(mi) {}
|
||||
|
||||
QString cppMemberName() const
|
||||
{
|
||||
return m_mi.cpp.memberName;
|
||||
}
|
||||
|
||||
QString cppMemberNameCc() const
|
||||
{
|
||||
return StructBuilder::camelCaseString(m_mi.cpp.memberName, true);
|
||||
}
|
||||
|
||||
QString cppStructName() const
|
||||
{
|
||||
return m_mi.cpp.structName;
|
||||
}
|
||||
|
||||
QString cppType() const
|
||||
{
|
||||
return m_mi.cpp.type;
|
||||
}
|
||||
|
||||
QString cppToQvPre() const
|
||||
{
|
||||
return m_mi.cpp.toVariantPre;
|
||||
}
|
||||
|
||||
QString cppToQvPost() const
|
||||
{
|
||||
return m_mi.cpp.toVariantPost;
|
||||
}
|
||||
|
||||
QString cppFromQvPre1() const
|
||||
{
|
||||
return m_mi.cpp.fromVariantPre1;
|
||||
}
|
||||
|
||||
QString cppFromQvPre2() const
|
||||
{
|
||||
return m_mi.cpp.fromVariantPre2;
|
||||
}
|
||||
|
||||
QString cppFromQvPost() const
|
||||
{
|
||||
return m_mi.cpp.fromVariantPost;
|
||||
}
|
||||
|
||||
QString cppDefault() const
|
||||
{
|
||||
return m_mi.cpp.defaultValue;
|
||||
}
|
||||
|
||||
QString dbTableName() const
|
||||
{
|
||||
return m_mi.db.table;
|
||||
}
|
||||
|
||||
QString dbColumnName() const
|
||||
{
|
||||
return m_mi.db.columnName;
|
||||
}
|
||||
|
||||
QString dbColumnNameView() const
|
||||
{
|
||||
return m_mi.db.getColumnNameView();
|
||||
}
|
||||
|
||||
QString cppDdsType() const
|
||||
{
|
||||
return m_mi.cpp.ddsType.isEmpty() ? cppType() : m_mi.cpp.ddsType;
|
||||
}
|
||||
|
||||
QString ddsToQVariant() const;
|
||||
QString qVariantToDds() const;
|
||||
QString ddsToJsonElement() const;
|
||||
QString jsonElementToDds() const;
|
||||
QString dbToJsonElement() const;
|
||||
QString jsonElementToDb() const;
|
||||
|
||||
bool dbHasSequence() const
|
||||
{
|
||||
return m_mi.db.hasSequence;
|
||||
}
|
||||
|
||||
bool isOptional() const
|
||||
{
|
||||
return m_mi.cpp.isOptional;
|
||||
}
|
||||
|
||||
bool isCppStruct() const
|
||||
{
|
||||
return m_mi.cpp.usedForCppStruct;
|
||||
}
|
||||
|
||||
QString cppToJsonPre() const
|
||||
{
|
||||
return m_mi.cpp.toJsonPre.isNull() ? m_mi.cpp.toVariantPre : m_mi.cpp.toJsonPre;
|
||||
}
|
||||
|
||||
QString cppToJsonPost() const
|
||||
{
|
||||
return m_mi.cpp.toJsonPost.isNull() ? m_mi.cpp.toVariantPost : m_mi.cpp.toJsonPost;
|
||||
}
|
||||
|
||||
QString cppFromJsonPre2() const
|
||||
{
|
||||
return m_mi.cpp.fromJsonPre2.isNull() ? m_mi.cpp.fromVariantPre2 : m_mi.cpp.fromJsonPre2;
|
||||
}
|
||||
|
||||
QString cppFromJsonPost() const
|
||||
{
|
||||
return m_mi.cpp.fromJsonPost.isNull() ? m_mi.cpp.fromVariantPost : m_mi.cpp.fromJsonPost;
|
||||
}
|
||||
|
||||
MemberInformation info() const
|
||||
{
|
||||
return m_mi;
|
||||
}
|
||||
|
||||
private:
|
||||
const MemberInformation m_mi;
|
||||
};
|
||||
|
||||
class MemberInformationListWrapper : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList cppMember READ cppMember)
|
||||
Q_PROPERTY(QVariantList jsonMember READ jsonMember)
|
||||
Q_PROPERTY(QVariantList fkMember READ fkMember)
|
||||
Q_PROPERTY(QVariantList selectRemoveMember READ selectRemoveMember)
|
||||
Q_PROPERTY(QVariantList viewMember READ viewMember)
|
||||
Q_PROPERTY(MemberInformationWrapper* ddsKey READ ddsKey)
|
||||
Q_PROPERTY(MemberInformationWrapper* primaryKey READ primaryKey)
|
||||
public:
|
||||
explicit MemberInformationListWrapper(const QString& name, const QVector<MemberInformation>& member,
|
||||
QObject* parent)
|
||||
: VariantListWrapper(name, parent)
|
||||
{
|
||||
for (const MemberInformation& mi : member)
|
||||
m_member += QVariant::fromValue(new MemberInformationWrapper(mi, this));
|
||||
}
|
||||
|
||||
QVariantList memberByFilter(const std::function<bool(const MemberInformation& mi)>& acceptFilter) const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
MemberInformationWrapper* mi = v.value<MemberInformationWrapper*>();
|
||||
if (mi && acceptFilter(mi->info()))
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
|
||||
QVariantList cppMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation& mi) { return mi.cpp.usedForCppStruct; });
|
||||
}
|
||||
|
||||
QVariantList jsonMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation& mi) { return mi.cpp.usedForJson; });
|
||||
}
|
||||
|
||||
QVariantList fkMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation& mi) { return mi.db.isForeignKey; });
|
||||
}
|
||||
|
||||
QVariantList selectRemoveMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation& mi) { return mi.db.generateSelectRemove; });
|
||||
}
|
||||
|
||||
QVariantList viewMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation& mi) { return mi.db.usedForView; });
|
||||
}
|
||||
|
||||
MemberInformationWrapper* ddsKey() const
|
||||
{
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
MemberInformationWrapper* mi = v.value<MemberInformationWrapper*>();
|
||||
if (mi->info().isDdsKey)
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MemberInformationWrapper* primaryKey() const
|
||||
{
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
MemberInformationWrapper* mi = v.value<MemberInformationWrapper*>();
|
||||
if (mi->info().db.isPrimaryKey)
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class TableWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVector<MemberInformationWrapper*> member READ member)
|
||||
|
||||
Q_PROPERTY(MemberInformationWrapper* serialMember READ serialMember)
|
||||
|
||||
Q_PROPERTY(MemberInformationWrapper* baseId READ baseId)
|
||||
|
||||
Q_PROPERTY(MemberInformationWrapper* primaryKey READ primaryKey)
|
||||
public:
|
||||
explicit TableWrapper(const QString& name, const QVector<MemberInformationWrapper*>& member,
|
||||
MemberInformationWrapper* serialMember, MemberInformationWrapper* baseId,
|
||||
MemberInformationWrapper* primaryKey, QObject* parent)
|
||||
: NameWrapper(name, parent), m_member(member), m_serialMember(serialMember), m_baseId(baseId),
|
||||
m_primaryKey(primaryKey)
|
||||
{
|
||||
}
|
||||
|
||||
QVector<MemberInformationWrapper*> member() const
|
||||
{
|
||||
return m_member;
|
||||
}
|
||||
|
||||
MemberInformationWrapper* serialMember() const
|
||||
{
|
||||
return m_serialMember;
|
||||
}
|
||||
|
||||
MemberInformationWrapper* baseId() const
|
||||
{
|
||||
return m_baseId;
|
||||
}
|
||||
|
||||
MemberInformationWrapper* primaryKey() const
|
||||
{
|
||||
return m_primaryKey;
|
||||
}
|
||||
|
||||
private:
|
||||
QVector<MemberInformationWrapper*> m_member;
|
||||
MemberInformationWrapper* m_serialMember;
|
||||
MemberInformationWrapper* m_baseId;
|
||||
MemberInformationWrapper* m_primaryKey;
|
||||
};
|
||||
|
||||
class DbStructWrapper final : public MemberInformationListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList insertStructures READ insertStructures)
|
||||
Q_PROPERTY(QString viewTableName READ viewTableName)
|
||||
Q_PROPERTY(bool deleteWithoutPkAllowed READ deleteWithoutPkAllowed)
|
||||
Q_PROPERTY(MemberInformationWrapper* primaryKey READ primaryKey)
|
||||
Q_PROPERTY(QVariantList dbNotifications READ dbNotifications)
|
||||
|
||||
public:
|
||||
explicit DbStructWrapper(const CompleteStructInformation& csi, QObject* parent)
|
||||
: MemberInformationListWrapper(csi.structName, csi.member, parent), m_csi(csi)
|
||||
{
|
||||
m_dbNotifications.reserve(m_csi.dbNotifications.size());
|
||||
for (const auto& notification : std::as_const(m_csi.dbNotifications))
|
||||
m_dbNotifications += QVariant(notification.methodName);
|
||||
}
|
||||
|
||||
MemberInformationWrapper* primaryKey() const
|
||||
{
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
MemberInformationWrapper* mi = v.value<MemberInformationWrapper*>();
|
||||
if (mi->info().db.isPrimaryKey && mi->info().db.table == primaryTableName())
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVariantList insertStructures();
|
||||
|
||||
bool deleteWithoutPkAllowed() const
|
||||
{
|
||||
return m_csi.tables.size() == 1;
|
||||
}
|
||||
|
||||
QVariantList dbNotifications() const
|
||||
{
|
||||
return m_dbNotifications;
|
||||
}
|
||||
|
||||
QString primaryTableName() const
|
||||
{
|
||||
return m_csi.primaryTable->name;
|
||||
}
|
||||
|
||||
QString viewTableName() const
|
||||
{
|
||||
return (m_csi.tables.size() == 1) ? primaryTableName() : m_csi.viewName;
|
||||
}
|
||||
|
||||
private:
|
||||
const CompleteStructInformation m_csi;
|
||||
QVariantList m_dbNotifications;
|
||||
};
|
||||
|
||||
class CustomFunctionWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString signature READ signature)
|
||||
public:
|
||||
explicit CustomFunctionWrapper(const QString& signature, QObject* parent) : QObject(parent), m_signature(signature)
|
||||
{
|
||||
}
|
||||
|
||||
QString signature() const
|
||||
{
|
||||
return m_signature;
|
||||
}
|
||||
|
||||
private:
|
||||
const QString m_signature;
|
||||
};
|
||||
|
||||
class IdlEnumKeyValueWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString key READ key)
|
||||
Q_PROPERTY(int value READ value)
|
||||
public:
|
||||
explicit IdlEnumKeyValueWrapper(const EnumKeyValuePair& ekvp, QObject* parent) : QObject(parent), m_ekvp(ekvp) {}
|
||||
|
||||
QString key() const
|
||||
{
|
||||
return m_ekvp.key;
|
||||
}
|
||||
|
||||
int value() const
|
||||
{
|
||||
return m_ekvp.value;
|
||||
}
|
||||
|
||||
private:
|
||||
const EnumKeyValuePair m_ekvp;
|
||||
};
|
||||
|
||||
class IdlDataWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString type READ type)
|
||||
Q_PROPERTY(QString comment READ comment)
|
||||
Q_PROPERTY(QString isKey READ isKey)
|
||||
Q_PROPERTY(QString isOptional READ isOptional)
|
||||
Q_PROPERTY(QString cppType READ cppType)
|
||||
Q_PROPERTY(QString cppTypeCr READ cppTypeCr)
|
||||
Q_PROPERTY(QString nameGetter READ nameGetter)
|
||||
public:
|
||||
IdlDataWrapper(const IdlData& data, QObject* parent) : NameWrapper(data.name, parent), m_data(data) {}
|
||||
|
||||
QString type() const
|
||||
{
|
||||
return m_data.dataTypeInfo->idlType();
|
||||
}
|
||||
|
||||
QString comment() const
|
||||
{
|
||||
return m_data.comment;
|
||||
}
|
||||
|
||||
QString isKey() const
|
||||
{
|
||||
return m_data.isKey ? QStringLiteral(" \t //@key") : QString();
|
||||
}
|
||||
|
||||
QString isOptional() const
|
||||
{
|
||||
return m_data.isOptional ? QStringLiteral(" \t //@Optional") : QString();
|
||||
}
|
||||
|
||||
QString cppType() const
|
||||
{
|
||||
return m_data.dataTypeInfo->cppType();
|
||||
}
|
||||
|
||||
QString cppTypeCr() const
|
||||
{
|
||||
return m_data.dataTypeInfo->cppTypeConstRef();
|
||||
}
|
||||
|
||||
QString nameGetter() const
|
||||
{
|
||||
// rtiddsgen 7.7 generates public data members (no getters); optional
|
||||
// members are omg::types::optional<T> and are unwrapped via .get().
|
||||
return m_data.name + (m_data.isOptional ? QStringLiteral(".get()") : QString());
|
||||
}
|
||||
|
||||
private:
|
||||
const IdlData m_data;
|
||||
};
|
||||
|
||||
class IdlEnumWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IdlEnumWrapper(const EnumInformation& ei, QObject* parent) : VariantListWrapper(ei.enumName, parent)
|
||||
{
|
||||
m_member.reserve(ei.values.size());
|
||||
for (const auto& val : ei.values)
|
||||
m_member += QVariant::fromValue(new IdlEnumKeyValueWrapper(val, this));
|
||||
}
|
||||
};
|
||||
|
||||
class IdlStructWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString comment READ comment)
|
||||
Q_PROPERTY(QString baseValueType READ baseValueType)
|
||||
Q_PROPERTY(QString extensibility READ extensibility)
|
||||
public:
|
||||
explicit IdlStructWrapper(const CompleteTopicTypeInformation& ctti, QObject* parent)
|
||||
: VariantListWrapper(ctti.name, parent), m_ctti(ctti)
|
||||
{
|
||||
m_member.reserve(m_ctti.members.size());
|
||||
for (const auto& val : std::as_const(m_ctti.members))
|
||||
m_member += QVariant::fromValue(new IdlDataWrapper(val, this));
|
||||
}
|
||||
|
||||
QString comment() const
|
||||
{
|
||||
return m_ctti.comment;
|
||||
}
|
||||
|
||||
QString baseValueType() const
|
||||
{
|
||||
return m_ctti.baseValueType;
|
||||
}
|
||||
|
||||
QString extensibility() const
|
||||
{
|
||||
return extensibility2String(m_ctti.extensibility);
|
||||
}
|
||||
|
||||
private:
|
||||
const CompleteTopicTypeInformation m_ctti;
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
static QString extensibility2String(dds::core::xtypes::ExtensibilityKind extensiblity);
|
||||
#else
|
||||
static QString extensibility2String(int extensiblity);
|
||||
#endif
|
||||
};
|
||||
|
||||
class IdlServiceWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString svcName READ svcName)
|
||||
Q_PROPERTY(QString baseFilePath READ baseFilePath)
|
||||
public:
|
||||
IdlServiceWrapper(const QString& svcName, const QString& baseFilePath)
|
||||
: m_svcName(svcName), m_baseFilePath(baseFilePath)
|
||||
{
|
||||
}
|
||||
|
||||
QString svcName() const
|
||||
{
|
||||
return m_svcName;
|
||||
}
|
||||
|
||||
QString baseFilePath() const
|
||||
{
|
||||
return m_baseFilePath;
|
||||
}
|
||||
|
||||
private:
|
||||
const QString m_svcName;
|
||||
const QString m_baseFilePath;
|
||||
};
|
||||
|
||||
class FunctionTopicWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString onReply READ onReply)
|
||||
Q_PROPERTY(QString onRequest READ onRequest)
|
||||
Q_PROPERTY(QString onError READ onError)
|
||||
Q_PROPERTY(bool isCoreFt READ isCoreFt)
|
||||
Q_PROPERTY(bool routeInReplay READ routeInReplay)
|
||||
|
||||
Q_PROPERTY(QString reply READ reply)
|
||||
Q_PROPERTY(QString replyFlc READ replyFlc)
|
||||
Q_PROPERTY(QString replyHandler READ replyHandler)
|
||||
Q_PROPERTY(QString replyHandlerFlc READ replyHandlerFlc)
|
||||
Q_PROPERTY(QString replyType READ replyType)
|
||||
Q_PROPERTY(QString replyTypeFro READ replyTypeFro)
|
||||
Q_PROPERTY(QVariantList replyParams READ replyParams)
|
||||
Q_PROPERTY(QString replyHandlerHash READ replyHandlerHash WRITE setReplyHandlerHash)
|
||||
|
||||
Q_PROPERTY(QString request READ request)
|
||||
Q_PROPERTY(QString requestFlc READ requestFlc)
|
||||
Q_PROPERTY(QString requestHandler READ requestHandler)
|
||||
Q_PROPERTY(QString requestHandlerFlc READ requestHandlerFlc)
|
||||
Q_PROPERTY(QString requestType READ requestType)
|
||||
Q_PROPERTY(QVariantList requestParams READ requestParams)
|
||||
|
||||
public:
|
||||
FunctionTopicWrapper(const FunctionTopic& ft, const CompleteTopicTypeInformation& siRequest,
|
||||
const CompleteTopicTypeInformation& siReply, QObject* parent)
|
||||
: NameWrapper(ft.name, parent), m_ft(ft), m_request(siRequest), m_reply(siReply)
|
||||
{
|
||||
}
|
||||
|
||||
QString onReply() const
|
||||
{
|
||||
return QLatin1String("on") + m_ft.replyTopicName;
|
||||
}
|
||||
|
||||
QString onRequest() const
|
||||
{
|
||||
return QLatin1String("on") + m_ft.requestTopicName;
|
||||
}
|
||||
|
||||
QString onError() const
|
||||
{
|
||||
return QLatin1String("on") + m_ft.name + QLatin1String("Error");
|
||||
}
|
||||
|
||||
bool isCoreFt() const
|
||||
{
|
||||
return (m_ft.replyTopicType == QStringLiteral("Core::FunctionReply") ||
|
||||
m_ft.replyTopicType == QStringLiteral("FunctionReply"));
|
||||
}
|
||||
|
||||
bool routeInReplay() const
|
||||
{
|
||||
return m_ft.routeInReplay;
|
||||
}
|
||||
|
||||
QString reply() const
|
||||
{
|
||||
return m_ft.replyTopicName;
|
||||
}
|
||||
|
||||
QString replyFlc() const
|
||||
{
|
||||
return StructBuilder::firstCharLowercase(reply());
|
||||
}
|
||||
|
||||
QString replyHandler() const
|
||||
{
|
||||
return m_ft.replyTopicName + QLatin1String("Handler");
|
||||
}
|
||||
|
||||
QString replyHandlerFlc() const
|
||||
{
|
||||
return StructBuilder::firstCharLowercase(replyHandler());
|
||||
}
|
||||
|
||||
QString replyType() const
|
||||
{
|
||||
return m_reply.name;
|
||||
}
|
||||
|
||||
QString replyTypeFro() const
|
||||
{
|
||||
return isCoreFt() ? QStringLiteral("Core::FunctionReplyObject") : m_reply.name;
|
||||
}
|
||||
|
||||
QString request() const
|
||||
{
|
||||
return m_ft.requestTopicName;
|
||||
}
|
||||
|
||||
QString requestFlc() const
|
||||
{
|
||||
return StructBuilder::firstCharLowercase(request());
|
||||
}
|
||||
|
||||
QString requestHandler() const
|
||||
{
|
||||
return m_ft.requestTopicName + QLatin1String("Handler");
|
||||
}
|
||||
|
||||
QString requestHandlerFlc() const
|
||||
{
|
||||
return StructBuilder::firstCharLowercase(requestHandler());
|
||||
}
|
||||
|
||||
QString requestType() const
|
||||
{
|
||||
return m_request.name;
|
||||
}
|
||||
|
||||
void addRequestParams(const QVector<IdlData>& params)
|
||||
{
|
||||
for (const auto& param : params)
|
||||
m_requestParams.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
|
||||
QVariantList requestParams() const
|
||||
{
|
||||
return m_requestParams;
|
||||
}
|
||||
|
||||
void addReplyParams(const QVector<IdlData>& params)
|
||||
{
|
||||
for (const auto& param : params)
|
||||
m_replyParams.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
|
||||
QVariantList replyParams() const
|
||||
{
|
||||
return m_replyParams;
|
||||
}
|
||||
|
||||
QString replyHandlerHash() const
|
||||
{
|
||||
return m_replyHandlerHash;
|
||||
}
|
||||
|
||||
void setReplyHandlerHash(const QString& hash)
|
||||
{
|
||||
m_replyHandlerHash = hash;
|
||||
}
|
||||
|
||||
private:
|
||||
const FunctionTopic m_ft;
|
||||
const CompleteTopicTypeInformation m_request;
|
||||
const CompleteTopicTypeInformation m_reply;
|
||||
QVariantList m_requestParams;
|
||||
QVariantList m_replyParams;
|
||||
QString m_replyHandlerHash;
|
||||
};
|
||||
|
||||
class FunctionTopicsWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QVariantList topicsToRouteInReplay READ topicsToRouteInReplay)
|
||||
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
FunctionTopicWrapper* addFunctionTopic(const FunctionTopic& ft, const CompleteTopicTypeInformation& siRequest,
|
||||
const CompleteTopicTypeInformation& siReply)
|
||||
{
|
||||
FunctionTopicWrapper* ret = new FunctionTopicWrapper(ft, siRequest, siReply, this);
|
||||
m_member += QVariant::fromValue(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantList topicsToRouteInReplay() const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
FunctionTopicWrapper* ft = v.value<FunctionTopicWrapper*>();
|
||||
if (ft->routeInReplay())
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
};
|
||||
|
||||
class DataTopicWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString serviceName READ serviceName)
|
||||
Q_PROPERTY(QString type READ type)
|
||||
Q_PROPERTY(QString typeFq READ typeFq)
|
||||
Q_PROPERTY(QVariant key READ key)
|
||||
Q_PROPERTY(bool dtcImpl READ dtcImpl)
|
||||
Q_PROPERTY(bool dtsImpl READ dtsImpl)
|
||||
Q_PROPERTY(bool recordTopic READ recordTopic)
|
||||
Q_PROPERTY(QVariant recTable READ recTable)
|
||||
Q_PROPERTY(QVariantList trColumns READ trColumns)
|
||||
Q_PROPERTY(bool hasTrColumns READ hasTrColumns)
|
||||
Q_PROPERTY(bool routeToClient READ routeToClient)
|
||||
Q_PROPERTY(bool routeToServer READ routeToServer)
|
||||
Q_PROPERTY(bool routeInReplay READ routeInReplay)
|
||||
Q_PROPERTY(bool autosubscribe READ isAutoSubscribe)
|
||||
|
||||
public:
|
||||
DataTopicWrapper(const CompleteTopicTypeInformation& ctti, QObject* parent)
|
||||
: NameWrapper(ctti.name, parent), m_ctti(ctti), m_keyData(nullptr), m_recordData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void setKeyColumnData(const IdlData& data)
|
||||
{
|
||||
delete m_keyData;
|
||||
m_keyData = new IdlDataWrapper(data, this);
|
||||
}
|
||||
|
||||
void setTrColumns(const QVector<IdlData>& params)
|
||||
{
|
||||
for (const auto& param : params)
|
||||
m_trColumns.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
|
||||
QVariantList trColumns() const
|
||||
{
|
||||
return m_trColumns;
|
||||
}
|
||||
|
||||
bool hasTrColumns() const
|
||||
{
|
||||
return !m_trColumns.empty();
|
||||
}
|
||||
|
||||
void setRecordTableInformation(const CompleteTableInformation& cti)
|
||||
{
|
||||
delete m_recordData;
|
||||
m_recordData = new MemberInformationListWrapper(cti.name, cti.columns, this);
|
||||
m_ctti.recordTopic = true;
|
||||
}
|
||||
|
||||
QString serviceName() const
|
||||
{
|
||||
return m_ctti.serviceName;
|
||||
}
|
||||
|
||||
QString type() const
|
||||
{
|
||||
return m_ctti.name;
|
||||
}
|
||||
|
||||
QString typeFq() const;
|
||||
|
||||
QVariant key() const
|
||||
{
|
||||
return m_keyData ? QVariant::fromValue(m_keyData) : QVariant();
|
||||
}
|
||||
|
||||
bool dtsImpl() const
|
||||
{
|
||||
return m_ctti.dtsAutogen;
|
||||
}
|
||||
|
||||
bool dtcImpl() const
|
||||
{
|
||||
return m_ctti.dtcAutogen;
|
||||
}
|
||||
|
||||
bool recordTopic() const
|
||||
{
|
||||
return m_ctti.recordTopic && m_recordData;
|
||||
}
|
||||
|
||||
bool routeToClient() const
|
||||
{
|
||||
return m_ctti.routeToClient;
|
||||
}
|
||||
|
||||
bool routeToServer() const
|
||||
{
|
||||
return m_ctti.routeToServer;
|
||||
}
|
||||
|
||||
bool routeInReplay() const
|
||||
{
|
||||
return m_ctti.routeInReplay;
|
||||
}
|
||||
|
||||
bool isAutoSubscribe() const
|
||||
{
|
||||
return m_ctti.autosubscribe;
|
||||
}
|
||||
|
||||
QVariant recTable() const
|
||||
{
|
||||
return recordTopic() ? QVariant::fromValue(m_recordData) : QVariant();
|
||||
}
|
||||
|
||||
private:
|
||||
CompleteTopicTypeInformation m_ctti;
|
||||
IdlDataWrapper* m_keyData;
|
||||
MemberInformationListWrapper* m_recordData;
|
||||
QVariantList m_trColumns;
|
||||
};
|
||||
|
||||
class DataTopicsWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QVariantList topicsToRouteInReplay READ topicsToRouteInReplay)
|
||||
Q_PROPERTY(QVariantList topicsToRouteToClient READ topicsToRouteToClient)
|
||||
Q_PROPERTY(QVariantList topicsToRouteToServer READ topicsToRouteToServer)
|
||||
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
DataTopicWrapper* addDataTopic(const CompleteTopicTypeInformation& ctti)
|
||||
{
|
||||
DataTopicWrapper* ret = new DataTopicWrapper(ctti, this);
|
||||
m_member += QVariant::fromValue(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantList memberByFilter(const std::function<bool(const DataTopicWrapper* dtw)>& acceptFilter) const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant& v : m_member)
|
||||
{
|
||||
DataTopicWrapper* dtw = v.value<DataTopicWrapper*>();
|
||||
if (dtw && acceptFilter(dtw))
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
|
||||
QVariantList topicsToRouteInReplay() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper* dtw) { return dtw->routeInReplay(); });
|
||||
}
|
||||
|
||||
QVariantList topicsToRouteToClient() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper* dtw) { return dtw->routeToClient(); });
|
||||
}
|
||||
|
||||
QVariantList topicsToRouteToServer() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper* dtw) { return dtw->routeToServer(); });
|
||||
}
|
||||
};
|
||||
|
||||
class IdlServicesWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
void addService(const QString& svcName, const QString& baseFilePath)
|
||||
{
|
||||
m_member += QVariant::fromValue(new IdlServiceWrapper(svcName, baseFilePath));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
@@ -1,37 +0,0 @@
|
||||
#
|
||||
# Hinweise für den CodeGen
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
Erstellt: Mai 2022, Norbert Thoden
|
||||
|
||||
Der Aufruf des CodeGen kann z.B. so aussehen:
|
||||
|
||||
codegen -s /tmp/ppm_serviceORG.xml -i /shd/CTC/TOOLS/TDS/TDS-build/service_idl_files.txt -a dds_topics -o /tmp /shd/CTC/TOOLS/TDS/TDS-source/Lts/Common/CodeGen/svc_record_replay_plugin.cpp.grantlee
|
||||
Edit Juni 2023, Niklas Schmidt
|
||||
|
||||
Ebenso ist es nicht möglich einen Struct aus einem anderen Service(Service B) zu verwenden,
|
||||
der in sich widerum einen anderen Struct aus dem anderen Service (Service B) beinhaltet.
|
||||
|
||||
Bsp:
|
||||
|
||||
Service A = Struct1{ int id,
|
||||
Struct2 test
|
||||
}
|
||||
|
||||
Service B = Struct2{
|
||||
int id2,
|
||||
Struct3 test
|
||||
}
|
||||
|
||||
Service B = Struct3{
|
||||
std::string test
|
||||
}
|
||||
|
||||
Mögliche Diagnose:
|
||||
|
||||
Wenn Struct3 aus Service A aufgerufen wird, ist wahrscheinlich nicht mehr gekennzeichnet dass der Struct3 aus Service B kommt. Dieser kann somit nicht
|
||||
aufgelöst werden
|
||||
@@ -1,892 +0,0 @@
|
||||
|
||||
|
||||
#include "SqlGenerator.h"
|
||||
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
static QString getExerciseSchemaName(int exerciseId)
|
||||
{
|
||||
return QStringLiteral("ex_") + QString::number(exerciseId);
|
||||
}
|
||||
|
||||
SqlGenerator::SqlGenerator(XmlReader* xmlReader, StructBuilder* structBuilder)
|
||||
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.SqlGenerator")),
|
||||
m_xmlReader(xmlReader), m_structBuilder(structBuilder), m_createdByXmlFile(false), m_isValid(true),
|
||||
m_exerciseId(0)
|
||||
{
|
||||
}
|
||||
|
||||
SqlGenerator::SqlGenerator(const QString& xmlFile)
|
||||
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.SqlGenerator")),
|
||||
m_xmlReader(new XmlReader), m_structBuilder(new StructBuilder(m_xmlReader)), m_createdByXmlFile(true),
|
||||
m_isValid(false), m_exerciseId(0)
|
||||
{
|
||||
m_isValid = m_xmlReader->readServiceFile(xmlFile, QString()) && m_structBuilder->buildStructures();
|
||||
}
|
||||
|
||||
SqlGenerator::~SqlGenerator()
|
||||
{
|
||||
if (m_createdByXmlFile)
|
||||
{
|
||||
delete m_xmlReader;
|
||||
delete m_structBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
bool SqlGenerator::generateData(int exerciseId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Generating SQL data for service " << getServiceAbbr() << " in exercise " << exerciseId
|
||||
<< ", this: " << this;
|
||||
|
||||
m_exerciseId = exerciseId;
|
||||
m_sqlGlobal = SqlStatements();
|
||||
m_sqlExercise = SqlStatements();
|
||||
m_sqlItemsGlobal = SqlItems();
|
||||
m_sqlItemsExercise = SqlItems();
|
||||
m_referencedSevices.clear();
|
||||
|
||||
if (!handleTables())
|
||||
return false;
|
||||
|
||||
if (!handleViews())
|
||||
return false;
|
||||
|
||||
if (!handleEnumerations())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::createStatementsForTable(const QString& tableName, const QString& tableNameOut)
|
||||
{
|
||||
const QMap<QString, CompleteTableInformation> tables = m_structBuilder->getDbTables();
|
||||
for (const CompleteTableInformation& cti : tables)
|
||||
{
|
||||
if (cti.name != tableName)
|
||||
continue;
|
||||
CompleteTableInformation ctiOut = cti;
|
||||
ctiOut.name = tableNameOut;
|
||||
return handleTable(ctiOut);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleTables()
|
||||
{
|
||||
const QMap<QString, CompleteTableInformation> tables = m_structBuilder->getDbTables();
|
||||
for (const CompleteTableInformation& cti : tables)
|
||||
{
|
||||
if (!handleTable(cti))
|
||||
return false;
|
||||
}
|
||||
|
||||
const QMap<QString, CompleteTableInformation> recTables = m_structBuilder->getRecordingTopicTables();
|
||||
MemberInformation miColumnIsValid;
|
||||
miColumnIsValid.db.columnName = QStringLiteral("dds_is_alive");
|
||||
miColumnIsValid.db.datatype = QStringLiteral("boolean");
|
||||
miColumnIsValid.db.defaultValue = QStringLiteral("true");
|
||||
MemberInformation miInsertionTime;
|
||||
miInsertionTime.cpp.type = QStringLiteral("timestamp");
|
||||
miInsertionTime.db.columnName = QStringLiteral("insert_time");
|
||||
miInsertionTime.db.defaultValue = QStringLiteral("now()");
|
||||
miInsertionTime.db.usedForInsert = false;
|
||||
m_structBuilder->fixupQVariantConversions(miInsertionTime);
|
||||
ConstraintInformation ci;
|
||||
ci.name = QStringLiteral("IDX_sample_time");
|
||||
ci.affectedColumns = QStringList({QStringLiteral("sample_time")});
|
||||
ci.type = ConstraintInformation::Type::index;
|
||||
for (const CompleteTableInformation& cti : recTables)
|
||||
{
|
||||
CompleteTableInformation ctiTmp(cti);
|
||||
ctiTmp.columns.push_back(miColumnIsValid);
|
||||
ctiTmp.columns.push_back(miInsertionTime);
|
||||
ctiTmp.constraints.push_back(ci);
|
||||
if (!handleTable(ctiTmp))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleViews()
|
||||
{
|
||||
const QMap<QString, ViewInformation> views = m_structBuilder->getDbViews();
|
||||
for (const ViewInformation& vi : views)
|
||||
{
|
||||
if (!handleView(vi))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleView(const ViewInformation& vi)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle view " << vi.name;
|
||||
|
||||
const QString parent = vi.baseTable;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Parent = " << parent;
|
||||
|
||||
if (!parent.isEmpty())
|
||||
{
|
||||
const CompleteStructInformation csi = m_structBuilder->structInformationByTableName(parent);
|
||||
const QString createViewStmt(QStringLiteral("CREATE OR REPLACE VIEW %1 AS SELECT %2\nFROM %3\nWHERE %4;\n"));
|
||||
const QString dropViewStmt(QStringLiteral("DROP VIEW IF EXISTS %1;"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "csi.primaryTable = " << csi.primaryTable.data()->name;
|
||||
|
||||
if (!csi.primaryTable.isNull())
|
||||
{
|
||||
QStringList fromTables;
|
||||
fromTables += vi.baseSchema + QLatin1Char('.') + vi.baseTable;
|
||||
|
||||
QStringList whereConditions;
|
||||
if (vi.filter.contains(QLatin1String("exercise_id")))
|
||||
whereConditions += QLatin1String("exercise_id=") + QString::number(m_exerciseId);
|
||||
|
||||
QStringList fqColumnNames;
|
||||
|
||||
for (const MemberInformation& mi : csi.member)
|
||||
{
|
||||
if (mi.db.usedForView)
|
||||
fqColumnNames += mi.db.table + QLatin1Char('.') + mi.db.columnName + QLatin1String(" AS ") +
|
||||
mi.db.getColumnNameView();
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "fqColumnNames = " << fqColumnNames.join(QStringLiteral(", "));
|
||||
|
||||
if (!whereConditions.isEmpty())
|
||||
addToCreateViews(createViewStmt.arg(csi.viewName, fqColumnNames.join(QStringLiteral(", ")),
|
||||
fromTables.join(QStringLiteral(", ")),
|
||||
whereConditions.join(QStringLiteral(" AND\n"))),
|
||||
vi.exerciseDependency);
|
||||
addToDropViews(dropViewStmt.arg(csi.viewName), vi.exerciseDependency);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleTable(const CompleteTableInformation& cti)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle table " << cti.name;
|
||||
|
||||
if (cti.columns.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Table " << cti.name
|
||||
<< " has no DatabaseServiceStruct - not generating anything for this!";
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString dropTableStmt(QStringLiteral("DROP TABLE IF EXISTS %1 CASCADE;"));
|
||||
const QString createTableStmt(QStringLiteral("CREATE TABLE IF NOT EXISTS %1 (%2\n);"));
|
||||
const QString commentTableStmt(QStringLiteral("COMMENT ON TABLE %1 IS '%2';"));
|
||||
|
||||
QStringList tableComments;
|
||||
addToDropTables(dropTableStmt.arg(cti.name), cti.exerciseDependency);
|
||||
|
||||
if ((cti.exerciseDependency & Global) == Global)
|
||||
{
|
||||
addToCreateTables(createTableStmt.arg(
|
||||
cti.name, getTableColumnCreateStatements(cti.name, cti.columns, &tableComments, Global)),
|
||||
Global);
|
||||
}
|
||||
if ((cti.exerciseDependency & Exercise) == Exercise)
|
||||
{
|
||||
addToCreateTables(createTableStmt.arg(cti.name, getTableColumnCreateStatements(cti.name, cti.columns,
|
||||
&tableComments, Exercise)),
|
||||
Exercise);
|
||||
}
|
||||
addToTables(cti.name, cti.exerciseDependency);
|
||||
|
||||
if (!cti.comment.isEmpty())
|
||||
addToCreateTables(commentTableStmt.arg(cti.name, fixupComment(cti.comment)), cti.exerciseDependency);
|
||||
addToCreateTables(tableComments, cti.exerciseDependency);
|
||||
|
||||
const QString parent = m_xmlReader->getStruct2BaseClassRelations().value(cti.name);
|
||||
const CompleteStructInformation csi = m_structBuilder->structInformationByTableName(cti.name);
|
||||
if (!parent.isEmpty())
|
||||
{
|
||||
const QString createViewStmt(QStringLiteral("CREATE OR REPLACE VIEW %1 AS SELECT %2\nFROM %3\nWHERE %4;\n"));
|
||||
const QString dropViewStmt(QStringLiteral("DROP VIEW IF EXISTS %1;"));
|
||||
if (!csi.primaryTable.isNull())
|
||||
{
|
||||
QStringList fqColumnNames;
|
||||
QStringList fromTables;
|
||||
QStringList whereConditions;
|
||||
fromTables += cti.name;
|
||||
|
||||
for (const MemberInformation& mi : csi.member)
|
||||
{
|
||||
if (mi.db.usedForView)
|
||||
fqColumnNames += mi.db.table + QLatin1Char('.') + mi.db.columnName + QLatin1String(" AS ") +
|
||||
mi.db.getColumnNameView();
|
||||
if (mi.cpp.isReadOnly && mi.db.isForeignKey)
|
||||
{
|
||||
|
||||
for (const QSharedPointer<TableInformation>& tiPtr : csi.tables)
|
||||
{
|
||||
if (tiPtr->name == mi.db.table)
|
||||
{
|
||||
const QSharedPointer<ForeignKeyInformation> fki =
|
||||
tiPtr->fkInformationForColumn(mi.db.table, mi.db.columnName);
|
||||
if (!fki.isNull())
|
||||
{
|
||||
|
||||
if (!fromTables.contains(fki->destination.tableName))
|
||||
{
|
||||
whereConditions += fki->destination.tableName + QLatin1Char('.') +
|
||||
fki->destination.columnName + QLatin1String(" = ") +
|
||||
fki->source.tableName + QLatin1Char('.') +
|
||||
fki->source.columnName;
|
||||
fromTables += fki->destination.tableName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!whereConditions.isEmpty())
|
||||
{
|
||||
addToCreateViews(createViewStmt.arg(csi.viewName, fqColumnNames.join(QStringLiteral(", ")),
|
||||
fromTables.join(QStringLiteral(", ")),
|
||||
whereConditions.join(QStringLiteral(" AND\n"))),
|
||||
cti.exerciseDependency);
|
||||
}
|
||||
addToDropViews(dropViewStmt.arg(csi.viewName), cti.exerciseDependency);
|
||||
}
|
||||
}
|
||||
|
||||
if (!generateDbNotifications(cti.name, csi.dbNotifications, cti.exerciseDependency))
|
||||
return false;
|
||||
|
||||
generateForeignKeys(cti.foreignKeys, cti.exerciseDependency);
|
||||
|
||||
generateConstraints(cti.name, cti.constraints, cti.exerciseDependency);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SqlGenerator::getTableColumnCreateStatements(const QString& tableName,
|
||||
const QVector<MemberInformation>& columns,
|
||||
QStringList* tableComments, ExerciseDependency ed)
|
||||
{
|
||||
Q_ASSERT(ed == Global || ed == Exercise);
|
||||
|
||||
const QString commentColumnStmt(QStringLiteral("COMMENT ON COLUMN %1 IS '%2';"));
|
||||
|
||||
int maxLength = 1;
|
||||
for (const MemberInformation& mi : columns)
|
||||
maxLength = std::max(maxLength, static_cast<int>(mi.db.columnName.length()));
|
||||
maxLength += 1;
|
||||
|
||||
QStringList retCols;
|
||||
retCols.reserve(columns.size() + 1);
|
||||
retCols += QString();
|
||||
for (int i = 0; i < columns.size(); ++i)
|
||||
{
|
||||
const MemberInformation& mi = columns.at(i);
|
||||
const FullQualifiedColumnInformation& ci = mi.db;
|
||||
const QString spaces(maxLength - ci.columnName.length(), QLatin1Char(' '));
|
||||
QString column = ci.columnName + spaces + ci.datatype;
|
||||
if (ci.hasSequence)
|
||||
{
|
||||
|
||||
const QString seqDescr = generateSequence(tableName, ci, ed);
|
||||
QString schema;
|
||||
if (ed == Global)
|
||||
schema = m_xmlReader->getServiceAbbr();
|
||||
else
|
||||
schema = getExerciseSchemaName(m_exerciseId);
|
||||
|
||||
column += QLatin1String(" DEFAULT nextval(( '") + schema + QLatin1Char('.') + seqDescr +
|
||||
QLatin1String("'::text)::regclass)");
|
||||
}
|
||||
if (!ci.canBeNull)
|
||||
column += QLatin1String(" NOT NULL");
|
||||
if (!ci.hasSequence && !ci.defaultValue.isEmpty())
|
||||
column += QLatin1String(" DEFAULT ") + ci.defaultValue;
|
||||
if (i < columns.size() - 1)
|
||||
column += QLatin1Char(',');
|
||||
if (!ci.comment.isEmpty())
|
||||
{
|
||||
const QString comment(fixupComment(ci.comment));
|
||||
const QString fqn = ci.table + QLatin1Char('.') + ci.columnName;
|
||||
*tableComments += commentColumnStmt.arg(fqn, comment);
|
||||
column += QLatin1String(" -- ") + comment;
|
||||
}
|
||||
|
||||
retCols += column;
|
||||
|
||||
if (ci.isPrimaryKey)
|
||||
generatePrimaryKey(tableName, ci, ed);
|
||||
}
|
||||
return retCols.join(QStringLiteral("\n "));
|
||||
}
|
||||
|
||||
QString SqlGenerator::generateSequence(const QString& tableName, const FullQualifiedColumnInformation& ci,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
const QString sequenceName = tableName + QLatin1Char('_') + ci.columnName + QLatin1String("_seq");
|
||||
|
||||
const QString createSequenceStmt(
|
||||
QLatin1String("CREATE SEQUENCE IF NOT EXISTS %1 INCREMENT %2 START %3 MINVALUE %4;"));
|
||||
|
||||
const int minValue = ci.sequenceStart < 1 ? ci.sequenceStart : 1;
|
||||
|
||||
addToCreateSequences(
|
||||
createSequenceStmt.arg(sequenceName).arg(ci.sequenceIncrement).arg(ci.sequenceStart).arg(minValue), ed);
|
||||
addToSequences(sequenceName, ed);
|
||||
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
void SqlGenerator::generatePrimaryKey(const QString& tableName, const FullQualifiedColumnInformation& ci,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
QString pkName = QLatin1String("PK_") + tableName + QLatin1Char('_') + ci.columnName;
|
||||
|
||||
if (pkName.size() > 63)
|
||||
pkName.resize(63);
|
||||
|
||||
addToPks(pkName, ed);
|
||||
|
||||
const QString pkConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 ADD CONSTRAINT %2 PRIMARY KEY (%3);"));
|
||||
addToCreatePks(pkConstraint.arg(tableName, pkName, ci.columnName), ed);
|
||||
|
||||
const QString pkDropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
addToDropConstraints(pkDropConstraint.arg(tableName, pkName), ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateForeignKeys(const QVector<QSharedPointer<ForeignKeyInformation>>& foreignKeys,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const QSharedPointer<ForeignKeyInformation>& fk : foreignKeys)
|
||||
generateForeignKey(fk, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateForeignKey(const QSharedPointer<ForeignKeyInformation>& foreignKey, ExerciseDependency ed)
|
||||
{
|
||||
QString fkName = QLatin1String("FK_") + foreignKey->source.tableName + QLatin1Char('_') +
|
||||
foreignKey->source.columnName + QLatin1Char('_') + foreignKey->destination.tableName +
|
||||
QLatin1Char('_') + foreignKey->destination.columnName;
|
||||
|
||||
if (fkName.size() > 63)
|
||||
fkName = foreignKey->name;
|
||||
|
||||
addToFks(fkName, ed);
|
||||
|
||||
QString fkConstraint(QStringLiteral("ALTER TABLE %1 ADD CONSTRAINT %2 FOREIGN KEY (%3) REFERENCES %4 (%5)"));
|
||||
switch (foreignKey->deleteAction)
|
||||
{
|
||||
case ForeignKeyInformation::OnDeleteAction::NoAction:
|
||||
fkConstraint += QStringLiteral(" ON DELETE NO ACTION");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::Cascade:
|
||||
fkConstraint += QStringLiteral(" ON DELETE CASCADE ON UPDATE CASCADE");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::Restrict:
|
||||
fkConstraint += QStringLiteral(" ON DELETE RESTRICT");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::SetNull:
|
||||
fkConstraint += QStringLiteral(" ON DELETE SET NULL");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::SetDefault:
|
||||
fkConstraint += QStringLiteral(" ON DELETE SET DEFAULT");
|
||||
break;
|
||||
}
|
||||
|
||||
fkConstraint += QLatin1Char(';');
|
||||
|
||||
QString destination;
|
||||
if (!foreignKey->destination.schema.isEmpty())
|
||||
{
|
||||
const QString& extSchema = foreignKey->destination.schema;
|
||||
destination = extSchema + QLatin1Char('.') + foreignKey->destination.tableName;
|
||||
}
|
||||
else
|
||||
destination = foreignKey->destination.tableName;
|
||||
|
||||
const QString& extSvcAbbr = foreignKey->destination.serviceAbbr;
|
||||
|
||||
if (!extSvcAbbr.isEmpty() && !m_referencedSevices.contains(extSvcAbbr))
|
||||
m_referencedSevices += extSvcAbbr;
|
||||
|
||||
addToCreateFks(fkConstraint.arg(foreignKey->source.tableName, fkName, foreignKey->source.columnName, destination,
|
||||
foreignKey->destination.columnName),
|
||||
ed);
|
||||
|
||||
const QString fkDropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
addToDropConstraints(fkDropConstraint.arg(foreignKey->source.tableName, fkName), ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateConstraints(const QString& tableName, const QVector<ConstraintInformation>& constraints,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const ConstraintInformation& constraint : constraints)
|
||||
generateConstraint(tableName, constraint, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateConstraint(const QString& tableName, const ConstraintInformation& constraint,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
const QString dropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
switch (constraint.type)
|
||||
{
|
||||
case ConstraintInformation::Type::index: {
|
||||
QString constraintName = QLatin1String("IDX_") + tableName + QLatin1Char('_') +
|
||||
constraint.affectedColumns.join(QStringLiteral("_"));
|
||||
|
||||
if (constraintName.size() > 63)
|
||||
constraintName.resize(63);
|
||||
|
||||
const QString index(QStringLiteral("CREATE INDEX %1 ON %2 (%3);"));
|
||||
|
||||
addToCreateConstraints(
|
||||
index.arg(constraintName, tableName, constraint.affectedColumns.join(QStringLiteral(", "))), ed);
|
||||
addToConstraints(constraintName, ed);
|
||||
|
||||
addToDropConstraints(dropConstraint.arg(tableName, constraintName), ed);
|
||||
|
||||
break;
|
||||
}
|
||||
case ConstraintInformation::Type::unique: {
|
||||
QString constraintName = QLatin1String("UQ_") + tableName + QLatin1Char('_') +
|
||||
constraint.affectedColumns.join(QStringLiteral("_"));
|
||||
|
||||
if (constraintName.size() > 63)
|
||||
constraintName.resize(63);
|
||||
const QString unique(QStringLiteral("ALTER TABLE %1 ADD CONSTRAINT %2 UNIQUE (%3);"));
|
||||
|
||||
addToCreateConstraints(
|
||||
unique.arg(tableName, constraintName, constraint.affectedColumns.join(QStringLiteral(", "))), ed);
|
||||
addToConstraints(constraintName, ed);
|
||||
|
||||
addToDropConstraints(dropConstraint.arg(tableName, constraintName), ed);
|
||||
|
||||
break;
|
||||
}
|
||||
case ConstraintInformation::Type::unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleEnumerations()
|
||||
{
|
||||
const QVector<EnumInformation> enumerations = m_xmlReader->getEnumerations();
|
||||
for (const EnumInformation& ei : enumerations)
|
||||
{
|
||||
if (!handleEnumeration(ei))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleEnumeration(const EnumInformation& ei)
|
||||
{
|
||||
const QStringList sql = handleEnumeration(ei, QString());
|
||||
if (m_sqlItemsGlobal.tables.contains(ei.tableName))
|
||||
m_sqlGlobal.enumerationValues += sql;
|
||||
if (m_sqlItemsExercise.tables.contains(ei.tableName))
|
||||
m_sqlExercise.enumerationValues += sql;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::handleEnumeration(const EnumInformation& ei, const QString& dbSchema) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle enumeration " << ei.enumName;
|
||||
|
||||
if (ei.tableName.isEmpty())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No table for enumeration " << ei.enumName << " - not creating inserts for this enum";
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
const QString insertEnum(QStringLiteral("INSERT INTO %1 (%2) VALUES (%3);"));
|
||||
const QString columnNames(QStringLiteral("id, name"));
|
||||
const QString tablename = dbSchema.isEmpty() ? ei.tableName : dbSchema + QLatin1Char('.') + ei.tableName;
|
||||
|
||||
QStringList enumerationValues;
|
||||
for (const EnumKeyValuePair& evp : ei.values)
|
||||
{
|
||||
const QString values(QString::number(evp.value) + QLatin1String(", '") + fixupComment(evp.key) +
|
||||
QLatin1Char('\''));
|
||||
enumerationValues += insertEnum.arg(tablename, columnNames, values);
|
||||
}
|
||||
|
||||
return enumerationValues;
|
||||
}
|
||||
|
||||
bool SqlGenerator::generateDbNotifications(const QString& tableName,
|
||||
const QVector<DbNotifcationInformation>& notifications,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const DbNotifcationInformation& notification : notifications)
|
||||
{
|
||||
if (notification.paramNames.isEmpty() || notification.paramNames.size() > 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not handle more than one parameter";
|
||||
continue;
|
||||
}
|
||||
generateDbNotification(notification, ed);
|
||||
if (!generateDbNotificationTrigger(tableName, notification, ed))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SqlGenerator::generateDbNotification(const DbNotifcationInformation& notification, ExerciseDependency ed)
|
||||
{
|
||||
const QString func(QStringLiteral("CREATE OR REPLACE FUNCTION public.%1()\n"
|
||||
"RETURNS TRIGGER AS $$\n"
|
||||
"DECLARE\n"
|
||||
" toNotify RECORD;\n"
|
||||
" toReturn RECORD;\n"
|
||||
"BEGIN\n"
|
||||
" IF (TG_OP = 'INSERT') THEN\n"
|
||||
" toNotify = NEW;\n"
|
||||
" toReturn = NEW;\n"
|
||||
" ELSIF (TG_OP = 'UPDATE') THEN\n"
|
||||
" toNotify = OLD;\n"
|
||||
" toReturn = NEW;\n"
|
||||
" ELSIF (TG_OP = 'DELETE') THEN\n"
|
||||
" toNotify = OLD;\n"
|
||||
" toReturn = OLD;\n"
|
||||
" END IF;\n"
|
||||
" \n"
|
||||
" PERFORM pg_notify('%2', CAST(toNotify.%3 AS text));\n"
|
||||
" RETURN toReturn;\n"
|
||||
"END;\n"
|
||||
"$$ LANGUAGE plpgsql;"));
|
||||
|
||||
const QString triggerFuncName(getNotificationFunctionName(notification));
|
||||
addToDbFunctions(func.arg(triggerFuncName, notification.methodName, notification.paramNames.first()), ed);
|
||||
}
|
||||
|
||||
bool SqlGenerator::generateDbNotificationTrigger(const QString& tableName, const DbNotifcationInformation& notification,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
|
||||
const QString drop(QStringLiteral("DROP TRIGGER IF EXISTS %1 ON %2;"));
|
||||
const QString func(QStringLiteral("CREATE TRIGGER %1\n") +
|
||||
QStringLiteral("%2 ON %3 FOR EACH ROW EXECUTE PROCEDURE public.%4();"));
|
||||
|
||||
for (DbNotifcationInformation::NotificationType notifyType : notification.notificationType)
|
||||
{
|
||||
QString when;
|
||||
QString triggerNameShortcut;
|
||||
switch (notifyType)
|
||||
{
|
||||
case DbNotifcationInformation::NotificationType::BeforeInsert:
|
||||
when = QStringLiteral("BEFORE INSERT");
|
||||
triggerNameShortcut = QStringLiteral("bi");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterInsert:
|
||||
when = QStringLiteral("AFTER INSERT");
|
||||
triggerNameShortcut = QStringLiteral("ai");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::BeforeUpdate:
|
||||
when = QStringLiteral("BEFORE UPDATE");
|
||||
triggerNameShortcut = QStringLiteral("bu");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterUpdate:
|
||||
when = QStringLiteral("AFTER UPDATE");
|
||||
triggerNameShortcut = QStringLiteral("au");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::BeforeDelete:
|
||||
when = QStringLiteral("BEFORE DELETE");
|
||||
triggerNameShortcut = QStringLiteral("bd");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterDelete:
|
||||
when = QStringLiteral("AFTER DELETE");
|
||||
triggerNameShortcut = QStringLiteral("ad");
|
||||
break;
|
||||
}
|
||||
const QString triggerName(QLatin1String("trg_") + triggerNameShortcut + QLatin1Char('_') +
|
||||
notification.methodName);
|
||||
const QString triggerFuncName(getNotificationFunctionName(notification));
|
||||
addToDbFunctionTrigger(drop.arg(triggerName, tableName), ed);
|
||||
addToDbFunctionTrigger(func.arg(triggerName, when, tableName, triggerFuncName), ed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SqlGenerator::getNotificationFunctionName(const DbNotifcationInformation& notification) const
|
||||
{
|
||||
return getServiceAbbr() + QLatin1Char('_') + notification.methodName;
|
||||
}
|
||||
|
||||
QString SqlGenerator::fixupComment(const QString& comment)
|
||||
{
|
||||
|
||||
QString ret = comment;
|
||||
ret = ret.remove(QLatin1Char('\''));
|
||||
ret = ret.replace(QLatin1Char(';'), QLatin1Char(','));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getDbSettings(const QString& dbSchema) const
|
||||
{
|
||||
QStringList data;
|
||||
|
||||
QString dbUser(QStringLiteral("ets_"));
|
||||
if (m_exerciseId > 0)
|
||||
dbUser += QStringLiteral("ex_00");
|
||||
else
|
||||
dbUser += m_xmlReader->getServiceAbbr().toLower();
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + dbUser +
|
||||
QLatin1Char(';'));
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT SELECT, REFERENCES ON TABLES TO ets_ro;"));
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT EXECUTE ON FUNCTIONS TO ") + dbUser + QLatin1Char(';'));
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT ALL ON SEQUENCES TO ") + dbUser + QLatin1Char(';'));
|
||||
|
||||
data.append(QLatin1String("SET SEARCH_PATH TO ") + dbSchema + QLatin1String(", PUBLIC;"));
|
||||
|
||||
QStringList deps;
|
||||
deps.reserve(m_referencedSevices.size());
|
||||
for (const QString& svc : m_referencedSevices)
|
||||
deps += QStringLiteral("-- DEPENDS: ") + svc;
|
||||
|
||||
return deps + data;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getAllSqlStmts(const QString& dbSchema, ExerciseDependency ed) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating statements for service " << getServiceAbbr() << " in exercise " << m_exerciseId
|
||||
<< ", this: " << this;
|
||||
|
||||
QStringList data;
|
||||
|
||||
const SqlStatements& sql = getStatements(ed);
|
||||
if (sql.isEmpty())
|
||||
return data;
|
||||
|
||||
if (!dbSchema.isEmpty())
|
||||
data << getDbSettings(dbSchema);
|
||||
|
||||
data.append(QStringLiteral("\n-- Drop tables/views/sequences/constraints"));
|
||||
data.append(sql.dropViews);
|
||||
data.append(sql.dropConstraints);
|
||||
data.append(sql.dropTables);
|
||||
data.append(sql.dropSequences);
|
||||
|
||||
data.append(QStringLiteral("\n-- Create tables"));
|
||||
data.append(sql.createTables);
|
||||
|
||||
data.append(QStringLiteral("\n-- Create sequence(s)"));
|
||||
data.append(sql.createSequences);
|
||||
|
||||
data.append(QStringLiteral("\n-- Create primary keys"));
|
||||
data.append(sql.createPrimaryKeys);
|
||||
|
||||
data.append(QStringLiteral("\n-- Create foreign keys"));
|
||||
data.append(sql.createForeignKeys);
|
||||
|
||||
data.append(QStringLiteral("\n-- Create views"));
|
||||
data.append(sql.createViews);
|
||||
|
||||
data.append(
|
||||
QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Inserts for static data i.e. enums\n"));
|
||||
data.append(sql.enumerationValues);
|
||||
|
||||
data.append(
|
||||
QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Notify functions for callbacks (signals in db interface)\n"));
|
||||
data.append(sql.dbFunctions);
|
||||
|
||||
data.append(
|
||||
QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Notify function trigger for callbacks (signals in db interface)\n"));
|
||||
data.append(sql.dbFunctionTrigger);
|
||||
|
||||
data.append(
|
||||
QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Indexes \n"));
|
||||
data.append(sql.createConstraints);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getEnumerationInsertValues(const QString& table, const QString& dbSchema) const
|
||||
{
|
||||
const QVector<EnumInformation> enumerations = m_xmlReader->getEnumerations();
|
||||
|
||||
for (const EnumInformation& ei : enumerations)
|
||||
{
|
||||
if (ei.tableName == table)
|
||||
return handleEnumeration(ei, dbSchema);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeSqlToFile(const QString& dbSchema, const QString& sqlFile, ExerciseDependency ed) const
|
||||
{
|
||||
return writeFile(sqlFile, getAllSqlStmts(dbSchema, ed).join(QLatin1Char('\n')));
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeSql(const QString& filePath, ExerciseDependency ed)
|
||||
{
|
||||
Q_ASSERT(ed == Global || ed == Exercise);
|
||||
|
||||
QString sqlFile = filePath + getServiceAbbr();
|
||||
if (ed == ExerciseDependency::Exercise)
|
||||
sqlFile += QLatin1Char('_') + getExerciseSchemaName(m_exerciseId);
|
||||
sqlFile += QLatin1String(".sql");
|
||||
|
||||
const SqlStatements& sql = getStatements(ed);
|
||||
if (sql.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Sql file is emtpy: " << sqlFile;
|
||||
return writeFile(sqlFile, QString());
|
||||
}
|
||||
|
||||
const QString dbSchema =
|
||||
(ed == ExerciseDependency::Exercise ? getExerciseSchemaName(m_exerciseId) : getServiceAbbr());
|
||||
|
||||
INFO_LOG(m_logger) << "Creating sql-stmt for schema (" << dbSchema << ")";
|
||||
return writeSqlToFile(dbSchema, sqlFile, ed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void addInternal(QStringList& global, QStringList& exercise, const T& stmt, ExerciseDependency ed)
|
||||
{
|
||||
switch (ed)
|
||||
{
|
||||
case ExerciseDependency::Global:
|
||||
global += stmt;
|
||||
break;
|
||||
case ExerciseDependency::Exercise:
|
||||
exercise += stmt;
|
||||
break;
|
||||
case ExerciseDependency::GlobalAndExercise:
|
||||
global += stmt;
|
||||
exercise += stmt;
|
||||
break;
|
||||
case ExerciseDependency::Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropSequences(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropSequences, m_sqlExercise.dropSequences, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropTables(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropTables, m_sqlExercise.dropTables, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropViews(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropViews, m_sqlExercise.dropViews, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateConstraints(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createConstraints, m_sqlExercise.createConstraints, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropConstraints(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropConstraints, m_sqlExercise.dropConstraints, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateFks(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createForeignKeys, m_sqlExercise.createForeignKeys, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreatePks(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createPrimaryKeys, m_sqlExercise.createPrimaryKeys, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateSequences(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createSequences, m_sqlExercise.createSequences, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateTables(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createTables, m_sqlExercise.createTables, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateTables(const QStringList& stmts, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createTables, m_sqlExercise.createTables, stmts, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateViews(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createViews, m_sqlExercise.createViews, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDbFunctions(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dbFunctions, m_sqlExercise.dbFunctions, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDbFunctionTrigger(const QString& stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dbFunctionTrigger, m_sqlExercise.dbFunctionTrigger, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToConstraints(const QString& name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.constraints, m_sqlItemsExercise.constraints, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToFks(const QString& name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.foreignKeys, m_sqlItemsExercise.foreignKeys, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToPks(const QString& name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.primaryKeys, m_sqlItemsExercise.primaryKeys, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToSequences(const QString& name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.sequences, m_sqlItemsExercise.sequences, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToTables(const QString& name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.tables, m_sqlItemsExercise.tables, name, ed);
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeFile(const QString& fn, const QString& content) const
|
||||
{
|
||||
QFile f(fn);
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << f.fileName() << "' for writing: " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
f.write(content.toUtf8());
|
||||
if (!content.isEmpty())
|
||||
f.write("\n");
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StructBuilder.h"
|
||||
#include "codegen_base_export.h"
|
||||
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct ColumnInformation;
|
||||
struct ConstraintInformation;
|
||||
struct EnumInformation;
|
||||
struct ForeignKeyInformation;
|
||||
struct TableInformation;
|
||||
class XmlReader;
|
||||
|
||||
class CODEGEN_BASE_EXPORT SqlGenerator final
|
||||
{
|
||||
public:
|
||||
struct SqlStatements
|
||||
{
|
||||
QStringList dropViews;
|
||||
QStringList dropTables;
|
||||
QStringList dropSequences;
|
||||
QStringList dropConstraints;
|
||||
|
||||
QStringList createTables;
|
||||
QStringList createSequences;
|
||||
QStringList createPrimaryKeys;
|
||||
QStringList createForeignKeys;
|
||||
QStringList createViews;
|
||||
QStringList createConstraints;
|
||||
|
||||
QStringList enumerationValues;
|
||||
QStringList dbFunctions;
|
||||
QStringList dbFunctionTrigger;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return dropViews.isEmpty() && dropTables.isEmpty() && dropSequences.isEmpty() && dropConstraints.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct SqlItems
|
||||
{
|
||||
QStringList tables;
|
||||
QStringList sequences;
|
||||
QStringList primaryKeys;
|
||||
QStringList foreignKeys;
|
||||
QStringList constraints;
|
||||
};
|
||||
|
||||
public:
|
||||
Q_DISABLE_COPY(SqlGenerator)
|
||||
|
||||
explicit SqlGenerator(XmlReader* xmlReader, StructBuilder* structBuilder);
|
||||
explicit SqlGenerator(const QString& xmlFile);
|
||||
|
||||
~SqlGenerator();
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
bool generateData(int exerciseId);
|
||||
|
||||
bool createStatementsForTable(const QString& tableName, const QString& tableNameOut);
|
||||
|
||||
SqlStatements getStatements(ExerciseDependency ed) const
|
||||
{
|
||||
return (ed == ExerciseDependency::Exercise ? m_sqlExercise : m_sqlGlobal);
|
||||
}
|
||||
|
||||
SqlItems getSqlItems(ExerciseDependency ed) const
|
||||
{
|
||||
return (ed == ExerciseDependency::Exercise ? m_sqlItemsExercise : m_sqlItemsGlobal);
|
||||
}
|
||||
|
||||
QStringList getEnumerationInsertValues(const QString& table, const QString& dbSchema) const;
|
||||
|
||||
QStringList getReferencedServices() const
|
||||
{
|
||||
return m_referencedSevices;
|
||||
}
|
||||
|
||||
QStringList getDbSettings(const QString& dbSchema) const;
|
||||
|
||||
bool writeSql(const QString& filePath, ExerciseDependency ed);
|
||||
|
||||
bool writeSqlToFile(const QString& dbSchema, const QString& sqlFile, ExerciseDependency ed) const;
|
||||
|
||||
QString getServiceAbbr() const
|
||||
{
|
||||
return m_xmlReader->getServiceAbbr();
|
||||
}
|
||||
|
||||
bool isServiceExerciseIndependent() const
|
||||
{
|
||||
return m_xmlReader->isServiceExerciseIndependent();
|
||||
}
|
||||
|
||||
bool isServiceGlobal() const
|
||||
{
|
||||
return (m_xmlReader->defaultExerciseDependency() == CodeGen::ExerciseDependency::Global ||
|
||||
m_xmlReader->defaultExerciseDependency() == CodeGen::ExerciseDependency::GlobalAndExercise);
|
||||
}
|
||||
|
||||
CodeGen::ExerciseDependency getExerciseDependency() const
|
||||
{
|
||||
return m_xmlReader->defaultExerciseDependency();
|
||||
}
|
||||
|
||||
QStringList getGroupNames() const
|
||||
{
|
||||
return m_xmlReader->getGroupNames();
|
||||
}
|
||||
|
||||
QStringList getAllSqlStmts(const QString& dbSchema, ExerciseDependency ed) const;
|
||||
|
||||
protected:
|
||||
NGL::INGLLogger& m_logger;
|
||||
|
||||
private:
|
||||
bool handleTables();
|
||||
bool handleViews();
|
||||
bool handleTable(const CompleteTableInformation& cti);
|
||||
bool handleView(const ViewInformation& vi);
|
||||
QString getTableColumnCreateStatements(const QString& tableName, const QVector<MemberInformation>& columns,
|
||||
QStringList* tableComments, ExerciseDependency ed);
|
||||
QString generateSequence(const QString& tableName, const FullQualifiedColumnInformation& ci, ExerciseDependency ed);
|
||||
void generatePrimaryKey(const QString& tableName, const FullQualifiedColumnInformation& ci, ExerciseDependency ed);
|
||||
void generateForeignKeys(const QVector<QSharedPointer<ForeignKeyInformation>>& foreignKeys, ExerciseDependency ed);
|
||||
void generateForeignKey(const QSharedPointer<ForeignKeyInformation>& foreignKey, ExerciseDependency ed);
|
||||
void generateConstraints(const QString& tableName, const QVector<ConstraintInformation>& constraints,
|
||||
ExerciseDependency ed);
|
||||
void generateConstraint(const QString& tableName, const ConstraintInformation& constraint, ExerciseDependency ed);
|
||||
bool handleEnumerations();
|
||||
bool handleEnumeration(const EnumInformation& ei);
|
||||
QStringList handleEnumeration(const EnumInformation& ei, const QString& dbSchema) const;
|
||||
bool generateDbNotifications(const QString& tableName, const QVector<DbNotifcationInformation>& notifications,
|
||||
ExerciseDependency ed);
|
||||
void generateDbNotification(const DbNotifcationInformation& notification, ExerciseDependency ed);
|
||||
bool generateDbNotificationTrigger(const QString& tableName, const DbNotifcationInformation& notification,
|
||||
ExerciseDependency ed);
|
||||
QString getNotificationFunctionName(const DbNotifcationInformation& notification) const;
|
||||
static QString fixupComment(const QString& comment);
|
||||
|
||||
private:
|
||||
XmlReader* m_xmlReader;
|
||||
StructBuilder* m_structBuilder;
|
||||
bool m_createdByXmlFile;
|
||||
|
||||
void addToDropSequences(const QString& stmt, ExerciseDependency ed);
|
||||
void addToDropTables(const QString& stmt, ExerciseDependency ed);
|
||||
void addToDropViews(const QString& stmt, ExerciseDependency ed);
|
||||
void addToDropConstraints(const QString& stmt, ExerciseDependency ed);
|
||||
|
||||
void addToCreateConstraints(const QString& stmt, ExerciseDependency ed);
|
||||
void addToCreateFks(const QString& stmt, ExerciseDependency ed);
|
||||
void addToCreatePks(const QString& stmt, ExerciseDependency ed);
|
||||
void addToCreateSequences(const QString& stmt, ExerciseDependency ed);
|
||||
void addToCreateTables(const QString& stmt, ExerciseDependency ed);
|
||||
void addToCreateTables(const QStringList& stmts, ExerciseDependency ed);
|
||||
void addToCreateViews(const QString& stmt, ExerciseDependency ed);
|
||||
|
||||
void addToDbFunctions(const QString& stmt, ExerciseDependency ed);
|
||||
void addToDbFunctionTrigger(const QString& stmt, ExerciseDependency ed);
|
||||
|
||||
void addToConstraints(const QString& name, ExerciseDependency ed);
|
||||
void addToFks(const QString& name, ExerciseDependency ed);
|
||||
void addToPks(const QString& name, ExerciseDependency ed);
|
||||
void addToSequences(const QString& name, ExerciseDependency ed);
|
||||
void addToTables(const QString& name, ExerciseDependency ed);
|
||||
|
||||
bool writeFile(const QString& fn, const QString& content) const;
|
||||
|
||||
SqlStatements m_sqlGlobal;
|
||||
SqlStatements m_sqlExercise;
|
||||
|
||||
SqlItems m_sqlItemsGlobal;
|
||||
SqlItems m_sqlItemsExercise;
|
||||
|
||||
QStringList m_referencedSevices;
|
||||
|
||||
bool m_isValid;
|
||||
int m_exerciseId;
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,385 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "XmlReader.h"
|
||||
#include "codegen_base_export.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class StructBuilder;
|
||||
|
||||
struct EaData
|
||||
{
|
||||
QString table;
|
||||
QString column;
|
||||
QString type;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return table + QLatin1Char(';') + column + QLatin1Char(';') + type;
|
||||
}
|
||||
};
|
||||
|
||||
struct FullQualifiedColumnInformation : public ColumnInformation
|
||||
{
|
||||
QString table;
|
||||
bool usedForInsert = false;
|
||||
bool usedForView = false;
|
||||
QString columnNameView;
|
||||
|
||||
QString getColumnNameView() const
|
||||
{
|
||||
return columnNameView.isEmpty() ? columnName : columnNameView;
|
||||
}
|
||||
|
||||
FullQualifiedColumnInformation() = default;
|
||||
|
||||
FullQualifiedColumnInformation(const ColumnInformation& ci, const QString& tableName)
|
||||
: ColumnInformation(ci), table(tableName)
|
||||
{
|
||||
}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return table + QLatin1Char(';') + columnName + QLatin1Char(';') + datatype +
|
||||
|
||||
QLatin1Char(';') + (isPrimaryKey ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') +
|
||||
(isForeignKey ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') +
|
||||
(usedForInsert ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') +
|
||||
(usedForView ? QLatin1String("true") : QLatin1String("false"));
|
||||
}
|
||||
};
|
||||
|
||||
class DataTypeInfo
|
||||
{
|
||||
public:
|
||||
DataTypeInfo(const QString& name, bool isPod) : m_name(name), m_isPod(isPod) {}
|
||||
|
||||
virtual ~DataTypeInfo() = default;
|
||||
|
||||
virtual QString name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
virtual QString idlType() const = 0;
|
||||
virtual QString ddsType() const = 0;
|
||||
virtual QString sqlType() const = 0;
|
||||
virtual QString cppType() const = 0;
|
||||
|
||||
virtual QString cppTypeConstRef() const
|
||||
{
|
||||
return isPod() ? cppType() : QLatin1String("const ") + cppType() + QLatin1String(" &");
|
||||
}
|
||||
|
||||
virtual bool isPod() const
|
||||
{
|
||||
return m_isPod;
|
||||
}
|
||||
|
||||
virtual bool isSequence() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isStructure() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual QVector<QSharedPointer<DataTypeInfo>> member() const
|
||||
{
|
||||
return QVector<QSharedPointer<DataTypeInfo>>();
|
||||
}
|
||||
|
||||
virtual QSharedPointer<DataTypeInfo> innerDataType() const
|
||||
{
|
||||
return QSharedPointer<DataTypeInfo>();
|
||||
}
|
||||
|
||||
static QSharedPointer<DataTypeInfo> fromIdlDataType(const QString& name, const QString& idlType,
|
||||
StructBuilder* structBuilder,
|
||||
const QString& svcName = QString());
|
||||
|
||||
protected:
|
||||
const QString m_name;
|
||||
const bool m_isPod;
|
||||
};
|
||||
|
||||
struct IdlData : public IdlColumnInformation
|
||||
{
|
||||
QSharedPointer<DataTypeInfo> dataTypeInfo;
|
||||
|
||||
IdlData() = default;
|
||||
|
||||
explicit IdlData(const IdlColumnInformation& ci) : IdlColumnInformation(ci) {}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return name + QLatin1Char(';') + type +
|
||||
|
||||
QLatin1Char(';') + (isKey ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') +
|
||||
(isOptional ? QLatin1String("true") : QLatin1String("false"));
|
||||
}
|
||||
};
|
||||
|
||||
struct CppData
|
||||
{
|
||||
QString structName;
|
||||
QString memberName;
|
||||
QString defaultValue;
|
||||
bool usedForCppStruct = false;
|
||||
bool usedForJson = false;
|
||||
bool isReadOnly = false;
|
||||
bool isOptional = false;
|
||||
QString type;
|
||||
QString ddsType;
|
||||
QString toVariantPre;
|
||||
QString toVariantPost;
|
||||
QString fromVariantPre1;
|
||||
QString fromVariantPre2;
|
||||
QString fromVariantPost;
|
||||
|
||||
QString toJsonPre;
|
||||
QString toJsonPost;
|
||||
QString fromJsonPre2;
|
||||
QString fromJsonPost;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return structName + QLatin1Char(';') + memberName + QLatin1Char(';') +
|
||||
(usedForCppStruct ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') +
|
||||
(isReadOnly ? QLatin1String("true") : QLatin1String("false")) + QLatin1Char(';') + type +
|
||||
QLatin1Char(';') + toVariantPre + QLatin1Char(';') + toVariantPost + QLatin1Char(';') + fromVariantPre1 +
|
||||
QLatin1Char(';') + fromVariantPre2 + QLatin1Char(';') + fromVariantPost;
|
||||
}
|
||||
};
|
||||
|
||||
struct MemberInformation
|
||||
{
|
||||
EaData ea;
|
||||
FullQualifiedColumnInformation db;
|
||||
CppData cpp;
|
||||
bool isDdsKey = false;
|
||||
QSharedPointer<ForeignKeyInformation> fk;
|
||||
QSharedPointer<EnumInformation> enumeration;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return ea.toString() + QLatin1Char(';') + db.toString() + QLatin1Char(';') + cpp.toString();
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return ea.column.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompleteStructInformation
|
||||
{
|
||||
QString structName;
|
||||
QString viewName;
|
||||
QSet<QSharedPointer<TableInformation>> tables;
|
||||
QSharedPointer<TableInformation> primaryTable;
|
||||
QVector<MemberInformation> member;
|
||||
QVector<DbNotifcationInformation> dbNotifications;
|
||||
bool hasStaticContent = false;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return primaryTable.isNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompleteTopicTypeInformation final : public TopicTypeInformationBase
|
||||
{
|
||||
QString serviceName;
|
||||
|
||||
QVector<IdlData> members;
|
||||
|
||||
CompleteTopicTypeInformation() = default;
|
||||
|
||||
explicit CompleteTopicTypeInformation(const TopicTypeInformationBase& s) : TopicTypeInformationBase(s) {}
|
||||
|
||||
bool hasBaseValue() const
|
||||
{
|
||||
return !baseValueType.isEmpty();
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return TopicTypeInformationBase::isValid() && !members.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompleteTableInformation : public TableInformation
|
||||
{
|
||||
QVector<MemberInformation> columns;
|
||||
|
||||
explicit CompleteTableInformation(const TableInformation& o) : TableInformation(o) {}
|
||||
|
||||
CompleteTableInformation() = default;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return columns.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
class CODEGEN_BASE_EXPORT StructBuilder
|
||||
{
|
||||
struct ColumnInformationEx : public ColumnInformation
|
||||
{
|
||||
QSharedPointer<TableInformation> table;
|
||||
|
||||
ColumnInformationEx() = default;
|
||||
|
||||
ColumnInformationEx(const ColumnInformation& o, const QSharedPointer<TableInformation>& ti)
|
||||
: ColumnInformation(o), table(ti)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
struct ServiceTypeStruct
|
||||
{
|
||||
QString service;
|
||||
QString type;
|
||||
bool bIsSequence = false;
|
||||
|
||||
bool isExternalType() const
|
||||
{
|
||||
return !service.isEmpty();
|
||||
}
|
||||
|
||||
bool isSequence() const
|
||||
{
|
||||
return bIsSequence;
|
||||
}
|
||||
|
||||
QString fqType() const
|
||||
{
|
||||
return service + QStringLiteral("::") + type;
|
||||
}
|
||||
};
|
||||
|
||||
explicit StructBuilder(XmlReader* xmlReader);
|
||||
~StructBuilder() = default;
|
||||
|
||||
bool buildStructures();
|
||||
|
||||
QVector<CompleteStructInformation> structInformations() const
|
||||
{
|
||||
return m_structInfos;
|
||||
}
|
||||
|
||||
QVector<CompleteTopicTypeInformation> topicTypeInformations() const
|
||||
{
|
||||
return m_topicTypeInfos;
|
||||
}
|
||||
|
||||
CompleteStructInformation structInformationByTableName(const QString& tableName) const;
|
||||
|
||||
EnumInformation enumInformationByType(const QString& type, bool checkExternals = true, bool verbose = true);
|
||||
|
||||
CompleteTopicTypeInformation topicTypeInformationByStructType(const QString& type, bool checkExternals = true);
|
||||
CompleteTopicTypeInformation externalTopicTypeByStructType(const ServiceTypeStruct& sts);
|
||||
|
||||
QVector<EnumInformation> enumInformations() const
|
||||
{
|
||||
return m_enumInfos;
|
||||
}
|
||||
|
||||
QMap<QString, CompleteTableInformation> getDbTables() const
|
||||
{
|
||||
return m_sqlTableInformations;
|
||||
}
|
||||
|
||||
QMap<QString, ViewInformation> getDbViews() const
|
||||
{
|
||||
return m_sqlViewInformations;
|
||||
}
|
||||
|
||||
bool needPoint3d() const
|
||||
{
|
||||
return m_needPoint3d;
|
||||
}
|
||||
|
||||
bool needPgArrayInclude() const
|
||||
{
|
||||
return m_needPgArrayInclude;
|
||||
}
|
||||
|
||||
CompleteTableInformation completeTableInformation(const CompleteTopicTypeInformation& ctti);
|
||||
CompleteTableInformation getRecordingTopicTable(const QString& structName);
|
||||
QMap<QString, CompleteTableInformation> getRecordingTopicTables();
|
||||
QVector<QSharedPointer<DataTypeInfo>> getSerializeFromToJsonTopics() const;
|
||||
bool fixupQVariantConversions(MemberInformation& mi) const;
|
||||
|
||||
Q_REQUIRED_RESULT static QString firstCharLowercase(const QString& txt);
|
||||
Q_REQUIRED_RESULT static QString camelCaseString(const QString& in, bool bFirstUppercase = false);
|
||||
Q_REQUIRED_RESULT static QString camelCaseToUnderline(const QString& in);
|
||||
|
||||
bool buildJSonStructureInformationFromIdlData(const CompleteTopicTypeInformation& ctti);
|
||||
|
||||
QMap<QString, QVector<MemberInformation>> jsonStructureInformation() const
|
||||
{
|
||||
return m_jsonStructureInformation;
|
||||
}
|
||||
|
||||
private:
|
||||
bool handleEnum(const EnumInformation& ei);
|
||||
bool handleTable(const ServiceStructInformation& ssi);
|
||||
bool handleIdlStructInfo(const TopicTypeInformation& tti, QVector<CompleteTopicTypeInformation>& destination,
|
||||
const QString& svcName = QString());
|
||||
bool loadExternalTopicType(const ServiceTypeStruct& sts);
|
||||
|
||||
bool getColumnsFromTable(const QString& tableName, QVector<ColumnInformationEx>& columns,
|
||||
QVector<QString>& tableNames) const;
|
||||
|
||||
bool fixupCustomDbDatatypes(MemberInformation& memberInfo, QVector<MemberInformation>& members);
|
||||
bool fixupDatatypePoint2d(MemberInformation& memberInfo, QVector<MemberInformation>& members);
|
||||
bool fixupDatatypePoint3d(MemberInformation& memberInfo, QVector<MemberInformation>& members);
|
||||
bool fixupDatatypeIntegerArray(MemberInformation& memberInfo);
|
||||
|
||||
QVector<MemberInformation> buildDbTableInformationFromIdlData(const CompleteTopicTypeInformation& ctti,
|
||||
const QString& tableName,
|
||||
const QString& columnNamePrefix,
|
||||
const QString& cppStructure);
|
||||
void addToSerializeFromToJsonTopics(const QSharedPointer<DataTypeInfo>& toAdd);
|
||||
CompleteTableInformation getRecordingTopicTable(const CompleteTopicTypeInformation& ctti,
|
||||
const MemberInformation& miPrimaryKey);
|
||||
MemberInformation getRecordPrimaryKey() const;
|
||||
|
||||
ServiceTypeStruct extractServiceAndTypeFromTypename(const QString& type);
|
||||
|
||||
void addToSqlTableInformation(const MemberInformation& mi);
|
||||
|
||||
private:
|
||||
QVector<CompleteStructInformation> m_structInfos;
|
||||
QVector<CompleteTopicTypeInformation> m_topicTypeInfos;
|
||||
mutable QVector<CompleteTopicTypeInformation> m_externalTopicTypes;
|
||||
QVector<EnumInformation> m_enumInfos;
|
||||
QMap<QString, CompleteTableInformation> m_sqlTableInformations;
|
||||
QMap<QString, ViewInformation> m_sqlViewInformations;
|
||||
QSet<QString> m_sqlTableInformationsAlreadyAvailable;
|
||||
QVector<QSharedPointer<DataTypeInfo>> m_serializeFromToJsonTopics;
|
||||
|
||||
QMap<QString, QVector<MemberInformation>> m_jsonStructureInformation;
|
||||
|
||||
bool m_needPoint3d;
|
||||
bool m_needPgArrayInclude;
|
||||
|
||||
XmlReader* m_xmlReader;
|
||||
NGL::INGLLogger& m_logger;
|
||||
NGL::INGLLogger& m_loggerCSV;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -1,893 +0,0 @@
|
||||
|
||||
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QDirIterator>
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
#include <utility>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
class XmlReaderException : public std::exception
|
||||
{
|
||||
public:
|
||||
explicit XmlReaderException(const QString& msg) noexcept : m_msg(msg.toUtf8()) {}
|
||||
|
||||
~XmlReaderException() = default;
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
return m_msg.data();
|
||||
}
|
||||
|
||||
private:
|
||||
const QByteArray m_msg;
|
||||
};
|
||||
|
||||
XmlReader::XmlReader() : m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.XmlReader")) {}
|
||||
|
||||
bool XmlReader::readServiceFile(const QString& svcFile, const QString& idlServiceInfoFile, const XmlReader* parent)
|
||||
{
|
||||
m_externalXmlInformations.clear();
|
||||
m_idlFiles.clear();
|
||||
m_xmlFiles.clear();
|
||||
m_usedServices.clear();
|
||||
m_fullServiceName2Abbreviation.clear();
|
||||
|
||||
m_svcNamespace.clear();
|
||||
m_svcAbbr.clear();
|
||||
m_svcProcNames.clear();
|
||||
m_customRecordReplay = false;
|
||||
m_exerciseDependency = ExerciseDependency::Exercise;
|
||||
m_dbClassTables.clear();
|
||||
m_struct2BaseClass.clear();
|
||||
m_structsToGenerate.clear();
|
||||
m_idlStructsToGenerate.clear();
|
||||
m_tables.clear();
|
||||
m_views.clear();
|
||||
m_enumerations.clear();
|
||||
m_functionTopics.clear();
|
||||
m_externalTopicTypes.clear();
|
||||
m_customFunctions.clear();
|
||||
m_prio = 0;
|
||||
m_svcDevMode = false;
|
||||
|
||||
if (parent)
|
||||
{
|
||||
m_idlFiles = parent->m_idlFiles;
|
||||
m_xmlFiles = parent->m_xmlFiles;
|
||||
m_fullServiceName2Abbreviation = parent->m_fullServiceName2Abbreviation;
|
||||
m_externalXmlInformations = parent->m_externalXmlInformations;
|
||||
}
|
||||
|
||||
loadIdlInfofile(idlServiceInfoFile);
|
||||
|
||||
QFile f(svcFile);
|
||||
if (!f.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Service file '" << svcFile << "' not found!";
|
||||
return false;
|
||||
}
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
m_errorString =
|
||||
QLatin1String("Can not open service file '") + svcFile + QLatin1String("' for reading: ") + f.errorString();
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "SvcFile: " << svcFile;
|
||||
|
||||
QDomDocument doc;
|
||||
const auto parseResult = doc.setContent(&f);
|
||||
if (!parseResult)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing service file '") + svcFile + QLatin1String("' at line ") +
|
||||
QString::number(int(parseResult.errorLine)) + QLatin1Char(':') +
|
||||
QString::number(int(parseResult.errorColumn));
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
QDomElement domRoot = doc.documentElement();
|
||||
if (!domRoot.hasAttribute(QStringLiteral("namespace")))
|
||||
{
|
||||
m_errorString = QLatin1String("Xml file '") + svcFile +
|
||||
QLatin1String("' is not a valid service file: service name/namespace is missing");
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
m_svcNamespace = getAttribute(domRoot, QStringLiteral("namespace"));
|
||||
m_svcAbbr = getAttribute(domRoot, QStringLiteral("abbreviation")).toLower();
|
||||
m_svcProcNames = getAttribute(domRoot, QStringLiteral("procNames")).split(QLatin1Char(','));
|
||||
m_customRecordReplay = getAttributeBool(domRoot, QStringLiteral("customRecordReplay"), true, false);
|
||||
|
||||
QString devModeStr = getAttribute(domRoot, QStringLiteral("devMode"), true);
|
||||
m_svcDevMode = devModeStr == QStringLiteral("1") || devModeStr == QStringLiteral("true");
|
||||
INFO_LOG(m_logger) << "devMode: " << m_svcDevMode;
|
||||
|
||||
const QString groupNamesString = getAttribute(domRoot, QStringLiteral("groups"), true);
|
||||
if (!groupNamesString.isEmpty())
|
||||
{
|
||||
m_groupNames = groupNamesString.split(QLatin1Char(','), Qt::SkipEmptyParts);
|
||||
INFO_LOG(m_logger) << "groups: " << groupNamesString;
|
||||
}
|
||||
else
|
||||
m_groupNames.clear();
|
||||
|
||||
m_exerciseDependency = string2ExerciseDependency(getAttribute(domRoot, QStringLiteral("exerciseDependency"), true));
|
||||
|
||||
if (m_groupNames.contains(QStringLiteral("Core")) || m_groupNames.contains(QStringLiteral("Master")))
|
||||
{
|
||||
if (m_exerciseDependency != ExerciseDependency::Global &&
|
||||
m_exerciseDependency != ExerciseDependency::GlobalAndExercise)
|
||||
{
|
||||
WARNING_LOG(m_logger)
|
||||
<< "Service " << getServiceNamespace()
|
||||
<< " is not marked as exercise independent but should be started in group Core/Master";
|
||||
}
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "exerciseDependency: " << (int)m_exerciseDependency;
|
||||
if (domRoot.hasAttribute(QStringLiteral("prio")))
|
||||
{
|
||||
m_prio = getAttribute(domRoot, QStringLiteral("prio"), 0).toInt();
|
||||
}
|
||||
try
|
||||
{
|
||||
parseDBSserviceStructs(domRoot.firstChildElement(QStringLiteral("dbServiceStructs")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbServiceStructs: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseDBTables(domRoot.firstChildElement(QStringLiteral("tables")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbtables: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseDBViews(domRoot.firstChildElement(QStringLiteral("views")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbviews: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseEnumerations(domRoot.firstChildElement(QStringLiteral("enumerations")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing enumerations: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseCustomDtcFunctions(domRoot.firstChildElement(QStringLiteral("customDtcFunctions")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing custom dtc functions: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseTopicTypes(domRoot.firstChildElement(QStringLiteral("topicTypes")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing idl strucs: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseFunctionTopics(domRoot.firstChildElement(QStringLiteral("functionTopics")));
|
||||
}
|
||||
catch (const XmlReaderException& ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing function topics: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString XmlReader::getAttribute(const QDomElement& element, const QString& attributeName, bool bOptional)
|
||||
{
|
||||
if (!element.hasAttribute(attributeName))
|
||||
{
|
||||
if (bOptional)
|
||||
return QString();
|
||||
throw XmlReaderException(QLatin1String("Element ") + element.tagName() + QLatin1String(" has no attribute ") +
|
||||
attributeName);
|
||||
}
|
||||
return element.attribute(attributeName);
|
||||
}
|
||||
|
||||
bool XmlReader::getAttributeBool(const QDomElement& element, const QString& attributeName, bool bOptional,
|
||||
bool defaultValue)
|
||||
{
|
||||
QString str = getAttribute(element, attributeName, bOptional);
|
||||
if (str.isEmpty())
|
||||
return defaultValue;
|
||||
bool bOk;
|
||||
bool ret = (str.toInt(&bOk) != 0);
|
||||
if (!bOk)
|
||||
throw XmlReaderException(QLatin1String("Can not parse boolean value: ") + str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int XmlReader::getAttributeInt(const QDomElement& element, const QString& attributeName, bool bOptional,
|
||||
int defaultValue)
|
||||
{
|
||||
QString str = getAttribute(element, attributeName, bOptional);
|
||||
if (str.isEmpty())
|
||||
return defaultValue;
|
||||
bool bOk;
|
||||
int ret = str.toInt(&bOk);
|
||||
if (!bOk)
|
||||
{
|
||||
|
||||
ret = str.toUInt(&bOk, 16);
|
||||
if (!bOk)
|
||||
throw XmlReaderException(QLatin1String("Can not parse int value: ") + str);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void XmlReader::parseDBSserviceStructs(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domDbStruct = rootElement.firstChildElement(QStringLiteral("serviceStruct"));
|
||||
while (!domDbStruct.isNull())
|
||||
{
|
||||
ServiceStructInformation ssi;
|
||||
ssi.name = getAttribute(domDbStruct, QStringLiteral("name"));
|
||||
ssi.primaryTable = getAttribute(domDbStruct, QStringLiteral("table"));
|
||||
ssi.hasStaticContent = getAttributeBool(domDbStruct, QStringLiteral("static"), true, false);
|
||||
|
||||
QDomElement domFunc = domDbStruct.firstChildElement(QStringLiteral("function"));
|
||||
while (!domFunc.isNull())
|
||||
{
|
||||
m_customFunctions += parseCustomFunction(domFunc, CustomServiceFunctionInformation::Type::Db);
|
||||
domFunc = domFunc.nextSiblingElement(domFunc.tagName());
|
||||
}
|
||||
|
||||
QDomElement domNotify = domDbStruct.firstChildElement(QStringLiteral("notification"));
|
||||
while (!domNotify.isNull())
|
||||
{
|
||||
ssi.dbNotifications.append(parseDbNotification(domNotify));
|
||||
domNotify = domNotify.nextSiblingElement(domNotify.tagName());
|
||||
}
|
||||
|
||||
m_structsToGenerate.push_back(ssi);
|
||||
|
||||
domDbStruct = domDbStruct.nextSiblingElement(domDbStruct.tagName());
|
||||
}
|
||||
std::sort(m_structsToGenerate.begin(), m_structsToGenerate.end());
|
||||
|
||||
domDbStruct = rootElement.firstChildElement(QStringLiteral("table"));
|
||||
while (!domDbStruct.isNull())
|
||||
{
|
||||
const QString table = getAttribute(domDbStruct, QStringLiteral("name"));
|
||||
const QString parentTable = getAttribute(domDbStruct, QStringLiteral("base"), true);
|
||||
m_struct2BaseClass[table] = parentTable;
|
||||
|
||||
domDbStruct = domDbStruct.nextSiblingElement(domDbStruct.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_structsToGenerate.size() << " database service struct(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseDBTables(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domDbTable = rootElement.firstChildElement(QStringLiteral("table"));
|
||||
while (!domDbTable.isNull())
|
||||
{
|
||||
QSharedPointer<TableInformation> ti(new TableInformation);
|
||||
ti->name = getAttribute(domDbTable, QStringLiteral("name"));
|
||||
ti->structName = QLatin1String("t_") + ti->name;
|
||||
ti->comment = getAttribute(domDbTable, QStringLiteral("comment"), true);
|
||||
ti->exerciseDependency =
|
||||
string2ExerciseDependency(getAttribute(domDbTable, QStringLiteral("exerciseDependency"), true));
|
||||
|
||||
QDomElement domColumn = domDbTable.firstChildElement(QStringLiteral("column"));
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
ti->plainColumns.append(parseTableColumn(domColumn, ti->name));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
|
||||
QDomElement domForeignKey = domDbTable.firstChildElement(QStringLiteral("foreignKey"));
|
||||
while (!domForeignKey.isNull())
|
||||
{
|
||||
ti->foreignKeys.append(parseForeignKey(domForeignKey));
|
||||
domForeignKey = domForeignKey.nextSiblingElement(domForeignKey.tagName());
|
||||
}
|
||||
QDomElement domConstraint = domDbTable.firstChildElement(QStringLiteral("constraint"));
|
||||
while (!domConstraint.isNull())
|
||||
{
|
||||
ti->constraints.append(parseConstraint(domConstraint));
|
||||
domConstraint = domConstraint.nextSiblingElement(domConstraint.tagName());
|
||||
}
|
||||
|
||||
m_tables.insert(ti->name, ti);
|
||||
|
||||
domDbTable = domDbTable.nextSiblingElement(domDbTable.tagName());
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_tables.size() << " database table(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseDBViews(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domDbView = rootElement.firstChildElement(QStringLiteral("view"));
|
||||
while (!domDbView.isNull())
|
||||
{
|
||||
QSharedPointer<ViewInformation> vi(new ViewInformation);
|
||||
vi->name = getAttribute(domDbView, QStringLiteral("name"));
|
||||
vi->structName = QLatin1String("v_") + vi->name;
|
||||
vi->baseSchema = m_svcAbbr;
|
||||
vi->baseTable = getAttribute(domDbView, QStringLiteral("base"));
|
||||
vi->comment = getAttribute(domDbView, QStringLiteral("comment"), true);
|
||||
vi->filter = getAttribute(domDbView, QStringLiteral("filter"));
|
||||
vi->exerciseDependency =
|
||||
string2ExerciseDependency(getAttribute(domDbView, QStringLiteral("exerciseDependency"), true));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Base table = " << vi->baseTable;
|
||||
|
||||
m_views.insert(vi->name, vi);
|
||||
|
||||
domDbView = domDbView.nextSiblingElement(domDbView.tagName());
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_views.size() << " database view(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseEnumerations(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domEnum = rootElement.firstChildElement(QStringLiteral("enumeration"));
|
||||
while (!domEnum.isNull())
|
||||
{
|
||||
EnumInformation enumeration;
|
||||
enumeration.serviceName = getServiceNamespace();
|
||||
enumeration.enumName = getAttribute(domEnum, QStringLiteral("name"));
|
||||
enumeration.tableName = getAttribute(domEnum, QStringLiteral("table"), true);
|
||||
|
||||
QDomElement enumVal = domEnum.firstChildElement(QStringLiteral("attribute"));
|
||||
while (!enumVal.isNull())
|
||||
{
|
||||
EnumKeyValuePair evp;
|
||||
evp.key = getAttribute(enumVal, QStringLiteral("key"));
|
||||
evp.value = getAttributeInt(enumVal, QStringLiteral("value"));
|
||||
enumeration.values.append(evp);
|
||||
|
||||
enumVal = enumVal.nextSiblingElement(enumVal.tagName());
|
||||
}
|
||||
|
||||
m_enumerations.push_back(enumeration);
|
||||
|
||||
domEnum = domEnum.nextSiblingElement(domEnum.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_enumerations.size() << " enumeration(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseCustomDtcFunctions(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domElement = rootElement.firstChildElement(QStringLiteral("customDtcFunction"));
|
||||
while (!domElement.isNull())
|
||||
{
|
||||
|
||||
QDomElement domFunc = domElement.firstChildElement(QStringLiteral("function"));
|
||||
while (!domFunc.isNull())
|
||||
{
|
||||
m_customFunctions += parseCustomFunction(domFunc, CustomServiceFunctionInformation::Type::Dtc);
|
||||
domFunc = domFunc.nextSiblingElement(domFunc.tagName());
|
||||
}
|
||||
domElement = domElement.nextSiblingElement(domElement.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_enumerations.size() << " customDtcFunction(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseTopicTypes(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domIdlStruct = rootElement.firstChildElement(QStringLiteral("topicType"));
|
||||
while (!domIdlStruct.isNull())
|
||||
{
|
||||
TopicTypeInformation isi;
|
||||
isi.name = getAttribute(domIdlStruct, QStringLiteral("name"));
|
||||
isi.baseValueType = getAttribute(domIdlStruct, QStringLiteral("baseValueType"), true);
|
||||
|
||||
const QStringList sl = isi.baseValueType.split(QStringLiteral("::"));
|
||||
if (sl.size() == 2)
|
||||
loadExternalTopicType(sl.at(0), sl.at(1));
|
||||
|
||||
const QString tmp = getAttribute(domIdlStruct, QStringLiteral("extensibility"), true);
|
||||
|
||||
#ifdef RTI_HEADER_AVAILABLE
|
||||
if (tmp.compare(QLatin1String("FINAL"), Qt::CaseInsensitive) == 0)
|
||||
isi.extensibility = dds::core::xtypes::ExtensibilityKind::FINAL;
|
||||
if (tmp.compare(QLatin1String("MUTABLE"), Qt::CaseInsensitive) == 0)
|
||||
isi.extensibility = dds::core::xtypes::ExtensibilityKind::MUTABLE;
|
||||
if (tmp.compare(QLatin1String("EXTENSIBLE"), Qt::CaseInsensitive) == 0)
|
||||
isi.extensibility = dds::core::xtypes::ExtensibilityKind::EXTENSIBLE;
|
||||
#else
|
||||
// RTI not available - skip extensibility parsing
|
||||
Q_UNUSED(tmp)
|
||||
#endif
|
||||
|
||||
isi.comment = getAttribute(domIdlStruct, QStringLiteral("comment"), true);
|
||||
isi.isDataObject = getAttributeBool(domIdlStruct, QStringLiteral("isDataObject"), true, false);
|
||||
isi.dtsAutogen = getAttributeBool(domIdlStruct, QStringLiteral("autogenDTS"), true, true);
|
||||
isi.dtcAutogen = getAttributeBool(domIdlStruct, QStringLiteral("autogenDTC"), true, true);
|
||||
isi.recordTopic = getAttributeBool(domIdlStruct, QStringLiteral("recordTopic"), true, false);
|
||||
isi.routeToClient = getAttributeBool(domIdlStruct, QStringLiteral("routeToClient"), true, true);
|
||||
isi.routeToServer = getAttributeBool(domIdlStruct, QStringLiteral("routeToServer"), true, false);
|
||||
isi.routeInReplay = getAttributeBool(domIdlStruct, QStringLiteral("routeInReplay"), true, false);
|
||||
isi.autosubscribe = getAttributeBool(domIdlStruct, QStringLiteral("autosubscribe"), true, true);
|
||||
|
||||
QDomElement domColumn = domIdlStruct.firstChildElement(QStringLiteral("column"));
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
isi.columns.append(parseIdlStructColumn(domColumn));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
|
||||
m_idlStructsToGenerate.insert(isi.name, isi);
|
||||
|
||||
domIdlStruct = domIdlStruct.nextSiblingElement(domIdlStruct.tagName());
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_idlStructsToGenerate.size() << " idl struct(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseFunctionTopics(const QDomElement& rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domFunctionTopic = rootElement.firstChildElement(QStringLiteral("functionTopic"));
|
||||
while (!domFunctionTopic.isNull())
|
||||
{
|
||||
FunctionTopic ft;
|
||||
ft.name = getAttribute(domFunctionTopic, QStringLiteral("name"));
|
||||
ft.requestTopicType = getAttribute(domFunctionTopic, QStringLiteral("requestTopicType"));
|
||||
ft.replyTopicType = getAttribute(domFunctionTopic, QStringLiteral("replyTopicType"));
|
||||
ft.requestTopicName = getAttribute(domFunctionTopic, QStringLiteral("requestTopicName"));
|
||||
ft.replyTopicName = getAttribute(domFunctionTopic, QStringLiteral("replyTopicName"));
|
||||
ft.routeInReplay = getAttributeBool(domFunctionTopic, QStringLiteral("routeInReplay"), true, false);
|
||||
|
||||
m_functionTopics.append(ft);
|
||||
|
||||
domFunctionTopic = domFunctionTopic.nextSiblingElement(domFunctionTopic.tagName());
|
||||
}
|
||||
|
||||
for (const FunctionTopic& ft : std::as_const(m_functionTopics))
|
||||
{
|
||||
const QStringList sl1 = ft.requestTopicType.split(QStringLiteral("::"));
|
||||
if (sl1.size() == 2)
|
||||
loadExternalTopicType(sl1.at(0), sl1.at(1));
|
||||
const QStringList sl2 = ft.replyTopicType.split(QStringLiteral("::"));
|
||||
if (sl2.size() == 2)
|
||||
loadExternalTopicType(sl2.at(0), sl2.at(1));
|
||||
}
|
||||
}
|
||||
|
||||
ColumnInformation XmlReader::parseTableColumn(const QDomElement& column, const QString& tableName) const
|
||||
{
|
||||
ColumnInformation ci;
|
||||
|
||||
ci.columnName = getAttribute(column, QStringLiteral("name"));
|
||||
ci.datatype = getAttribute(column, QStringLiteral("datatype"));
|
||||
ci.defaultValue = getAttribute(column, QStringLiteral("default"), true);
|
||||
ci.comment = getAttribute(column, QStringLiteral("comment"), true);
|
||||
ci.isPrimaryKey = getAttributeBool(column, QStringLiteral("isPrimaryKey"), true, false);
|
||||
ci.isForeignKey = getAttributeBool(column, QStringLiteral("isForeignKey"), true, false);
|
||||
ci.isOptional = getAttributeBool(column, QStringLiteral("isOptional"), true, false);
|
||||
const QDomElement seq = column.firstChildElement(QStringLiteral("sequence"));
|
||||
if (!seq.isNull())
|
||||
{
|
||||
ci.sequenceStart = getAttributeInt(seq, QStringLiteral("start"), true, -1);
|
||||
ci.sequenceIncrement = getAttributeInt(seq, QStringLiteral("increment"), true, -1);
|
||||
ci.hasSequence = ci.sequenceStart >= 0 && ci.sequenceIncrement > 0;
|
||||
}
|
||||
|
||||
if (ci.columnName.toLower() != ci.columnName)
|
||||
WARNING_LOG(m_logger) << "Column " << ci.columnName << " in Table " << tableName
|
||||
<< " has has upper-case chars which is not allowed!";
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
IdlColumnInformation XmlReader::parseIdlStructColumn(const QDomElement& column) const
|
||||
{
|
||||
IdlColumnInformation ci;
|
||||
|
||||
ci.name = getAttribute(column, QStringLiteral("name"));
|
||||
ci.type = getAttribute(column, QStringLiteral("idlType"));
|
||||
ci.comment = getAttribute(column, QStringLiteral("comment"), true);
|
||||
ci.isKey = getAttributeBool(column, QStringLiteral("isKey"), true, false);
|
||||
ci.isOptional = getAttributeBool(column, QStringLiteral("isOptional"), true, false);
|
||||
ci.isTranslatable = getAttributeBool(column, QStringLiteral("isTranslatable"), true, false);
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> XmlReader::parseForeignKey(const QDomElement& foreignKey) const
|
||||
{
|
||||
QSharedPointer<ForeignKeyInformation> fk(new ForeignKeyInformation);
|
||||
|
||||
fk->name = getAttribute(foreignKey, QStringLiteral("name"));
|
||||
|
||||
const QString deleteAction = getAttribute(foreignKey, QStringLiteral("referential_integrity"), true);
|
||||
if (deleteAction == QLatin1String("DeleteNoAction"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::NoAction;
|
||||
else if (deleteAction == QLatin1String("DeleteCascade"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Cascade;
|
||||
else if (deleteAction == QLatin1String("DeleteRestrict"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Restrict;
|
||||
else if (deleteAction == QLatin1String("DeleteSetNull"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::SetNull;
|
||||
else if (deleteAction == QLatin1String("DeleteSetDefault"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::SetDefault;
|
||||
else
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Cascade;
|
||||
|
||||
fk->source = parseForeignKeyEndpoint(fk->name, foreignKey.firstChildElement(QStringLiteral("source")));
|
||||
fk->destination = parseForeignKeyEndpoint(fk->name, foreignKey.firstChildElement(QStringLiteral("destination")));
|
||||
|
||||
return fk;
|
||||
}
|
||||
|
||||
ForeignKeyInformation::Endpoint XmlReader::parseForeignKeyEndpoint(const QString& foreignKeyName,
|
||||
const QDomElement& endpoint) const
|
||||
{
|
||||
if (endpoint.isNull())
|
||||
throw XmlReaderException(QLatin1String("No endpoint for foreign key ") + foreignKeyName);
|
||||
|
||||
ForeignKeyInformation::Endpoint fkEndpoint;
|
||||
|
||||
fkEndpoint.service = getAttribute(endpoint, QStringLiteral("service"), true);
|
||||
fkEndpoint.serviceAbbr = getAttribute(endpoint, QStringLiteral("serviceAbbr"), true);
|
||||
fkEndpoint.schema = getAttribute(endpoint, QStringLiteral("schema"), true);
|
||||
fkEndpoint.tableName = getAttribute(endpoint, QStringLiteral("table"));
|
||||
fkEndpoint.columnName = getAttribute(endpoint, QStringLiteral("column"));
|
||||
|
||||
return fkEndpoint;
|
||||
}
|
||||
|
||||
ConstraintInformation XmlReader::parseConstraint(const QDomElement& constraint) const
|
||||
{
|
||||
ConstraintInformation ret;
|
||||
|
||||
ret.name = getAttribute(constraint, QStringLiteral("name"), true);
|
||||
const QString type = getAttribute(constraint, QStringLiteral("type")).toLower();
|
||||
if (type == QLatin1String("unique"))
|
||||
ret.type = ConstraintInformation::Type::unique;
|
||||
else if (type == QLatin1String("index"))
|
||||
ret.type = ConstraintInformation::Type::index;
|
||||
|
||||
QDomElement domColumn = constraint.firstChildElement(QStringLiteral("column"));
|
||||
if (domColumn.isNull())
|
||||
throw XmlReaderException(QLatin1String("No column for constraint") + ret.name);
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
ret.affectedColumns += getAttribute(domColumn, QStringLiteral("name"));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CustomServiceFunctionInformation XmlReader::parseCustomFunction(const QDomElement& customFunc,
|
||||
CustomServiceFunctionInformation::Type funcType) const
|
||||
{
|
||||
CustomServiceFunctionInformation ret;
|
||||
ret.methodName = getAttribute(customFunc, QStringLiteral("name"));
|
||||
ret.returnValue = getAttribute(customFunc, QStringLiteral("returns"), true);
|
||||
ret.isConst = getAttributeBool(customFunc, QStringLiteral("isConst"), true, false);
|
||||
if (ret.returnValue.isEmpty())
|
||||
ret.returnValue = QStringLiteral("bool");
|
||||
QMap<int, QPair<QString, QString>> paramHelper;
|
||||
QDomElement domParam = customFunc.firstChildElement(QStringLiteral("parameter"));
|
||||
while (!domParam.isNull())
|
||||
{
|
||||
int pos = getAttributeInt(domParam, QStringLiteral("pos"));
|
||||
if (paramHelper.contains(pos))
|
||||
throw XmlReaderException(QLatin1String("Doubled position entry for custom function ") + ret.methodName);
|
||||
QString paramName = getAttribute(domParam, QStringLiteral("name"));
|
||||
const QString paramType = getAttribute(domParam, QStringLiteral("type"));
|
||||
const QString paramDefault = getAttribute(domParam, QStringLiteral("default"), true);
|
||||
if (!paramDefault.isEmpty())
|
||||
paramName.append(QLatin1String(" = ") + paramDefault);
|
||||
paramHelper[pos] = qMakePair(paramName, paramType);
|
||||
domParam = domParam.nextSiblingElement(domParam.tagName());
|
||||
}
|
||||
ret.paramNames.reserve(paramHelper.size());
|
||||
ret.paramTypes.reserve(paramHelper.size());
|
||||
ret.type = funcType;
|
||||
QStringList signature;
|
||||
for (auto it = paramHelper.constBegin(); it != paramHelper.constEnd(); ++it)
|
||||
{
|
||||
ret.paramNames += it.value().first;
|
||||
ret.paramTypes += it.value().second;
|
||||
QString tmp = it.value().second;
|
||||
if (!it.value().second.endsWith(QLatin1Char('&')))
|
||||
tmp += QLatin1Char(' ');
|
||||
tmp += it.value().first;
|
||||
signature += tmp;
|
||||
}
|
||||
ret.signature += signature.join(QStringLiteral(", "));
|
||||
return ret;
|
||||
}
|
||||
|
||||
DbNotifcationInformation XmlReader::parseDbNotification(const QDomElement& customFunc) const
|
||||
{
|
||||
DbNotifcationInformation ret(parseCustomFunction(customFunc, CustomServiceFunctionInformation::Type::DbNotify));
|
||||
|
||||
const QString attribute(getAttribute(customFunc, QStringLiteral("notificationTypes")).toLower());
|
||||
const QStringList nfTypes = attribute.split(QLatin1Char(','));
|
||||
static const QMap<QString, DbNotifcationInformation::NotificationType> s_nfTypeMap = {
|
||||
{QLatin1String("beforeinsert"), DbNotifcationInformation::NotificationType::BeforeInsert},
|
||||
{QLatin1String("afterinsert"), DbNotifcationInformation::NotificationType::AfterInsert},
|
||||
{QLatin1String("beforeupdate"), DbNotifcationInformation::NotificationType::BeforeUpdate},
|
||||
{QLatin1String("afterupdate"), DbNotifcationInformation::NotificationType::AfterUpdate},
|
||||
{QLatin1String("beforedelete"), DbNotifcationInformation::NotificationType::BeforeDelete},
|
||||
{QLatin1String("afterdelete"), DbNotifcationInformation::NotificationType::AfterDelete}};
|
||||
for (const QString& nfType : nfTypes)
|
||||
{
|
||||
const auto it = s_nfTypeMap.find(nfType);
|
||||
if (it == s_nfTypeMap.end())
|
||||
throw XmlReaderException(QStringLiteral("Can not find notification type %2 in type map for function %1")
|
||||
.arg(ret.methodName, nfType));
|
||||
ret.notificationType += it.value();
|
||||
}
|
||||
if (ret.notificationType.isEmpty())
|
||||
throw XmlReaderException(
|
||||
QStringLiteral("Notification function '%1' without a valid notification type").arg(ret.methodName));
|
||||
if (ret.paramTypes.size() != 1)
|
||||
throw XmlReaderException(
|
||||
QStringLiteral("Notification function '%1' must have exactly one parameter").arg(ret.methodName));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TopicTypeInformation XmlReader::loadExternalTopicType(const QString& externalServiceName, const QString& topicTypeName)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "externalServiceName: " << externalServiceName << ", topicTypeName: " << topicTypeName;
|
||||
|
||||
if (!loadExternalService(externalServiceName))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find service " << externalServiceName << " referenced by external topic "
|
||||
<< topicTypeName;
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
auto extXmlReader = m_externalXmlInformations.value(externalServiceName);
|
||||
if (!extXmlReader)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find service xml file for service '" << externalServiceName << "'";
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
|
||||
TopicTypeInformation tti = extXmlReader->getIdlStructInformation().value(topicTypeName);
|
||||
if (tti.isValid())
|
||||
{
|
||||
tti.name = externalServiceName + QLatin1String("::") + tti.name;
|
||||
m_externalTopicTypes += tti;
|
||||
m_usedServices[externalServiceName] = true;
|
||||
return tti;
|
||||
}
|
||||
WARNING_LOG(m_logger) << "Could not find topic " << topicTypeName << " in external service definition for service "
|
||||
<< externalServiceName;
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
|
||||
EnumInformation XmlReader::getExternalEnumeration(const QString& externalServiceName, const QString& enumName,
|
||||
bool verbose)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "externalServiceName: " << externalServiceName << ", topicTypeName: " << enumName;
|
||||
|
||||
if (!loadExternalService(externalServiceName))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find service '" << externalServiceName << "'"
|
||||
<< " referenced by external enumeration " << enumName;
|
||||
return EnumInformation();
|
||||
}
|
||||
auto extXmlReader = m_externalXmlInformations.value(externalServiceName);
|
||||
if (!extXmlReader)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find service xml file for service '" << externalServiceName << "'";
|
||||
return EnumInformation();
|
||||
}
|
||||
|
||||
const QVector<EnumInformation> enums = extXmlReader->getEnumerations();
|
||||
for (const EnumInformation& ei : enums)
|
||||
{
|
||||
if (ei.enumName == enumName)
|
||||
{
|
||||
m_usedServices[externalServiceName] = true;
|
||||
return ei;
|
||||
}
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find enumeration " << enumName << " in external service definition for '"
|
||||
<< externalServiceName << "'";
|
||||
}
|
||||
return EnumInformation();
|
||||
}
|
||||
|
||||
bool XmlReader::loadExternalService(const QString& serviceName)
|
||||
{
|
||||
if (serviceName == getServiceNamespace())
|
||||
return false;
|
||||
if (m_externalXmlInformations.contains(serviceName))
|
||||
return true;
|
||||
|
||||
QString fileName = xmlFileForService(serviceName);
|
||||
if (fileName.isEmpty())
|
||||
{
|
||||
const QVector<QString> dirs = NGL::directories(NGL::FileType::ConfigFile);
|
||||
for (const QString& dirname : dirs)
|
||||
{
|
||||
QDirIterator dirIt(dirname + QStringLiteral("/xml"), QDir::Files | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
while (dirIt.hasNext())
|
||||
{
|
||||
dirIt.next();
|
||||
if (!dirIt.fileName().endsWith(QLatin1String(".xml")))
|
||||
continue;
|
||||
|
||||
fileName = dirIt.filePath();
|
||||
const QString svcNamespace = serviceNamespaceFromFile(fileName);
|
||||
if (svcNamespace == serviceName)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "xml file for " << serviceName << ": " << fileName;
|
||||
auto extXmlReader = QSharedPointer<XmlReader>(new XmlReader);
|
||||
if (!extXmlReader->readServiceFile(fileName, QString(), this))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error reading service file " << fileName << " for service " << serviceName;
|
||||
return false;
|
||||
}
|
||||
m_externalXmlInformations[serviceName] = extXmlReader;
|
||||
if (!m_usedServices.contains(serviceName))
|
||||
m_usedServices[serviceName] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void XmlReader::loadIdlInfofile(const QString& idlServiceInfoFile)
|
||||
{
|
||||
if (idlServiceInfoFile.isEmpty())
|
||||
return;
|
||||
QFile f(idlServiceInfoFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not read idl service info file " << idlServiceInfoFile;
|
||||
return;
|
||||
}
|
||||
const QList<QByteArray> files = f.readAll().split('\n');
|
||||
for (const QByteArray& filePath : files)
|
||||
{
|
||||
|
||||
if (filePath.startsWith("--") || filePath.trimmed().isEmpty())
|
||||
continue;
|
||||
const QString fileName = QString::fromLocal8Bit(filePath.trimmed());
|
||||
const QStringList parts = fileName.split(QStringLiteral("/"));
|
||||
getServiceNameInfoFromFilePath(parts);
|
||||
const auto fn = parts.last().trimmed();
|
||||
if (fn.endsWith(QLatin1String(".xml")))
|
||||
{
|
||||
const auto svcAbbreveation = fn.split(QLatin1Char('.')).at(0).split(QLatin1Char('_')).at(0);
|
||||
m_xmlFiles[svcAbbreveation] = fileName;
|
||||
DEBUG_LOG(m_logger) << "xml: " << svcAbbreveation << " = " << fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto svcAbbreveation = fn.split(QLatin1Char('.')).at(0).toLower();
|
||||
if (svcAbbreveation.endsWith(QLatin1String("_enums")))
|
||||
continue;
|
||||
m_idlFiles[svcAbbreveation] = fileName;
|
||||
DEBUG_LOG(m_logger) << "idl: " << svcAbbreveation << " = " << fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString XmlReader::getIdlFileForService(const QMap<QString, QString>& data, const QString& serviceName) const
|
||||
{
|
||||
const QString serviceAbbr = serviceNameAbbreviation(serviceName);
|
||||
return data.value(serviceAbbr);
|
||||
}
|
||||
|
||||
QString XmlReader::serviceNameAbbreviation(const QString& serviceName) const
|
||||
{
|
||||
return m_fullServiceName2Abbreviation.value(serviceName);
|
||||
}
|
||||
|
||||
void XmlReader::getServiceNameInfoFromFilePath(const QStringList& parts)
|
||||
{
|
||||
if (parts.size() < 2)
|
||||
return;
|
||||
|
||||
const QString abbreviation = parts.last().split(QLatin1Char('.')).first().split(QLatin1Char('_')).first();
|
||||
const QString serviceName = parts.at(parts.size() - 2);
|
||||
DEBUG_LOG(m_logger) << "serviceName: " << serviceName << " = " << abbreviation;
|
||||
m_fullServiceName2Abbreviation[serviceName] = abbreviation;
|
||||
}
|
||||
|
||||
ExerciseDependency XmlReader::string2ExerciseDependency(const QString& str)
|
||||
{
|
||||
if (str.isEmpty())
|
||||
return ExerciseDependency::Undefined;
|
||||
const QStringList sd = str.toLower().split(QLatin1Char(','));
|
||||
int ret = ExerciseDependency::Undefined;
|
||||
for (const QString& s : sd)
|
||||
{
|
||||
if (s == QLatin1String("global"))
|
||||
ret |= ExerciseDependency::Global;
|
||||
else if (s == QLatin1String("exercise"))
|
||||
ret |= ExerciseDependency::Exercise;
|
||||
else if (s == QLatin1String("globalandexercise"))
|
||||
ret |= ExerciseDependency::GlobalAndExercise;
|
||||
}
|
||||
return static_cast<ExerciseDependency>(ret);
|
||||
}
|
||||
|
||||
QString XmlReader::serviceNamespaceFromFile(const QString& fn)
|
||||
{
|
||||
QFile f(fn);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return QString();
|
||||
QXmlStreamReader sr(&f);
|
||||
while (!sr.atEnd())
|
||||
{
|
||||
sr.readNext();
|
||||
if (sr.isStartElement() && sr.name() == QLatin1String("service"))
|
||||
return (sr.attributes().value(QLatin1String("namespace"))).toString();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
@@ -1,459 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QStringView>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#ifdef RTI_DDS_AVAILABLE
|
||||
// Only include RTI headers if they are actually available
|
||||
#if __has_include(<dds/core/xtypes/EnumType.hpp>)
|
||||
#include <dds/core/xtypes/EnumType.hpp>
|
||||
#define RTI_HEADER_AVAILABLE 1
|
||||
#else
|
||||
#undef RTI_DDS_AVAILABLE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "codegen_base_export.h"
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
class QDomElement;
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
|
||||
enum ExerciseDependency { Undefined = 0, Global = 0x1, Exercise = 0x2, GlobalAndExercise = 0x3 };
|
||||
|
||||
struct EnumKeyValuePair
|
||||
{
|
||||
QString key;
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
struct EnumInformation
|
||||
{
|
||||
QString enumName;
|
||||
QString tableName;
|
||||
QString serviceName;
|
||||
QVector<EnumKeyValuePair> values;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return !enumName.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct ColumnInformation
|
||||
{
|
||||
QString columnName;
|
||||
QString datatype;
|
||||
QString comment;
|
||||
QString defaultValue;
|
||||
bool isPrimaryKey = false;
|
||||
bool isAssignmentForPrimaryTablePk = false;
|
||||
bool isForeignKey = false;
|
||||
bool generateSelectRemove = false;
|
||||
bool canBeNull = true;
|
||||
bool hasSequence = false;
|
||||
bool isOptional = false;
|
||||
int sequenceStart = 0;
|
||||
int sequenceIncrement = 0;
|
||||
};
|
||||
|
||||
struct IdlColumnInformation
|
||||
{
|
||||
QString name;
|
||||
QString type;
|
||||
QString comment;
|
||||
bool isKey = false;
|
||||
bool isOptional = false;
|
||||
bool isTranslatable = false;
|
||||
};
|
||||
|
||||
struct ForeignKeyInformation
|
||||
{
|
||||
struct Endpoint
|
||||
{
|
||||
QString service;
|
||||
QString serviceAbbr;
|
||||
QString schema;
|
||||
QString tableName;
|
||||
QString columnName;
|
||||
};
|
||||
|
||||
QString name;
|
||||
Endpoint source;
|
||||
Endpoint destination;
|
||||
enum class OnDeleteAction {
|
||||
NoAction,
|
||||
Cascade,
|
||||
Restrict,
|
||||
SetNull,
|
||||
SetDefault
|
||||
} deleteAction = OnDeleteAction::Cascade;
|
||||
};
|
||||
|
||||
struct CustomServiceFunctionInformation
|
||||
{
|
||||
QString methodName;
|
||||
QString returnValue;
|
||||
QString signature;
|
||||
bool isConst = false;
|
||||
QVector<QString> paramTypes;
|
||||
QVector<QString> paramNames;
|
||||
enum class Type { Db, DbNotify, Dtc } type = Type::Db;
|
||||
};
|
||||
|
||||
struct DbNotifcationInformation : public CustomServiceFunctionInformation
|
||||
{
|
||||
DbNotifcationInformation() = default;
|
||||
|
||||
explicit DbNotifcationInformation(const CustomServiceFunctionInformation& d) : CustomServiceFunctionInformation(d)
|
||||
{
|
||||
}
|
||||
enum class NotificationType { BeforeInsert, AfterInsert, BeforeUpdate, AfterUpdate, BeforeDelete, AfterDelete };
|
||||
QVector<NotificationType> notificationType;
|
||||
};
|
||||
|
||||
struct ConstraintInformation
|
||||
{
|
||||
enum struct Type { unknown = 0x00, unique = 0x01, index = 0x02 } type = Type::unknown;
|
||||
QString name;
|
||||
QStringList affectedColumns;
|
||||
};
|
||||
|
||||
struct TableInformation
|
||||
{
|
||||
QString name;
|
||||
QString structName;
|
||||
QString comment;
|
||||
QVector<ColumnInformation> plainColumns;
|
||||
QVector<QSharedPointer<ForeignKeyInformation>> foreignKeys;
|
||||
QVector<ConstraintInformation> constraints;
|
||||
ExerciseDependency exerciseDependency = ExerciseDependency::Undefined;
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> fkInformationForColumn(const QString& tableName,
|
||||
const QString& columnName) const
|
||||
{
|
||||
for (const QSharedPointer<ForeignKeyInformation>& fki : foreignKeys)
|
||||
{
|
||||
if (fki->source.columnName == columnName && fki->source.tableName == tableName)
|
||||
return fki;
|
||||
}
|
||||
return QSharedPointer<ForeignKeyInformation>();
|
||||
}
|
||||
};
|
||||
|
||||
struct ViewInformation
|
||||
{
|
||||
QString name;
|
||||
QString comment;
|
||||
QString structName;
|
||||
QString baseTable;
|
||||
QString baseSchema;
|
||||
QString filter;
|
||||
ExerciseDependency exerciseDependency = ExerciseDependency::Undefined;
|
||||
};
|
||||
|
||||
struct ServiceStructInformation
|
||||
{
|
||||
QString name;
|
||||
QString primaryTable;
|
||||
bool hasStaticContent = false;
|
||||
|
||||
bool operator<(const ServiceStructInformation& o) const
|
||||
{
|
||||
if (hasStaticContent != o.hasStaticContent)
|
||||
return hasStaticContent < o.hasStaticContent;
|
||||
if (name != o.name)
|
||||
return name < o.name;
|
||||
return primaryTable < o.primaryTable;
|
||||
}
|
||||
|
||||
QVector<DbNotifcationInformation> dbNotifications;
|
||||
};
|
||||
|
||||
struct TopicTypeInformationBase
|
||||
{
|
||||
TopicTypeInformationBase() = default;
|
||||
virtual ~TopicTypeInformationBase() = default;
|
||||
|
||||
QString name;
|
||||
QString baseValueType;
|
||||
QString comment;
|
||||
bool isDataObject = false;
|
||||
bool dtsAutogen = true;
|
||||
bool dtcAutogen = true;
|
||||
bool recordTopic = false;
|
||||
bool routeToClient = true;
|
||||
bool routeToServer = false;
|
||||
bool routeInReplay = true;
|
||||
bool autosubscribe = true;
|
||||
|
||||
#ifdef RTI_DDS_AVAILABLE
|
||||
dds::core::xtypes::ExtensibilityKind extensibility = dds::core::xtypes::ExtensibilityKind::EXTENSIBLE;
|
||||
#else
|
||||
int extensibility = 0; // Placeholder when RTI DDS is not available
|
||||
#endif
|
||||
|
||||
virtual bool isValid() const
|
||||
{
|
||||
return !name.isEmpty();
|
||||
}
|
||||
|
||||
bool operator<(const TopicTypeInformationBase& o) const
|
||||
{
|
||||
if (name != o.name)
|
||||
return name < o.name;
|
||||
return baseValueType < o.baseValueType;
|
||||
}
|
||||
};
|
||||
|
||||
struct TopicTypeInformation : public TopicTypeInformationBase
|
||||
{
|
||||
QVector<IdlColumnInformation> columns;
|
||||
};
|
||||
|
||||
struct FunctionTopic
|
||||
{
|
||||
QString name;
|
||||
QString requestTopicType;
|
||||
QString replyTopicType;
|
||||
QString requestTopicName;
|
||||
QString replyTopicName;
|
||||
bool routeInReplay = false;
|
||||
};
|
||||
|
||||
class CODEGEN_BASE_EXPORT XmlReader final
|
||||
{
|
||||
public:
|
||||
XmlReader();
|
||||
|
||||
bool readServiceFile(const QString& svcFile, const QString& idlServiceInfoFile = QString(),
|
||||
const XmlReader* parent = nullptr);
|
||||
|
||||
QString errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
QString getServiceNamespace() const
|
||||
{
|
||||
return m_svcNamespace;
|
||||
}
|
||||
|
||||
QString getServiceAbbr() const
|
||||
{
|
||||
return m_svcAbbr;
|
||||
}
|
||||
|
||||
QStringList getGroupNames() const
|
||||
{
|
||||
return m_groupNames;
|
||||
}
|
||||
|
||||
int getPrio() const
|
||||
{
|
||||
return m_prio;
|
||||
}
|
||||
|
||||
QStringList getProcNames() const
|
||||
{
|
||||
return m_svcProcNames;
|
||||
}
|
||||
|
||||
bool hasCustomRecordReplayPlugin() const
|
||||
{
|
||||
return m_customRecordReplay;
|
||||
}
|
||||
|
||||
bool getDevMode() const
|
||||
{
|
||||
return m_svcDevMode;
|
||||
}
|
||||
|
||||
bool isServiceExerciseIndependent() const
|
||||
{
|
||||
return m_exerciseDependency == ExerciseDependency::Global;
|
||||
}
|
||||
|
||||
ExerciseDependency defaultExerciseDependency() const
|
||||
{
|
||||
return m_exerciseDependency;
|
||||
}
|
||||
|
||||
QMap<QString, QVector<QString>> getDbClass2TableMapping() const
|
||||
{
|
||||
return m_dbClassTables;
|
||||
}
|
||||
|
||||
QMap<QString, QString> getStruct2BaseClassRelations() const
|
||||
{
|
||||
return m_struct2BaseClass;
|
||||
}
|
||||
|
||||
QVector<ServiceStructInformation> getStructToGenerate() const
|
||||
{
|
||||
return m_structsToGenerate;
|
||||
}
|
||||
|
||||
QMap<QString, TopicTypeInformation> getIdlStructInformation() const
|
||||
{
|
||||
return m_idlStructsToGenerate;
|
||||
}
|
||||
|
||||
QVector<TopicTypeInformation> getIdlStructToGenerate() const
|
||||
{
|
||||
QVector<TopicTypeInformation> res;
|
||||
res.reserve(m_idlStructsToGenerate.size());
|
||||
auto it = m_idlStructsToGenerate.constBegin();
|
||||
while (it != m_idlStructsToGenerate.constEnd())
|
||||
{
|
||||
res.append(it.value());
|
||||
++it;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QMap<QString, QSharedPointer<TableInformation>> getTables() const
|
||||
{
|
||||
return m_tables;
|
||||
}
|
||||
|
||||
QMap<QString, QSharedPointer<ViewInformation>> getViews() const
|
||||
{
|
||||
return m_views;
|
||||
}
|
||||
|
||||
QSharedPointer<TableInformation> getTable(const QString& table) const
|
||||
{
|
||||
return m_tables.value(table);
|
||||
}
|
||||
|
||||
QVector<EnumInformation> getEnumerations() const
|
||||
{
|
||||
return m_enumerations;
|
||||
}
|
||||
|
||||
QVector<IdlColumnInformation> getIdlColumns(const QString& structName) const
|
||||
{
|
||||
return m_idlStructsToGenerate.value(structName).columns;
|
||||
}
|
||||
|
||||
QVector<FunctionTopic> getFunctionTopics() const
|
||||
{
|
||||
return m_functionTopics;
|
||||
}
|
||||
|
||||
QVector<TopicTypeInformation> getExternalTopicTypes() const
|
||||
{
|
||||
return m_externalTopicTypes;
|
||||
}
|
||||
|
||||
QString idlFileForService(const QString& serviceName) const
|
||||
{
|
||||
return getIdlFileForService(m_idlFiles, serviceName);
|
||||
}
|
||||
|
||||
QString xmlFileForService(const QString& serviceName) const
|
||||
{
|
||||
return getIdlFileForService(m_xmlFiles, serviceName);
|
||||
}
|
||||
|
||||
QMap<QString, bool> usedServices() const
|
||||
{
|
||||
return m_usedServices;
|
||||
}
|
||||
|
||||
QVector<CustomServiceFunctionInformation> getCustomFunctions() const
|
||||
{
|
||||
return m_customFunctions;
|
||||
}
|
||||
|
||||
TopicTypeInformation loadExternalTopicType(const QString& externalServiceName, const QString& topicTypeName);
|
||||
EnumInformation getExternalEnumeration(const QString& externalServiceName, const QString& enumName, bool verbose);
|
||||
|
||||
static ExerciseDependency string2ExerciseDependency(const QString& str);
|
||||
|
||||
XmlReader(const XmlReader&) = delete;
|
||||
XmlReader& operator=(const XmlReader&) = delete;
|
||||
|
||||
private:
|
||||
NGL::INGLLogger& m_logger;
|
||||
void parseDBSserviceStructs(const QDomElement& rootElement);
|
||||
void parseDBTables(const QDomElement& rootElement);
|
||||
void parseDBViews(const QDomElement& rootElement);
|
||||
void parseEnumerations(const QDomElement& rootElement);
|
||||
void parseTopicTypes(const QDomElement& rootElement);
|
||||
void parseFunctionTopics(const QDomElement& rootElement);
|
||||
void parseCustomDtcFunctions(const QDomElement& rootElement);
|
||||
|
||||
static QString getAttribute(const QDomElement& element, const QString& attributeName, bool bOptional = false);
|
||||
static bool getAttributeBool(const QDomElement& element, const QString& attributeName, bool bOptional,
|
||||
bool defaultValue);
|
||||
static int getAttributeInt(const QDomElement& element, const QString& attributeName, bool bOptional = false,
|
||||
int defaultValue = 0);
|
||||
|
||||
ColumnInformation parseTableColumn(const QDomElement& column, const QString& tableName) const;
|
||||
IdlColumnInformation parseIdlStructColumn(const QDomElement& column) const;
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> parseForeignKey(const QDomElement& foreignKey) const;
|
||||
ForeignKeyInformation::Endpoint parseForeignKeyEndpoint(const QString& foreignKeyName,
|
||||
const QDomElement& endpoint) const;
|
||||
ConstraintInformation parseConstraint(const QDomElement& constraint) const;
|
||||
CustomServiceFunctionInformation parseCustomFunction(const QDomElement& customFunc,
|
||||
CustomServiceFunctionInformation::Type funcType) const;
|
||||
DbNotifcationInformation parseDbNotification(const QDomElement& customFunc) const;
|
||||
bool loadExternalService(const QString& serviceName);
|
||||
void loadIdlInfofile(const QString& idlServiceInfoFile);
|
||||
QString getIdlFileForService(const QMap<QString, QString>& data, const QString& serviceName) const;
|
||||
QString serviceNameAbbreviation(const QString& serviceName) const;
|
||||
void getServiceNameInfoFromFilePath(const QStringList& parts);
|
||||
static QString serviceNamespaceFromFile(const QString& fn);
|
||||
|
||||
QString m_svcNamespace;
|
||||
|
||||
QString m_svcAbbr;
|
||||
|
||||
QStringList m_svcProcNames;
|
||||
|
||||
bool m_customRecordReplay;
|
||||
|
||||
ExerciseDependency m_exerciseDependency{ExerciseDependency::Exercise};
|
||||
|
||||
QMap<QString, QVector<QString>> m_dbClassTables;
|
||||
|
||||
QMap<QString, QString> m_struct2BaseClass;
|
||||
QVector<ServiceStructInformation> m_structsToGenerate;
|
||||
|
||||
QMap<QString, TopicTypeInformation> m_idlStructsToGenerate;
|
||||
|
||||
QVector<FunctionTopic> m_functionTopics;
|
||||
QVector<TopicTypeInformation> m_externalTopicTypes;
|
||||
QVector<CustomServiceFunctionInformation> m_customFunctions;
|
||||
|
||||
QMap<QString, QSharedPointer<TableInformation>> m_tables;
|
||||
QMap<QString, QSharedPointer<ViewInformation>> m_views;
|
||||
QVector<EnumInformation> m_enumerations;
|
||||
QString m_errorString;
|
||||
|
||||
QMap<QString, QSharedPointer<XmlReader>> m_externalXmlInformations;
|
||||
QMap<QString, QString> m_idlFiles;
|
||||
QMap<QString, QString> m_xmlFiles;
|
||||
QMap<QString, bool> m_usedServices;
|
||||
QMap<QString, QString> m_fullServiceName2Abbreviation;
|
||||
|
||||
QStringList m_groupNames;
|
||||
int m_prio;
|
||||
bool m_svcDevMode{false};
|
||||
};
|
||||
} // namespace CodeGen
|
||||
BIN
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef CODEGEN_BASE_EXPORT
|
||||
#ifdef BUILD_STATIC_LIBRARIES
|
||||
#define CODEGEN_BASE_EXPORT
|
||||
#else
|
||||
#if defined(MAKE_CODEGEN_BASE_LIB)
|
||||
#define CODEGEN_BASE_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define CODEGEN_BASE_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,101 +0,0 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, stdout
|
||||
|
||||
# CodeGeneration Tool
|
||||
###########################################################
|
||||
|
||||
log4j.logger.CodeGen.main=WARN
|
||||
log4j.logger.CodeGen=INFO
|
||||
log4j.logger.CodeGen.Settings=INFO
|
||||
log4j.logger.CodeGen.FtsImpl=INFO
|
||||
log4j.logger.CodeGen.FtcImpl=INFO
|
||||
|
||||
# DTS/DTC, FTS/FTC
|
||||
log4j.logger.Generic.DTS=INFO
|
||||
log4j.logger.Generic.DTC=INFO
|
||||
log4j.logger.Generic.FTS.Function=INFO
|
||||
log4j.logger.Generic.FTC=INFO
|
||||
log4j.logger.DTC.Subscriber=INFO
|
||||
log4j.logger.DTC.SubscriberListener=INFO
|
||||
log4j.logger.FTS=INFO
|
||||
log4j.logger.FTC=WARN
|
||||
|
||||
# connext (request/reply feature)
|
||||
log4j.logger.connext.requester=WARN
|
||||
log4j.logger.connext.replier=WARN
|
||||
|
||||
# CodeGen
|
||||
log4j.logger.CodeGen.XmlReader=WARN
|
||||
|
||||
# SqlGenerator
|
||||
log4j.logger.CodeGen.SqlGenerator=WARN
|
||||
log4j.logger.CodeGen.StructBuilder=INFO
|
||||
|
||||
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_codeGen.log
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
@@ -1,498 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
|
||||
class FtData(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.namespace = ''
|
||||
self.requestTopicType = ''
|
||||
self.requestTopicName = ''
|
||||
self.replyTopicType = ''
|
||||
self.replyTopicName = ''
|
||||
|
||||
def fqnVar( self, name ):
|
||||
if name.find('::') < 0:
|
||||
name = self.namespace + '::' + name
|
||||
return name
|
||||
def stripNamespace( self, str ):
|
||||
return str.split('::')[-1]
|
||||
|
||||
def getReplyTopicName( self ):
|
||||
return 'LTS_' + self.stripNamespace( self.replyTopicName ).replace( '::', '_' )
|
||||
|
||||
def getReplyTopicNameType( self, withNamespace = True ):
|
||||
var = self.replyTopicName
|
||||
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
|
||||
|
||||
def getRequestTopicName( self ):
|
||||
return 'LTS_' + self.stripNamespace( self.requestTopicName ).replace( '::', '_' )
|
||||
|
||||
def getRequestTopicNameType( self, withNamespace = True ):
|
||||
var = self.requestTopicName
|
||||
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
|
||||
|
||||
def getReplyTopicType( self ):
|
||||
return self.fqnVar( self.replyTopicType )
|
||||
def getRequestTopicType( self ):
|
||||
return self.fqnVar( self.requestTopicType )
|
||||
|
||||
def needReplyTopicTypedef( self ):
|
||||
return self.getReplyTopicNameType() != self.getReplyTopicType()
|
||||
def needRequestTopicTypedef( self ):
|
||||
return self.getRequestTopicNameType() != self.getRequestTopicType()
|
||||
|
||||
class GuiPluginRights(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.offset = 0
|
||||
self.groups = []
|
||||
class GuiPluginRightsGroup(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.desc = ''
|
||||
self.values = []
|
||||
|
||||
class FileParser(object):
|
||||
def __init__( self ):
|
||||
self.filename = ''
|
||||
self.service_abbr = ''
|
||||
self.module_name = ''
|
||||
self.struct_names = []
|
||||
self.ft_enums = []
|
||||
self.ft_replies = []
|
||||
self.ft_data = dict()
|
||||
self.op_right_offset = 0
|
||||
self.op_rights = []
|
||||
|
||||
def build(self, path):
|
||||
""" Parse the whole stuff ... """
|
||||
self.filename = path
|
||||
self.read_file_xml(self.filename)
|
||||
|
||||
def read_file_xml(self, filename):
|
||||
""" Read the given xml service file"""
|
||||
|
||||
"""print >> sys.stdout, 'Reading xml file %s' % filename"""
|
||||
xmlTree = ET.parse(filename)
|
||||
root = xmlTree.getroot()
|
||||
self.module_name = root.attrib['namespace']
|
||||
self.service_abbr = root.attrib['abbreviation'].lower()
|
||||
|
||||
for child in root.iter('topicType'):
|
||||
struct_name = child.attrib['name']
|
||||
if 'isDataObject' in child.attrib and int(child.attrib['isDataObject']) != 0:
|
||||
self.struct_names.append(struct_name)
|
||||
for child in root.iter('functionTopic'):
|
||||
ft_name = child.attrib['name']
|
||||
self.ft_enums.append(ft_name)
|
||||
|
||||
ft_data = FtData()
|
||||
ft_data.name = ft_name
|
||||
ft_data.namespace = self.module_name
|
||||
ft_data.requestTopicType = child.attrib['requestTopicType']
|
||||
ft_data.requestTopicName = child.attrib['requestTopicName']
|
||||
ft_data.replyTopicType = child.attrib['replyTopicType']
|
||||
ft_data.replyTopicName = child.attrib['replyTopicName']
|
||||
self.ft_data[ft_name] = ft_data
|
||||
|
||||
for child in root.iter('operatorRights'):
|
||||
self.op_right_offset = int(child.attrib['offset'])
|
||||
for pluginChild in child.iter('guiPlugin'):
|
||||
r = GuiPluginRights()
|
||||
r.name = pluginChild.attrib['name']
|
||||
r.offset = int(pluginChild.attrib['offset'])
|
||||
r.groups = [];
|
||||
for groups in pluginChild.iter('operatorRightGroup'):
|
||||
g = GuiPluginRightsGroup();
|
||||
g.name = groups.attrib['name']
|
||||
g.desc = groups.attrib['description'] if 'description' in groups.attrib else ''
|
||||
|
||||
for right in groups.iter('operatorRight'):
|
||||
desc = right.attrib['description'] if 'description' in right.attrib else ''
|
||||
g.values.append((right.attrib['right'], int(right.attrib['value']), desc))
|
||||
r.groups.append(g)
|
||||
self.op_rights.append(r)
|
||||
|
||||
|
||||
def outputHeader( outfile, parser, description, with_dds_include = True, with_pragma = True ):
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write('* %s definitions\n' % description)
|
||||
outfile.write('*/\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('// warning: this file is generated with command\n')
|
||||
outfile.write('// %s\n' % ( " ".join(sys.argv) ))
|
||||
outfile.write('// at %s\n' % time.strftime( '%c' ))
|
||||
outfile.write('// it will be overwritten by next run - do not modify!\n')
|
||||
outfile.write('\n')
|
||||
if with_pragma:
|
||||
outfile.write('#pragma once\n')
|
||||
outfile.write('\n')
|
||||
if with_dds_include:
|
||||
outfile.write('#include "%s.hpp"\n' % ( parser.service_abbr ))
|
||||
|
||||
class DtsGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'DTS' )
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write(' * Type definitions \n')
|
||||
outfile.write(' * => DataWriterObjects (DWOs)\n')
|
||||
outfile.write(' * => DataTopicServers (DTSs)\n')
|
||||
outfile.write(' */\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DDSGeneric\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataWriter;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' template<typename T> class GenericDts;\n')
|
||||
outfile.write(' template<typename T> class GenericDtsImpl;\n')
|
||||
outfile.write('\n')
|
||||
|
||||
for struct_name in sorted(parser.struct_names):
|
||||
|
||||
topic_name = "%s::%s" % ( parser.module_name, struct_name )
|
||||
dwo_name = "Dwo%s" % ( struct_name )
|
||||
outfile.write(' // Topic %s\n' % ( topic_name ))
|
||||
outfile.write(' // Interface\n')
|
||||
outfile.write(' using %s = GenericDts<%s>;\n' % ( struct_name, topic_name ))
|
||||
outfile.write(' // Interface impl\n')
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataWriter<%s>;\n' % ( dwo_name, topic_name ))
|
||||
outfile.write(' using %sImpl = GenericDtsImpl<%s>;\n' % ( struct_name, dwo_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace DTS\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class DtcGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write('* %s definitions\n' % 'DTC')
|
||||
outfile.write('*/\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('// warning: this file is generated with command\n')
|
||||
outfile.write('// %s\n' % ( " ".join(sys.argv) ))
|
||||
outfile.write('// at %s\n' % time.strftime( '%c' ))
|
||||
outfile.write('// it will be overwritten by next run - do not modify!\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('#pragma once\n')
|
||||
outfile.write('\n')
|
||||
# Include Qt headers FIRST to avoid namespace conflicts with DDS
|
||||
outfile.write('#include <QtCore/QObject>\n')
|
||||
outfile.write('#include <QtCore/QTimer>\n')
|
||||
outfile.write('\n')
|
||||
# Include DDS headers BEFORE project headers to avoid namespace conflicts
|
||||
outfile.write('#include <DDS/Generic/generic_data_reader.h>\n')
|
||||
outfile.write('#include <DDS/DTC/generic_dtc.h>\n')
|
||||
outfile.write('#include <DDS/DTC/generic_dtc_impl.h>\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('#include "%s.hpp"\n' % ( parser.service_abbr ))
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write(' * Type definitions \n')
|
||||
outfile.write(' * => DataTopicClients (DTCs)\n')
|
||||
outfile.write(' */\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DDSGeneric\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataReader;\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataReaderContentFilter;\n')
|
||||
outfile.write('class DynamicDataReader;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' template<typename T> class GenericDtc;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcImpl;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcSampleInfo;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcImplSampleInfo;\n')
|
||||
outfile.write('\n')
|
||||
|
||||
for struct_name in sorted(parser.struct_names):
|
||||
|
||||
topic_name = "%s::%s" % ( parser.module_name, struct_name )
|
||||
dro_name = "Dro%s" % ( struct_name )
|
||||
dro_name_cf = "Dro%sCF" % ( struct_name )
|
||||
|
||||
outfile.write(' // Topic %s\n' % ( topic_name ))
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataReader<%s>;\n' % ( dro_name, topic_name ))
|
||||
outfile.write(' using %s = GenericDtc<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' using %sImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name ))
|
||||
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataReaderContentFilter<%s>;\n' % ( dro_name_cf, topic_name ))
|
||||
outfile.write(' using %sCF = GenericDtc<%s>;\n' % ( struct_name, dro_name_cf ))
|
||||
outfile.write(' using %sCFImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name_cf ))
|
||||
|
||||
outfile.write(' namespace SampleInfo {\n')
|
||||
outfile.write(' using %s = GenericDtcSampleInfo<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' using %sImpl = GenericDtcImplSampleInfo<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' }\n')
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace DTC\n')
|
||||
outfile.write('\n')
|
||||
|
||||
def printFtTopicTypeNames( outfile, ft_data ):
|
||||
outfile.write(' template<> struct TopicNames<%s>' % ft_data.name)
|
||||
outfile.write(' {\n')
|
||||
outfile.write(' static constexpr const char *functionTopicName() { return "%s"; }\n' % ft_data.name)
|
||||
outfile.write(' static constexpr const char *replyTopicName() { return "%s"; }\n' % ft_data.getReplyTopicName())
|
||||
outfile.write(' static constexpr const char *replyTopicTypeName() { return "%s"; }\n' % ft_data.getReplyTopicNameType( True ))
|
||||
outfile.write(' static constexpr const char *requestTopicName() { return "%s"; }\n' % ft_data.getRequestTopicName())
|
||||
outfile.write(' static constexpr const char *requestTopicTypeName() { return "%s"; }\n' % ft_data.getRequestTopicNameType( True ))
|
||||
outfile.write(' };\n')
|
||||
|
||||
def printFtTypedefs( outfile, ft_data ):
|
||||
if ft_data.needRequestTopicTypedef():
|
||||
outfile.write(' using %s = %s;\n' % ( ft_data.getRequestTopicNameType( False ), ft_data.getRequestTopicType() ))
|
||||
if ft_data.needReplyTopicTypedef():
|
||||
outfile.write(' using %s = %s;\n' % ( ft_data.getReplyTopicNameType( False ), ft_data.getReplyTopicType() ))
|
||||
|
||||
class FtsGenerator(object):
|
||||
def generate( self, outfile, parser):
|
||||
outputHeader( outfile, parser, 'FTS' )
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtsImpl;\n')
|
||||
outfile.write('template<typename GENERIC_FTS> struct TopicNames;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
printFtTypedefs( outfile, parser.ft_data[ft_name] )
|
||||
|
||||
outfile.write('} // namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for GenericFtsImpl\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
ft_data = parser.ft_data[ft_name]
|
||||
|
||||
dummy = '%sTemplateHelperDummy' % ft_data.name;
|
||||
outfile.write(' class %s;\n' % dummy)
|
||||
outfile.write(' using %s = GenericFtsImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
|
||||
printFtTopicTypeNames( outfile, ft_data )
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace FTS\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class FtcGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'FTC' )
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtcImpl;\n')
|
||||
outfile.write('template<typename GENERIC_FTC> struct TopicNames;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
printFtTypedefs( outfile, parser.ft_data[ft_name] )
|
||||
|
||||
outfile.write('} // namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for GenericFtcImpl\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
ft_data = parser.ft_data[ft_name]
|
||||
|
||||
dummy = '%sTemplateHelperDummy' % ft_data.name;
|
||||
outfile.write(' class %s;\n' % dummy)
|
||||
outfile.write(' using %s = GenericFtcImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
|
||||
printFtTopicTypeNames( outfile, ft_data )
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace FTC\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class OperatorRights(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'Operator Rights', False )
|
||||
outfile.write('namespace %s \n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
outfile.write(' static const int Offset = %s; \n' % parser.op_right_offset)
|
||||
outfile.write('}\n\n')
|
||||
|
||||
outfile.write('namespace OperatorRights\n')
|
||||
outfile.write('{\n')
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
for r in parser.op_rights:
|
||||
outfile.write('enum %s\n' % r.name)
|
||||
outfile.write('{\n')
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
for k,v,d in group.values:
|
||||
v += groupOffset
|
||||
outfile.write(' %s = %s,\n' % (k, hex(v)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('enum Groups_%s\n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
pattern = re.compile(r'\W+')
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
for group in r.groups:
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
name = pattern.sub('', group.name)
|
||||
outfile.write(' Group%s = %s,\n' % (name, hex(groupOffset)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('enum Plugins_%s\n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
name = pattern.sub('', r.name)
|
||||
outfile.write(' Plugin%s = %s,\n' % (name, hex(offsetPlugin)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('} // namespace OperatorRights\n')
|
||||
|
||||
class OperatorRightsCpp(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'Operator Rights (source)', False, False )
|
||||
outfile.write('#include "%s_operator_rights.h"\n' % parser.service_abbr)
|
||||
outfile.write('#include <QCoreApplication>\n\n\n')
|
||||
if len(parser.op_rights) == 0:
|
||||
return
|
||||
outfile.write('\nvoid doNothing()\n{\n const char * txt[] {\n')
|
||||
|
||||
disamb = 'OperatorRights'
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
if group.name != '':
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.name))
|
||||
if group.desc != '':
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.desc))
|
||||
for aclName, aclId, aclDescr in group.values:
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, aclDescr))
|
||||
outfile.write(' };\n Q_UNUSED(txt);\n}\n')
|
||||
|
||||
class OperatorRightsSql(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outfile.write('BEGIN;\n')
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
if globalOffset > 0:
|
||||
outfile.write('--- Offset: %s = %s\n' % (globalOffset, hex(globalOffset)))
|
||||
|
||||
groupId = globalOffset;
|
||||
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
|
||||
outfile.write('\n--- %s - %s = %s\n' % (group.name, hex(groupOffset), groupOffset))
|
||||
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 4, false);\n"
|
||||
outfile.write(str % (groupOffset, group.name, group.desc))
|
||||
for aclName, aclId, aclDescr in group.values:
|
||||
aclId += groupOffset
|
||||
outfile.write('--- Base: %s, %s - %s = %s\n' % (groupOffset, aclName, aclId, hex(aclId)))
|
||||
str = "INSERT INTO opm.opm_access_control_level (id, name, description) VALUES (%s, '%s', '%s');\n";
|
||||
outfile.write(str % (aclId, aclName, aclDescr));
|
||||
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 1, true);\n";
|
||||
outfile.write(str % (groupId, aclName, aclDescr));
|
||||
str = "INSERT INTO opm.opm_acl_allow (group_id, acl_id) VALUES (%s, %s); -- group_id is: %s = %s\n";
|
||||
outfile.write(str % (groupId, aclId, groupId, hex(groupId)));
|
||||
str = "INSERT INTO opm.opm_group_group (group_id, is_member_of_group_id) VALUES (%s, %s); -- %s\n"
|
||||
outfile.write(str % (groupOffset, groupId, group.name))
|
||||
groupId = groupId + 1
|
||||
outfile.write('\n')
|
||||
outfile.write('END;\n')
|
||||
|
||||
def generate( parser, generator, out_filename ):
|
||||
try:
|
||||
outfile = open(out_filename, 'w')
|
||||
except:
|
||||
print("Could not open %s for writing" % out_filename, file=sys.stderr)
|
||||
sys.exit(4)
|
||||
generator.generate(outfile, parser)
|
||||
outfile.close()
|
||||
|
||||
def usage( error ):
|
||||
print(error, file=sys.stderr)
|
||||
print("Usage: %s DTS|DTC|FTS|FTC|SQL <service_file.xml> <outfile> " % sys.argv[0], file=sys.stderr)
|
||||
print(" %s ALL <service_file.xml> <outdir> " % sys.argv[0], file=sys.stderr)
|
||||
print("i.e.: %s DTS exm_service.xml DtsTypeDefinitions.h" % sys.argv[0], file=sys.stderr)
|
||||
print("call: '%s'" % " ".join(sys.argv), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
usage("Invalid argument count")
|
||||
|
||||
option_str = sys.argv[1]
|
||||
xml_filename = sys.argv[2]
|
||||
|
||||
parser = FileParser()
|
||||
parser.build(xml_filename)
|
||||
|
||||
if option_str == "DTS":
|
||||
generate(parser, DtsGenerator(), sys.argv[3])
|
||||
elif option_str == "DTC":
|
||||
generate(parser, DtcGenerator(), sys.argv[3])
|
||||
elif option_str == "FTS":
|
||||
generate(parser, FtsGenerator(), sys.argv[3])
|
||||
elif option_str == "FTC":
|
||||
generate(parser, FtcGenerator(), sys.argv[3])
|
||||
elif option_str == "SQL":
|
||||
out_dir = sys.argv[3]
|
||||
generate(parser, OperatorRightsSql(), os.path.join(out_dir, parser.service_abbr + '_operator_rights.sql'))
|
||||
elif option_str == "ALL":
|
||||
out_dir = sys.argv[3]
|
||||
fn = out_dir + '/' + parser.service_abbr + '_%s_types.h'
|
||||
generate(parser, DtsGenerator(), fn % 'dts')
|
||||
generate(parser, DtcGenerator(), fn % 'dtc')
|
||||
generate(parser, FtsGenerator(), fn % 'fts')
|
||||
generate(parser, FtcGenerator(), fn % 'ftc')
|
||||
generate(parser, OperatorRights(), out_dir + '/' + parser.service_abbr + '_operator_rights.h')
|
||||
generate(parser, OperatorRightsCpp(), out_dir + '/' + parser.service_abbr + '_operator_rights.cpp')
|
||||
else:
|
||||
usage("invalid option '%s'" % option_str)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,167 +0,0 @@
|
||||
|
||||
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
#include "DaoGeneratorGrantlee.h"
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
#include "SqlGenerator.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QtCore/QDir>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser() : LtsCommandLineParser(LtsCommandLineParser::LtsCommandLineParser::None)
|
||||
{
|
||||
addOption({QStringList() << QStringLiteral("s") << QStringLiteral("servicefile"),
|
||||
QStringLiteral("full path to the service xml-file"), QStringLiteral("service xml-file"),
|
||||
QStringLiteral("/home")});
|
||||
|
||||
addOption({QStringList() << QStringLiteral("a") << QStringLiteral("action"),
|
||||
QStringLiteral("the action to execute"), QStringLiteral("DATABASE|DATABASE_SERVER|IDL|DDS_TOPICS"),
|
||||
QStringLiteral("/0")});
|
||||
|
||||
addOption({QStringList() << QStringLiteral("o") << QStringLiteral("outdir"),
|
||||
QStringLiteral("the output directory where to put the generated files"),
|
||||
QStringLiteral("output directory"), QStringLiteral("/home")});
|
||||
|
||||
addOption({QStringList() << QStringLiteral("i") << QStringLiteral("idlinfo"),
|
||||
QStringLiteral("the info file with all available idl service files"),
|
||||
QStringLiteral("info file for idl"), QStringLiteral("/0")});
|
||||
}
|
||||
|
||||
bool init()
|
||||
{
|
||||
if (!LtsCommandLineParser::init())
|
||||
return false;
|
||||
|
||||
if (serviceFile().isEmpty() || action().isEmpty() || outDir().isEmpty())
|
||||
{
|
||||
showHelp();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString serviceFile() const
|
||||
{
|
||||
return value(QStringLiteral("s"));
|
||||
}
|
||||
|
||||
QString action() const
|
||||
{
|
||||
return value(QStringLiteral("a"));
|
||||
}
|
||||
|
||||
QString outDir() const
|
||||
{
|
||||
return value(QStringLiteral("o"));
|
||||
}
|
||||
|
||||
QString idlInfoFile() const
|
||||
{
|
||||
return value(QStringLiteral("i"));
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("CodeGen", "codegen_log4cxx.props", true);
|
||||
|
||||
NGL::INGLLogger& m_logger = app.baseLogger();
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
QScopedPointer<CodeGen::XmlReader> reader(new CodeGen::XmlReader);
|
||||
|
||||
DEBUG_LOG(m_logger) << "ServiceFile: " << options.serviceFile();
|
||||
DEBUG_LOG(m_logger) << "IdlInfoFile: " << options.idlInfoFile();
|
||||
if (!reader->readServiceFile(options.serviceFile(), options.idlInfoFile()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error parsing service file '" << options.serviceFile() << ": " << reader->errorString();
|
||||
return 2;
|
||||
}
|
||||
|
||||
QDir dir(options.outDir());
|
||||
DEBUG_LOG(m_logger) << "Directory: " << options.outDir();
|
||||
if (!dir.exists() && !dir.mkpath(options.outDir()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Directory '" << options.outDir() << "' does not exist and can not be created!";
|
||||
return 3;
|
||||
}
|
||||
|
||||
QScopedPointer<CodeGen::StructBuilder> structBuilder(new CodeGen::StructBuilder(reader.data()));
|
||||
if (!structBuilder->buildStructures())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error building up structures";
|
||||
return 4;
|
||||
}
|
||||
|
||||
const QString action = options.action().toLower();
|
||||
|
||||
QScopedPointer<CodeGen::GeneratorGrantleeBase> generator;
|
||||
if (action == QStringLiteral("dao"))
|
||||
generator.reset(new CodeGen::DaoGeneratorGrantlee);
|
||||
else if (action == QStringLiteral("database"))
|
||||
generator.reset(new CodeGen::DatabaseGeneratorGrantlee(false));
|
||||
else if (action == QStringLiteral("database_server"))
|
||||
generator.reset(new CodeGen::DatabaseGeneratorGrantlee(true));
|
||||
else if (action == QStringLiteral("dds_topics"))
|
||||
generator.reset(new CodeGen::CppTopicGeneratorGrantlee);
|
||||
else if (action == QStringLiteral("sql"))
|
||||
{
|
||||
CodeGen::SqlGenerator sql(reader.data(), structBuilder.data());
|
||||
if (!sql.generateData(35))
|
||||
return 8;
|
||||
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (!sql.generateData(42))
|
||||
return 8;
|
||||
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
|
||||
sql.generateData(0);
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Global))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid action '" << options.action() << "' given!";
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (!generator->init(reader.data(), structBuilder.data()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing generator!";
|
||||
return 6;
|
||||
}
|
||||
|
||||
const auto posArgs = options.positionalArguments();
|
||||
for (const QString& file : posArgs)
|
||||
{
|
||||
|
||||
if (!generator->generateData(file, dir.absolutePath()))
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
|
||||
|
||||
#include "main_grantlee_gui.h"
|
||||
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
#include "ui_main_grantlee_gui.h"
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <nglapplication/nglapplication.h>
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent), m_xmlReader(nullptr), m_structBuilder(nullptr),
|
||||
m_generator(new CodeGen::CppTopicGeneratorGrantlee), m_engine(new KTextTemplate::Engine), m_ui(new Ui_MainGrantleeGui)
|
||||
{
|
||||
m_idlServiceInfoFile = QStringLiteral("/home/chehrlic/TDS/TDS-build-product-clang/service_idl_files.txt");
|
||||
m_ui->setupUi(this);
|
||||
connect(m_ui->actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||
connect(m_ui->actionSelect_Data_Source, &QAction::triggered, this, &MainWindow::onSelectDataSource);
|
||||
connect(m_ui->actionOpen_Template, &QAction::triggered, this, &MainWindow::onOpenTemplate);
|
||||
connect(m_ui->actionSave_Template, &QAction::triggered, this, &MainWindow::onSaveTemplate);
|
||||
connect(m_ui->pbRefresh, &QPushButton::clicked, this, &MainWindow::onRefreshOutput);
|
||||
connect(m_ui->actionDatabaseGenerator, &QAction::triggered, this, &MainWindow::onGeneratorDb);
|
||||
connect(m_ui->actionDDS_Generator, &QAction::triggered, this, &MainWindow::onGeneratorDds);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete m_xmlReader;
|
||||
delete m_structBuilder;
|
||||
delete m_generator;
|
||||
delete m_engine;
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
static QLatin1String s_startDir("/home/chehrlic/TDS/TDS-source-product/Lts/");
|
||||
|
||||
void MainWindow::onSelectDataSource()
|
||||
{
|
||||
const QString dataSource =
|
||||
QFileDialog::getOpenFileName(this, tr("Select data source"), s_startDir, tr("Service Files (*.xml)"));
|
||||
if (dataSource.isEmpty())
|
||||
return;
|
||||
delete m_xmlReader;
|
||||
m_xmlReader = new CodeGen::XmlReader;
|
||||
if (!m_xmlReader->readServiceFile(dataSource, m_idlServiceInfoFile))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid data source"),
|
||||
tr("The selected data source is not valid: %1").arg(m_xmlReader->errorString()));
|
||||
return;
|
||||
}
|
||||
delete m_structBuilder;
|
||||
m_structBuilder = new CodeGen::StructBuilder(m_xmlReader);
|
||||
if (!m_structBuilder->buildStructures())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid data source"), tr("Error building structures from data"));
|
||||
return;
|
||||
}
|
||||
m_ui->teOuput->clear();
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
QMessageBox::information(this, tr("Data source"), tr("Successfully loaded data source"));
|
||||
}
|
||||
|
||||
void MainWindow::onOpenTemplate()
|
||||
{
|
||||
const QString templateFile =
|
||||
QFileDialog::getOpenFileName(this, tr("Select data source"), s_startDir, tr("Templates (*.grantlee)"));
|
||||
if (templateFile.isEmpty())
|
||||
return;
|
||||
QFile f(templateFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error reading template file"), tr("Can not read file: %1").arg(f.errorString()));
|
||||
return;
|
||||
}
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
m_ui->teInput->setText(content);
|
||||
m_templateFile = templateFile;
|
||||
}
|
||||
|
||||
void MainWindow::onSaveTemplate()
|
||||
{
|
||||
QFile f(m_templateFile);
|
||||
if (!f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error saving template file"), tr("Can not save file: %1").arg(f.errorString()));
|
||||
return;
|
||||
}
|
||||
f.write(m_ui->teInput->toPlainText().toUtf8());
|
||||
f.close();
|
||||
QMessageBox::information(this, tr("Saving template file"),
|
||||
tr("Successfully saved template to %1").arg(m_templateFile));
|
||||
}
|
||||
|
||||
void MainWindow::onRefreshOutput()
|
||||
{
|
||||
const QString in = m_ui->teInput->toPlainText();
|
||||
if (!m_generator->setTemplate(QString(), in))
|
||||
{
|
||||
m_ui->teOuput->setText(m_generator->errorString());
|
||||
return;
|
||||
}
|
||||
m_ui->teOuput->setText(m_generator->render());
|
||||
}
|
||||
|
||||
void MainWindow::onGeneratorDb()
|
||||
{
|
||||
if (dynamic_cast<CodeGen::DatabaseGeneratorGrantlee*>(m_generator))
|
||||
return;
|
||||
delete m_generator;
|
||||
m_generator = new CodeGen::DatabaseGeneratorGrantlee(false);
|
||||
if (m_xmlReader && m_structBuilder)
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
}
|
||||
|
||||
void MainWindow::onGeneratorDds()
|
||||
{
|
||||
if (dynamic_cast<CodeGen::CppTopicGeneratorGrantlee*>(m_generator))
|
||||
return;
|
||||
delete m_generator;
|
||||
m_generator = new CodeGen::CppTopicGeneratorGrantlee;
|
||||
if (m_xmlReader && m_structBuilder)
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
NGLApplication app(argc, argv);
|
||||
app.createLogger("CodeGen", "codegen_log4cxx.props");
|
||||
|
||||
NGL::INGLLogger& m_logger = app.baseLogger();
|
||||
STARTUP_LOG(m_logger);
|
||||
|
||||
int iRet = 0;
|
||||
{
|
||||
QScopedPointer<MainWindow> mw(new MainWindow);
|
||||
mw->show();
|
||||
iRet = app.exec();
|
||||
}
|
||||
|
||||
SHUTDOWN_LOG(m_logger);
|
||||
return iRet;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class XmlReader;
|
||||
class StructBuilder;
|
||||
class GeneratorGrantleeBase;
|
||||
} // namespace CodeGen
|
||||
|
||||
namespace KTextTemplate
|
||||
{
|
||||
class Engine;
|
||||
}
|
||||
class Ui_MainGrantleeGui;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
~MainWindow();
|
||||
private Q_SLOTS:
|
||||
void onSelectDataSource();
|
||||
void onOpenTemplate();
|
||||
void onSaveTemplate();
|
||||
void onRefreshOutput();
|
||||
void onGeneratorDb();
|
||||
void onGeneratorDds();
|
||||
|
||||
private:
|
||||
CodeGen::XmlReader* m_xmlReader;
|
||||
CodeGen::StructBuilder* m_structBuilder;
|
||||
CodeGen::GeneratorGrantleeBase* m_generator;
|
||||
KTextTemplate::Engine* m_engine;
|
||||
QString m_idlServiceInfoFile;
|
||||
QString m_templateFile;
|
||||
Ui_MainGrantleeGui* m_ui;
|
||||
};
|
||||
@@ -1,140 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainGrantleeGui</class>
|
||||
<widget class="QMainWindow" name="MainGrantleeGui">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>838</width>
|
||||
<height>532</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="teInput"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Output</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="pbRefresh">
|
||||
<property name="text">
|
||||
<string>Refresh Output</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QTextBrowser" name="teOuput"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>838</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>Fi&le</string>
|
||||
</property>
|
||||
<addaction name="actionSelect_Data_Source"/>
|
||||
<addaction name="actionOpen_Template"/>
|
||||
<addaction name="actionSave_Template"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuGenerator">
|
||||
<property name="title">
|
||||
<string>&Generator</string>
|
||||
</property>
|
||||
<addaction name="actionDatabaseGenerator"/>
|
||||
<addaction name="actionDDS_Generator"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuGenerator"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>&Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_Template">
|
||||
<property name="text">
|
||||
<string>&Open Template</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSelect_Data_Source">
|
||||
<property name="text">
|
||||
<string>&Select Data Source</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Template">
|
||||
<property name="text">
|
||||
<string>Sa&ve Template</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDatabaseGenerator">
|
||||
<property name="text">
|
||||
<string>&DatabaseGenerator</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDDS_Generator">
|
||||
<property name="text">
|
||||
<string>DDS &Generator</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for idl struct definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-05
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}.idl
|
||||
#ifndef {{ namespace_abbr }}_idl_included
|
||||
#define {{ namespace_abbr }}_idl_included
|
||||
|
||||
//@copy #include <{{ include_prefix }}/{{ namespace_abbr }}_export.h> // #define NDDSUSERDllExport for linux
|
||||
|
||||
//@copy #include "{{ namespace_abbr }}_enums.hpp"
|
||||
#include "{{ namespace_abbr }}_enums.idl"
|
||||
|
||||
{% for ext_service in ext_services.member %}
|
||||
//@copy #include <{{ ext_service.baseFilePath }}.hpp>
|
||||
#include <{{ ext_service.baseFilePath }}.idl>
|
||||
{% endfor %}
|
||||
|
||||
module {{ namespace }}
|
||||
{
|
||||
{% for idl_struct in idl_structs %}
|
||||
|
||||
{% if idl_struct.comment %} // {{ idl_struct.comment }} {% endif %}
|
||||
struct {{ idl_struct.name }} {% if idl_struct.baseValueType %}: {{ idl_struct.baseValueType }} {% endif %}
|
||||
{ {% for idl_member in idl_struct.member %}
|
||||
{{ idl_member.type }} {{ idl_member.name }}; {{ idl_member.isKey }} {{ idl_member.isOptional }} {% endfor %}
|
||||
}; //@Extensibility {{ idl_struct.extensibility }}
|
||||
|
||||
{% endfor %}
|
||||
}; // namespace {{ namespace }}
|
||||
|
||||
#endif
|
||||
{% endautoescape %}
|
||||
@@ -1,204 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id: svc_db_impl.cpp.grantlee 56901 2022-04-22 04:21:30Z karwat $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/svc_db_impl.cpp.grantlee $
|
||||
* $Author: karwat $
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dao.cpp
|
||||
#include "{{ namespace_abbr }}_dao.h"
|
||||
{% if custom_db_procs %}
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_db_impl_custom.h>
|
||||
{% endif %}
|
||||
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/sql_query_janitor.h>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <QVariant>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
|
||||
Dao::Dao(int exerciseId)
|
||||
: m_query(nullptr)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_bEmitMessageOnError(true)
|
||||
, m_bCanHandleSchemas(true)
|
||||
, m_ownDatabaseConnection(true)
|
||||
, m_logger(getLogger("Db"))
|
||||
{}
|
||||
|
||||
Dao::~Dao()
|
||||
{
|
||||
m_query = nullptr;
|
||||
{% if has_db_notifications %}
|
||||
QSqlDriver *driver = m_dbConnection.driver();
|
||||
if (driver && m_dbConnection.isOpen())
|
||||
{
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %} driver->unsubscribeFromNotification(QStringLiteral("{{ db_notify }}"));
|
||||
{% endfor %}{% endfor %} }
|
||||
{% endif %}
|
||||
if (m_ownDatabaseConnection && m_dbConnection.isOpen())
|
||||
m_dbConnection.close();
|
||||
}
|
||||
|
||||
bool Dao::init(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName)
|
||||
{
|
||||
m_ownDatabaseConnection = true;
|
||||
|
||||
m_dbConnection = DBConnection::open(m_logger, dbUser, dbPasswd, dbDriver, dbHost, dbName, schemaName());
|
||||
|
||||
return initInternal();
|
||||
}
|
||||
|
||||
bool Dao::initInternal()
|
||||
{
|
||||
QSqlDriver *driver = m_dbConnection.driver();
|
||||
if (!driver)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No SQL driver loaded - no database available!";
|
||||
return false;
|
||||
}
|
||||
const QString driverName = m_dbConnection.driverName();
|
||||
DEBUG_LOG(m_logger) << "Connected to database " << m_dbConnection.databaseName() << "@" << m_dbConnection.hostName()
|
||||
<< ", schema: " << schemaName() << ", used driver: " << driverName;
|
||||
if (!m_dbConnection.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Database connection is no open - can not initialize database interface";
|
||||
return false;
|
||||
}
|
||||
if (driverName == QLatin1String("QSQLITE"))
|
||||
m_bCanHandleSchemas = false;
|
||||
|
||||
{% if has_db_notifications %}
|
||||
if (!driver->hasFeature(QSqlDriver::EventNotifications))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not subscribe to notifications - sqldriver does not support this feature!";
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(driver, QOverload<const QString&,QSqlDriver::NotificationSource,const QVariant&>::of(&QSqlDriver::notification),
|
||||
this, &Dao::onNotification);
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}driver->subscribeToNotification(QStringLiteral("{{ db_notify }}"));{% endfor %}{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
m_query = std::unique_ptr<NSqlQuery>(new NSqlQuery(m_dbConnection, m_logger));
|
||||
return true;
|
||||
}
|
||||
|
||||
QString Dao::schemaName() const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return QString();
|
||||
if (m_exerciseId <= 0)
|
||||
return QStringLiteral("{{ namespace_abbr }}");
|
||||
return DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
}
|
||||
|
||||
QString Dao::dbUser() const
|
||||
{
|
||||
if (m_exerciseId > 0)
|
||||
return QStringLiteral("ets_ex_00");
|
||||
else
|
||||
return QStringLiteral("ets_") + schemaName();
|
||||
}
|
||||
|
||||
void Dao::setEmitMessageOnError(bool bEmit)
|
||||
{
|
||||
m_bEmitMessageOnError = bEmit;
|
||||
}
|
||||
|
||||
QString Dao::getTableName(const QString &tableName) const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return tableName;
|
||||
if (m_exerciseId > 0)
|
||||
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
||||
return QStringLiteral("{{ namespace_abbr }}.") + tableName;
|
||||
}
|
||||
|
||||
QSqlError Dao::getLastError() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
{% if has_db_notifications %}
|
||||
void Dao::onNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Notification source = " << source;
|
||||
if (source == QSqlDriver::SelfSource)
|
||||
return;
|
||||
// search coresponding signal
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
||||
if (name == QStringLiteral("{{ db_notify }}"))
|
||||
{
|
||||
emit signal{{ db_notify }}(payload.toInt());
|
||||
|
||||
return;
|
||||
}
|
||||
{% endfor %}{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
//
|
||||
// --> Struct: Database::{{ cpp_struct.name }}
|
||||
//
|
||||
|
||||
bool Dao::select(QVector<Database::{{ cpp_struct.name }}> &dataVec, const QString &where)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const auto cb =[&dataVec] (const Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
dataVec.push_back(data);
|
||||
};
|
||||
return selectPrepareInternal{{ cpp_struct.name }}(where) && selectFetchInternal{{ cpp_struct.name }}(cb);
|
||||
}
|
||||
|
||||
bool Dao::selectPrepareInternal{{ cpp_struct.name }}(const QString &where)
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.viewTableName }}")));
|
||||
const QString stmt(QStringLiteral("SELECT {% for row in cpp_struct.viewMember %}{{ row.dbColumnNameView }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" FROM ") + tableName + where);
|
||||
return m_query->prepare(stmt);
|
||||
}
|
||||
|
||||
bool Dao::selectFetchInternal{{ cpp_struct.name }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb)
|
||||
{
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::{{ cpp_struct.name }} data;
|
||||
while (m_query->next())
|
||||
{
|
||||
int i = 0;
|
||||
{% for row in cpp_struct.viewMember %}
|
||||
data.{{ row.cppMemberName }}{{ row.cppFromQvPre1 }} = {{ row.cppFromQvPre2 }}m_query->value(i++){{ row.cppFromQvPost }};{% endfor %}
|
||||
cb(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// <-- Database::{{ cpp_struct.name }} end
|
||||
{% endfor %}
|
||||
|
||||
/*static*/ QString Dao::qVariantToJsonString(const QVariant &value)
|
||||
{
|
||||
return value.isNull() ? QStringLiteral("{}") : value.toString();
|
||||
}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id: svc_db_impl.h.grantlee 53676 2021-06-10 10:21:06Z diers $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/svc_db_impl.h.grantlee $
|
||||
* $Author: diers $
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dao.h
|
||||
#pragma once
|
||||
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlDatabase>
|
||||
#include <QtSql/QSqlError>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_enums.hpp>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_db.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
class NSqlQuery;
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
class {{ namespace_abbr_upper }}_COMMON_EXPORT Dao {% if not custom_db_procs %}final {%endif %}: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Dao(int exerciseId);
|
||||
~Dao();
|
||||
|
||||
bool init(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName);
|
||||
|
||||
QString schemaName() const;
|
||||
QString dbUser() const;
|
||||
const QSqlDatabase &database() const { return m_dbConnection; }
|
||||
void setEmitMessageOnError(bool bEmit);
|
||||
QSqlError getLastError() const;
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
// --> Database::{{ cpp_struct.name }}
|
||||
public:
|
||||
bool select(QVector<Database::{{ cpp_struct.name }}> &dataVec, const QString &where = QString());
|
||||
|
||||
private:
|
||||
bool selectPrepareInternal{{ cpp_struct.name }}(const QString &where);
|
||||
bool selectFetchInternal{{ cpp_struct.name }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb);
|
||||
// <-- Database::{{ cpp_struct.name }}
|
||||
{% endfor %}
|
||||
|
||||
static QString qVariantToJsonString(const QVariant &value);
|
||||
|
||||
protected:
|
||||
QString getTableName(const QString &tableName) const;
|
||||
{% if has_db_notifications %}
|
||||
private Q_SLOTS:
|
||||
void onNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload);
|
||||
|
||||
Q_SIGNALS:
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %} void signal{{ db_notify }}(int id);
|
||||
{% endfor %}{% endfor %}{% endif %}
|
||||
protected:
|
||||
QSqlDatabase m_dbConnection;
|
||||
std::unique_ptr<NSqlQuery> m_query;
|
||||
QSqlError m_lastError;
|
||||
int m_exerciseId;
|
||||
bool m_bEmitMessageOnError;
|
||||
bool m_bCanHandleSchemas;
|
||||
bool m_ownDatabaseConnection;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
private:
|
||||
bool initInternal();
|
||||
};// class Dao
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,145 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_db.h
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
#include <QtSql/QSqlError>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_db_structs.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_enums.hpp>
|
||||
|
||||
{% for ext_service in ext_services.member %}
|
||||
#include <{{ ext_service.baseFilePath }}.hpp>
|
||||
{% endfor %}
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
class QSqlDatabase;
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
|
||||
class {{ namespace_abbr_upper }}_COMMON_EXPORT DatabaseInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~DatabaseInterface() = default;
|
||||
|
||||
/**
|
||||
* Create a new instance for {{ namespace }}::DatabaseInterface.
|
||||
* @param exerciseId if <= 0 -> global service
|
||||
*/
|
||||
static std::shared_ptr<DatabaseInterface> create(int exerciseId);
|
||||
|
||||
/**
|
||||
* @brief initialize the database interface (must be called after the db connection was opened!)
|
||||
* @return true on succcess
|
||||
*/
|
||||
virtual bool init(const QSqlDatabase &dbConnection) = 0;
|
||||
virtual bool init(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName) = 0;
|
||||
|
||||
/**
|
||||
* @brief return the current schema name depending if exercise id > 0 or not
|
||||
*/
|
||||
virtual QString schemaName() const = 0;
|
||||
|
||||
/**
|
||||
* @brief return the current database user dependening if exercise id > 0 or not
|
||||
*/
|
||||
virtual QString dbUser() const = 0;
|
||||
|
||||
/**
|
||||
* @brief return the database connection used in this DatabaseInterface
|
||||
*/
|
||||
virtual const QSqlDatabase &database() const = 0;
|
||||
|
||||
/**
|
||||
* emit an error message (ERROR_LOG) when a statement fails to execute (default: on)
|
||||
*/
|
||||
virtual void setEmitMessageOnError(bool bEmit) = 0;
|
||||
|
||||
virtual QSqlError getLastError() const = 0;
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
//
|
||||
// Database::{{ cpp_struct.name }}
|
||||
//
|
||||
public:
|
||||
virtual bool insert(Database::{{ cpp_struct.name }} &data) = 0;
|
||||
virtual bool upsert(Database::{{ cpp_struct.name }} &data) = 0;
|
||||
virtual bool update(const Database::{{ cpp_struct.name }} &data) = 0;
|
||||
{% if cpp_struct.insertStructures|length == 1 %}
|
||||
virtual bool insert(std::vector<Database::{{ cpp_struct.name }}> &cont) = 0;
|
||||
virtual bool upsert(std::vector<Database::{{ cpp_struct.name }}> &cont) = 0;
|
||||
virtual bool update(const std::vector<Database::{{ cpp_struct.name }}> &cont) = 0;
|
||||
{% endif %}
|
||||
virtual bool select(QVector<Database::{{ cpp_struct.name }}> &dataVec) = 0;
|
||||
virtual bool select(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb) = 0;
|
||||
{% for fk in cpp_struct.selectRemoveMember %}
|
||||
virtual bool selectBy{{ fk.cppMemberNameCc }}(QVector<Database::{{ cpp_struct.name }}> &dataVec, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy = QString()) = 0;
|
||||
virtual bool selectBy{{ fk.cppMemberNameCc }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy = QString()) = 0;
|
||||
{% endfor %}
|
||||
virtual bool select{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}, Database::{{ cpp_struct.name }} &data) = 0;
|
||||
virtual bool remove{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}) = 0;
|
||||
{% if cpp_struct.deleteWithoutPkAllowed %} {% for fk in cpp_struct.selectRemoveMember %}
|
||||
virtual bool remove{{ cpp_struct.nameCc }}By{{ fk.cppMemberNameCc }}(const {{ fk.cppType }} &{{ fk.cppMemberName }}) = 0;
|
||||
{% endfor %} {% endif %}
|
||||
virtual bool fixUpSequence{{ cpp_struct.name }}() = 0;
|
||||
virtual bool truncate{{ cpp_struct.name }}() = 0;
|
||||
{% if cpp_struct.dbNotifications %}
|
||||
Q_SIGNALS:
|
||||
{% for dbnotify in cpp_struct.dbNotifications %}
|
||||
// database notification on insert/update/delete
|
||||
void {{ dbnotify }}(const QVariant &payload);
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
//
|
||||
// Database::{{ cpp_struct.name }} end
|
||||
//
|
||||
{% endfor %}
|
||||
{% if data_structs|length > 0 %}
|
||||
public:{% for data_struct in data_structs %}
|
||||
// read only struct Database::{{ data_struct.name }}
|
||||
virtual bool select(QVector<Database::{{ data_struct.name }}> &dataVec) = 0;
|
||||
{% endfor %} {% endif %}
|
||||
{% if custom_db_procs|length > 0 %}
|
||||
public:{% for db_proc in custom_db_procs %}
|
||||
// custom proc, body must be implemented by user
|
||||
virtual {{ db_proc.signature }} = 0;
|
||||
{% endfor %} {% endif %}
|
||||
|
||||
public:
|
||||
|
||||
// vector of database struct to/from JSON-array
|
||||
// helper for BaseDownloader
|
||||
template<typename T>
|
||||
static QJsonArray toJson(const QVector<T> &dataVec)
|
||||
{
|
||||
return Database::toJson<T>(dataVec);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::vector<T> fromJson(const QJsonArray &arr)
|
||||
{
|
||||
return Database::fromJson<T>(arr);
|
||||
}
|
||||
};// class DatabaseInterface
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,732 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_db_impl.cpp
|
||||
#include "{{ namespace_abbr }}_db_impl.h"
|
||||
{% if custom_db_procs %}
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_db_impl_custom.h>
|
||||
{% endif %}
|
||||
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/sql_query_janitor.h>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <QVariant>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
|
||||
QString qVariantToJsonString(const QVariant &value)
|
||||
{
|
||||
return value.isNull() ? QStringLiteral("{}") : value.toString();
|
||||
}
|
||||
|
||||
QString fixupEmptyJsonString(const QString &str)
|
||||
{
|
||||
return str.isEmpty() ? QStringLiteral("{}") : str;
|
||||
}
|
||||
|
||||
// DatabaseInterface
|
||||
std::shared_ptr<DatabaseInterface> DatabaseInterface::create(int exerciseId)
|
||||
{
|
||||
{% if custom_db_procs %}
|
||||
return std::make_shared<DatabaseInterfaceImplCustom>(exerciseId);
|
||||
{% else %}
|
||||
return std::make_shared<DatabaseInterfaceImpl>(exerciseId);
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
DatabaseInterfaceImpl::DatabaseInterfaceImpl(int exerciseId)
|
||||
: m_query(nullptr)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_bEmitMessageOnError(true)
|
||||
, m_bCanHandleSchemas(true)
|
||||
, m_ownDatabaseConnection(true)
|
||||
, m_logger(getLogger("Db"))
|
||||
{}
|
||||
|
||||
DatabaseInterfaceImpl::~DatabaseInterfaceImpl()
|
||||
{
|
||||
m_query = nullptr;
|
||||
{% if has_db_notifications %}
|
||||
QSqlDriver *driver = m_dbConnection.driver();
|
||||
if (driver && m_dbConnection.isOpen())
|
||||
{
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
||||
driver->unsubscribeFromNotification(QStringLiteral("{{ db_notify }}"));{% endfor %}{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
if (m_ownDatabaseConnection && m_dbConnection.isOpen())
|
||||
m_dbConnection.close();
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::init(const QSqlDatabase &dbConnection)
|
||||
{
|
||||
m_dbConnection = dbConnection;
|
||||
m_ownDatabaseConnection = false;
|
||||
return initInternal();
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::init(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName)
|
||||
{
|
||||
m_ownDatabaseConnection = true;
|
||||
|
||||
m_dbConnection = DBConnection::open(m_logger, dbUser, dbPasswd, dbDriver, dbHost, dbName, schemaName());
|
||||
|
||||
return initInternal();
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::initInternal()
|
||||
{
|
||||
QSqlDriver *driver = m_dbConnection.driver();
|
||||
if (!driver)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No SQL driver loaded - no database available!";
|
||||
return false;
|
||||
}
|
||||
const QString driverName = m_dbConnection.driverName();
|
||||
DEBUG_LOG(m_logger) << "Connected to database " << m_dbConnection.databaseName() << "@" << m_dbConnection.hostName()
|
||||
<< ", schema: " << schemaName() << ", used driver: " << driverName;
|
||||
if (!m_dbConnection.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Database connection is no open - can not initialize database interface";
|
||||
return false;
|
||||
}
|
||||
if (driverName == QLatin1String("QSQLITE"))
|
||||
m_bCanHandleSchemas = false;
|
||||
|
||||
{% if has_db_notifications %}
|
||||
if (!driver->hasFeature(QSqlDriver::EventNotifications))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not subscribe to notifications - sqldriver does not support this feature!";
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(driver, QOverload<const QString&,QSqlDriver::NotificationSource,const QVariant&>::of(&QSqlDriver::notification),
|
||||
this, &DatabaseInterfaceImpl::onNotification);
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
||||
driver->subscribeToNotification(QStringLiteral("{{ db_notify }}"));{% endfor %}{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
m_query = std::unique_ptr<NSqlQuery>(new NSqlQuery(m_dbConnection, m_logger));
|
||||
return true;
|
||||
}
|
||||
|
||||
QString DatabaseInterfaceImpl::schemaName() const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return QString();
|
||||
if (m_exerciseId <= 0)
|
||||
return QStringLiteral("{{ namespace_abbr }}");
|
||||
return DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
}
|
||||
|
||||
QString DatabaseInterfaceImpl::dbUser() const
|
||||
{
|
||||
if (m_exerciseId > 0)
|
||||
return QStringLiteral("ets_ex_00");
|
||||
else
|
||||
return QStringLiteral("ets_") + schemaName();
|
||||
}
|
||||
|
||||
void DatabaseInterfaceImpl::setEmitMessageOnError(bool bEmit)
|
||||
{
|
||||
m_bEmitMessageOnError = bEmit;
|
||||
}
|
||||
|
||||
QString DatabaseInterfaceImpl::getTableName(const QString &tableName) const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return tableName;
|
||||
if (m_exerciseId > 0)
|
||||
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
||||
return QStringLiteral("{{ namespace_abbr }}.") + tableName;
|
||||
}
|
||||
|
||||
QSqlError DatabaseInterfaceImpl::getLastError() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
{% if has_db_notifications %}
|
||||
void DatabaseInterfaceImpl::onNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Notification source = " << source;
|
||||
// no need to emit notification signals
|
||||
if (source == QSqlDriver::SelfSource)
|
||||
return;
|
||||
// search coresponding signal
|
||||
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
||||
if (name == QLatin1String("{{ db_notify }}"))
|
||||
{
|
||||
emit {{ db_notify }}(payload);
|
||||
}{% endfor %}{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
//
|
||||
// Struct: Database::{{ cpp_struct.name }}
|
||||
//
|
||||
bool DatabaseInterfaceImpl::insert(Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
DBTransaction transaction(m_dbConnection);
|
||||
{% endif %}
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
|
||||
QString keyColumnInsertKey;
|
||||
QString keyColumnInsertVal;
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
const bool bInsertWithKey = data.{{cpp_struct.primaryKey.cppMemberName}} != {{cpp_struct.primaryKey.cppDefault}};
|
||||
if (bInsertWithKey)
|
||||
{
|
||||
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
}
|
||||
{% endif %}
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
||||
QStringLiteral(" (") + keyColumnInsertKey +
|
||||
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" ) VALUES (") + keyColumnInsertVal +
|
||||
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )"));
|
||||
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% else %}
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% endif %}
|
||||
{% if insertStruct.baseId.cppMemberName %}
|
||||
data.{{ insertStruct.baseId.cppMemberName }} = data.{{ insertStruct.serialMember.cppMemberName }};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
transaction.commit();
|
||||
{% endif %}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::upsert(Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
DBTransaction transaction(m_dbConnection);
|
||||
{% endif %}
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
|
||||
QString keyColumnInsertKey;
|
||||
QString keyColumnInsertKeyConflict;
|
||||
QString keyColumnInsertVal;
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
const bool bInsertWithKey = true;
|
||||
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
{% endif %}
|
||||
|
||||
keyColumnInsertKeyConflict = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }} ");
|
||||
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
||||
QStringLiteral(" (") + keyColumnInsertKey +
|
||||
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" ) VALUES (") + keyColumnInsertVal +
|
||||
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )") +
|
||||
QStringLiteral(" ON CONFLICT (") + keyColumnInsertKeyConflict + QStringLiteral(") DO UPDATE ") +
|
||||
QStringLiteral(" SET"
|
||||
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" WHERE excluded.{{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
||||
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% else %}
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% endif %}
|
||||
{% if insertStruct.baseId.cppMemberName %}
|
||||
data.{{ insertStruct.baseId.cppMemberName }} = data.{{ insertStruct.serialMember.cppMemberName }};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
transaction.commit();
|
||||
{% endif %}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::update(const Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
DBTransaction transaction(m_dbConnection);
|
||||
{% endif %}
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
const QString stmt(QStringLiteral("UPDATE ") + tableName +
|
||||
QStringLiteral(" SET"
|
||||
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" WHERE {{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
||||
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
{% if cpp_struct.insertStructures|length > 1 %}
|
||||
transaction.commit();
|
||||
{% endif %}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% if cpp_struct.insertStructures|length == 1 %}
|
||||
// current only implemented for 'plain' structures with only one affected table
|
||||
bool DatabaseInterfaceImpl::insert(std::vector<Database::{{ cpp_struct.name }}> &cont)
|
||||
{
|
||||
if (cont.empty())
|
||||
return true;
|
||||
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
|
||||
QString keyColumnInsertKey;
|
||||
QString keyColumnInsertVal;
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
const bool bInsertWithKey = cont[0].{{cpp_struct.primaryKey.cppMemberName}} != {{cpp_struct.primaryKey.cppDefault}};
|
||||
// the first element determines the stmt to be used
|
||||
if (bInsertWithKey)
|
||||
{
|
||||
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
}
|
||||
{% endif %}
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
||||
QStringLiteral(" (") + keyColumnInsertKey +
|
||||
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" ) VALUES (") + keyColumnInsertVal +
|
||||
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )"));
|
||||
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &data : cont)
|
||||
{
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
fixUpSequence{{ cpp_struct.nameCc }}();
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
{% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::upsert(std::vector<Database::{{ cpp_struct.name }}> &cont)
|
||||
{
|
||||
if (cont.empty())
|
||||
return true;
|
||||
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
|
||||
QString keyColumnInsertKey;
|
||||
QString keyColumnInsertKeyConflict;
|
||||
QString keyColumnInsertVal;
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
const bool bInsertWithKey = true;
|
||||
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
||||
{% endif %}
|
||||
// the first element determines the stmt to be used
|
||||
keyColumnInsertKeyConflict = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }} ");
|
||||
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
||||
QStringLiteral(" (") + keyColumnInsertKey +
|
||||
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" ) VALUES (") + keyColumnInsertVal +
|
||||
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )") +
|
||||
QStringLiteral(" ON CONFLICT (") + keyColumnInsertKeyConflict + QStringLiteral(") DO UPDATE ") +
|
||||
QStringLiteral(" SET"
|
||||
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" WHERE excluded.{{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
||||
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &data : cont)
|
||||
{
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
||||
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
||||
if (bInsertWithKey)
|
||||
fixUpSequence{{ cpp_struct.nameCc }}();
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
{% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
// current only implemented for 'plain' structures with only one affected table
|
||||
bool DatabaseInterfaceImpl::update(const std::vector<Database::{{ cpp_struct.name }}> &cont)
|
||||
{
|
||||
if (cont.empty())
|
||||
return true;
|
||||
|
||||
{% for insertStruct in cpp_struct.insertStructures %}
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
||||
const QString stmt(QStringLiteral("UPDATE ") + tableName +
|
||||
QStringLiteral(" SET"
|
||||
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" WHERE {{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
||||
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &data : cont)
|
||||
{
|
||||
{% for row in insertStruct.member %}
|
||||
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
||||
{% endfor %}
|
||||
{% if insertStruct.serialMember.cppMemberName %}
|
||||
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
||||
{% endif %}
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
return true;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
bool DatabaseInterfaceImpl::select(QVector<Database::{{ cpp_struct.name }}> &dataVec)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const auto cb =[&dataVec] (const Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
dataVec.push_back(data);
|
||||
};
|
||||
return selectPrepareInternal{{ cpp_struct.name }}(QString()) && selectFetchInternal{{ cpp_struct.name }}(cb);
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::select(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
return selectPrepareInternal{{ cpp_struct.name }}(QString()) && selectFetchInternal{{ cpp_struct.name }}(cb);
|
||||
}
|
||||
|
||||
{% for fk in cpp_struct.selectRemoveMember %}
|
||||
bool DatabaseInterfaceImpl::selectBy{{ fk.cppMemberNameCc }}(QVector<Database::{{ cpp_struct.name }}> &dataVec, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
if (!selectPrepareInternal{{ cpp_struct.name }}(QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.dbColumnName }}") + orderBy))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
m_query->bindValue(QStringLiteral(":{{ fk.dbColumnName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
||||
const auto cb =[&dataVec] (const Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
dataVec.push_back(data);
|
||||
};
|
||||
return selectFetchInternal{{ cpp_struct.name }}(cb);
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::selectBy{{ fk.cppMemberNameCc }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
if (!selectPrepareInternal{{ cpp_struct.name }}(QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.dbColumnName }}") + orderBy))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
m_query->bindValue(QStringLiteral(":{{ fk.dbColumnName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
||||
return selectFetchInternal{{ cpp_struct.name }}(cb);
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
bool DatabaseInterfaceImpl::selectPrepareInternal{{ cpp_struct.name }}(const QString &where)
|
||||
{
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.viewTableName }}")));
|
||||
const QString stmt(QStringLiteral("SELECT {% for row in cpp_struct.viewMember %}{{ row.dbColumnNameView }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" FROM ") + tableName + where);
|
||||
return m_query->prepare(stmt);
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::selectFetchInternal{{ cpp_struct.name }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb)
|
||||
{
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::{{ cpp_struct.name }} data;
|
||||
while (m_query->next())
|
||||
{
|
||||
int i = 0;
|
||||
{% for row in cpp_struct.viewMember %}
|
||||
data.{{ row.cppMemberName }}{{ row.cppFromQvPre1 }} = {{ row.cppFromQvPre2 }}m_query->value(i++){{ row.cppFromQvPost }};{% endfor %}
|
||||
cb(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::select{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}, Database::{{ cpp_struct.name }} &data)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
int iCnt = 0;
|
||||
const auto cb =[&data, &iCnt] (const Database::{{ cpp_struct.name }} &content)
|
||||
{
|
||||
data = content;
|
||||
++iCnt;
|
||||
};
|
||||
const QString where = QStringLiteral(" WHERE {{ cpp_struct.primaryKey.dbColumnName }} = %1").arg({{ cpp_struct.primaryKey.cppMemberName }});
|
||||
if (!selectPrepareInternal{{ cpp_struct.name }}(where) || !selectFetchInternal{{ cpp_struct.name }}(cb))
|
||||
return false;
|
||||
|
||||
return (iCnt == 1);
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::remove{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }})
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
||||
const QString stmt(QStringLiteral("DELETE FROM ") + tableName +
|
||||
QStringLiteral(" WHERE {{ cpp_struct.primaryKey.dbColumnName }} = ") +
|
||||
QString::number({{ cpp_struct.primaryKey.cppMemberName }}));
|
||||
|
||||
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
{% if cpp_struct.deleteWithoutPkAllowed %} {% for fk in cpp_struct.selectRemoveMember %}
|
||||
bool DatabaseInterfaceImpl::remove{{ cpp_struct.nameCc }}By{{ fk.cppMemberNameCc }}(const {{ fk.cppType }} &{{ fk.cppMemberName }})
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
||||
const QString stmt(QStringLiteral("DELETE FROM ") + tableName +
|
||||
QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.cppMemberName }}"));
|
||||
|
||||
if (!m_query->prepare(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_query->bindValue(QStringLiteral(":{{ fk.cppMemberName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
||||
|
||||
|
||||
return m_query->exec(m_bEmitMessageOnError);
|
||||
}
|
||||
{% endfor %} {% endif %}
|
||||
bool DatabaseInterfaceImpl::fixUpSequence{{ cpp_struct.nameCc }}()
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
||||
const QString stmt(QStringLiteral("SELECT setval('") + tableName + QStringLiteral("_{{ cpp_struct.primaryKey.dbColumnName }}_seq', COALESCE((SELECT MAX({{ cpp_struct.primaryKey.dbColumnName }})+1 FROM ") +
|
||||
tableName + QStringLiteral("), 1),false)"));
|
||||
|
||||
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseInterfaceImpl::truncate{{ cpp_struct.nameCc }}()
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
||||
const QString stmt(QStringLiteral("TRUNCATE TABLE ") + tableName + QStringLiteral(" CASCADE"));
|
||||
|
||||
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Database::{{ cpp_struct.name }} end
|
||||
{% endfor %}
|
||||
|
||||
{% for ds in data_structs %}
|
||||
bool DatabaseInterfaceImpl::select(QVector<Database::{{ ds.name }}> &dataVec)
|
||||
{
|
||||
SqlQueryJanitor janitor(m_query);
|
||||
const QString tableName(getTableName(QStringLiteral("{{ ds.viewTableName }}")));
|
||||
const QString stmt(QStringLiteral("SELECT {% for row in ds.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
||||
" FROM ") + tableName);
|
||||
|
||||
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::{{ ds.name }} data;
|
||||
while (m_query->next())
|
||||
{
|
||||
int i = 0;
|
||||
{% for row in ds.member %}
|
||||
data.{{ row.cppMemberName }}{{ row.cppFromQvPre1 }} = {{ row.cppFromQvPre2 }}m_query->value(i++){{ row.cppFromQvPost }};{% endfor %}
|
||||
dataVec.append(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
{% endfor %}
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_db_impl.h
|
||||
#pragma once
|
||||
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlDatabase>
|
||||
#include <QtSql/QSqlError>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_enums.hpp>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_db.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
class NSqlQuery;
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
class {{ namespace_abbr_upper }}_COMMON_EXPORT DatabaseInterfaceImpl {% if not custom_db_procs %}final {%endif %}: public DatabaseInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DatabaseInterfaceImpl(int exerciseId);
|
||||
~DatabaseInterfaceImpl();
|
||||
|
||||
bool init(const QSqlDatabase &dbConnection) override final;
|
||||
bool init(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName) override final;
|
||||
|
||||
QString schemaName() const override final;
|
||||
QString dbUser() const override final;
|
||||
const QSqlDatabase &database() const override final { return m_dbConnection; }
|
||||
void setEmitMessageOnError(bool bEmit) override final;
|
||||
QSqlError getLastError() const override final;
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
|
||||
// Database::{{ cpp_struct.name }}
|
||||
bool insert(Database::{{ cpp_struct.name }} &data) override final;
|
||||
bool upsert(Database::{{ cpp_struct.name }} &data) override final;
|
||||
bool update(const Database::{{ cpp_struct.name }} &data) override final;
|
||||
{% if cpp_struct.insertStructures|length == 1 %}
|
||||
bool insert(std::vector<Database::{{ cpp_struct.name }}> &cont) override final;
|
||||
bool upsert(std::vector<Database::{{ cpp_struct.name }}> &cont) override final;
|
||||
bool update(const std::vector<Database::{{ cpp_struct.name }}> &cont) override final;
|
||||
{% endif %}
|
||||
bool select(QVector<Database::{{ cpp_struct.name }}> &dataVec) override final;
|
||||
bool select(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb) override final;
|
||||
{% for fk in cpp_struct.selectRemoveMember %}
|
||||
bool selectBy{{ fk.cppMemberNameCc }}(QVector<Database::{{ cpp_struct.name }}> &dataVec, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy = QString()) override final;
|
||||
bool selectBy{{ fk.cppMemberNameCc }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy = QString()) override final;
|
||||
{% endfor %}
|
||||
protected:
|
||||
bool selectPrepareInternal{{ cpp_struct.name }}(const QString &where);
|
||||
bool selectFetchInternal{{ cpp_struct.name }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb);
|
||||
public:
|
||||
bool select{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}, Database::{{ cpp_struct.name }} &data) override final;
|
||||
bool remove{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}) override final;
|
||||
{% if cpp_struct.deleteWithoutPkAllowed %} {% for fk in cpp_struct.selectRemoveMember %}
|
||||
bool remove{{ cpp_struct.nameCc }}By{{ fk.cppMemberNameCc }}(const {{ fk.cppType }} &{{ fk.cppMemberName }}) override final;
|
||||
{% endfor %} {% endif %}
|
||||
bool fixUpSequence{{ cpp_struct.name }}() override final;
|
||||
bool truncate{{ cpp_struct.name }}() override final;
|
||||
// Database::{{ cpp_struct.name }}
|
||||
{% endfor %}
|
||||
|
||||
{% for data_struct in data_structs %}
|
||||
// read only struct{{ data_struct.name }}
|
||||
bool select(QVector<Database::{{ data_struct.name }}> &dataVec) override final;
|
||||
{% endfor %}
|
||||
|
||||
protected:
|
||||
QString getTableName(const QString &tableName) const;
|
||||
{% if has_db_notifications %}
|
||||
private Q_SLOTS:
|
||||
void onNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload);
|
||||
{% endif %}
|
||||
protected:
|
||||
QSqlDatabase m_dbConnection;
|
||||
std::unique_ptr<NSqlQuery> m_query;
|
||||
QSqlError m_lastError;
|
||||
int m_exerciseId;
|
||||
bool m_bEmitMessageOnError;
|
||||
bool m_bCanHandleSchemas;
|
||||
bool m_ownDatabaseConnection;
|
||||
LOGGER_T m_logger;
|
||||
private:
|
||||
bool initInternal();
|
||||
};// class DatabaseInterfaceImpl
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,112 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_db_structs.cpp
|
||||
#include "{{ namespace_abbr }}_db_structs.h"
|
||||
#include "{{ namespace_abbr }}_export.h"
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Database
|
||||
{
|
||||
QString jsonValueToJsonString(const QJsonValue &value)
|
||||
{
|
||||
return value.isNull() ? QStringLiteral("{}") : value.toString();
|
||||
}
|
||||
|
||||
QString qVariantToJsonString(const QVariant &value)
|
||||
{
|
||||
return value.isNull() ? QStringLiteral("{}") : value.toString();
|
||||
}
|
||||
|
||||
QString fixupEmptyJsonString(const QString &str)
|
||||
{
|
||||
return str.isEmpty() ? QStringLiteral("{}") : str;
|
||||
}
|
||||
|
||||
// Basic type toJson overloads
|
||||
QJsonValue toJson(int val)
|
||||
{
|
||||
return QJsonValue(val);
|
||||
}
|
||||
QJsonValue toJson(double val)
|
||||
{
|
||||
return QJsonValue(val);
|
||||
}
|
||||
QJsonValue toJson(qint64 val)
|
||||
{
|
||||
return QJsonValue(QString::number(val));
|
||||
}
|
||||
QJsonValue toJson(const std::string &val)
|
||||
{
|
||||
return QJsonValue(QString::fromStdString(val));
|
||||
}
|
||||
|
||||
// QPointF
|
||||
QJsonValue toJson(const QPointF &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("x"), QJsonValue(element.x()));
|
||||
obj.insert(QStringLiteral("y"), QJsonValue(element.y()));
|
||||
return QJsonValue(obj);
|
||||
}
|
||||
template<>
|
||||
QPointF fromJson(const QJsonValue &val)
|
||||
{
|
||||
QJsonObject obj = val.toObject();
|
||||
return QPointF(obj.value(QStringLiteral("x")).toDouble(), obj.value(QStringLiteral("y")).toDouble());
|
||||
}
|
||||
{% if need_point3d %}
|
||||
// QPoint3D
|
||||
QJsonValue toJson(const LtsUtils::QPoint3D &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("x"), QJsonValue(element.x()));
|
||||
obj.insert(QStringLiteral("y"), QJsonValue(element.y()));
|
||||
obj.insert(QStringLiteral("z"), QJsonValue(element.z()));
|
||||
return QJsonValue(obj);
|
||||
}
|
||||
template<>
|
||||
LtsUtils::QPoint3D fromJson(const QJsonValue &val)
|
||||
{
|
||||
QJsonObject obj = val.toObject();
|
||||
return LtsUtils::QPoint3D(obj.value(QStringLiteral("x")).toDouble(), obj.value(QStringLiteral("y")).toDouble(), obj.value(QStringLiteral("z")).toDouble());
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
//
|
||||
// Struct: {{ cpp_struct.name }}
|
||||
//
|
||||
QJsonObject toJson(const {{ cpp_struct.name }} &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
{% for row in cpp_struct.jsonMember %}
|
||||
{{ row.dbToJsonElement }};
|
||||
{% endfor %}
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
{{ cpp_struct.name }} fromJson(const QJsonValue &value)
|
||||
{
|
||||
const QJsonObject objElement(value.toObject());
|
||||
{{ cpp_struct.name }} element;
|
||||
|
||||
{% for row in cpp_struct.jsonMember %}
|
||||
{ {{ row.jsonElementToDb }}; } {% endfor %}
|
||||
|
||||
return element;
|
||||
}
|
||||
// {{ cpp_struct.name }} end
|
||||
{% endfor %}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for 'real' structures including insert/update/delete functions for db
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_db_structs.h
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
{% if need_point3d %}
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
{% endif %}
|
||||
{% if need_pgarray %}
|
||||
#include <LtsUtilsCore/pgarray.h>
|
||||
{% endif %}
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_enums.hpp>
|
||||
|
||||
{% for ext_service in ext_services.member %}
|
||||
#include <{{ ext_service.baseFilePath }}.hpp>
|
||||
{% endfor %}
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Database
|
||||
{
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
// {{ cpp_struct.name }}
|
||||
struct {{ cpp_struct.name }}
|
||||
{
|
||||
{% for m in cpp_struct.cppMember %}{{ m.cppType }} {{ m.cppMemberName }}{% if m.cppDefault %} = {{ m.cppDefault }}{% endif %};
|
||||
{% endfor %}
|
||||
};{% endfor %}
|
||||
|
||||
{% for data_struct in data_structs %}
|
||||
// read only struct {{ data_struct.name }}
|
||||
struct {{ data_struct.name }}
|
||||
{
|
||||
{% for m in data_struct.cppMember %}{{ m.cppType }} {{ m.cppMemberName }}{% if m.cppDefault %} = {{ m.cppDefault }}{% endif %};
|
||||
{% endfor %}
|
||||
};{% endfor %}
|
||||
|
||||
// converting DbStructs to/from JSON
|
||||
template<typename T>
|
||||
T fromJson(const QJsonValue &value);
|
||||
{% for cpp_struct in cpp_structs %}
|
||||
// {{ cpp_struct.name }}
|
||||
template <> {{ namespace_abbr_upper }}_{{ library_target }}_EXPORT {{ cpp_struct.name }} fromJson(const QJsonValue &value);
|
||||
{{ namespace_abbr_upper }}_{{ library_target }}_EXPORT QJsonObject toJson(const {{ cpp_struct.name }} &element);{% endfor %}
|
||||
|
||||
// vector of database struct to/from JSON-array
|
||||
template<typename T>
|
||||
QJsonArray toJson(const QVector<T> &dataVec)
|
||||
{
|
||||
QJsonArray arr;
|
||||
for (const T &data : dataVec)
|
||||
arr.append(QJsonValue(toJson(data)));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromJson(const QJsonArray &arr)
|
||||
{
|
||||
std::vector<T> dataVec;
|
||||
dataVec.reserve(arr.size());
|
||||
for (const QJsonValue &val : arr)
|
||||
dataVec.push_back(fromJson<T>(val));
|
||||
|
||||
return dataVec;
|
||||
}
|
||||
};// namespace Database
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,91 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Client Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-01-04
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dtc.h
|
||||
#pragma once
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}.hpp>
|
||||
|
||||
// Bring Core namespace types into scope for Interface namespace
|
||||
using namespace {{ namespace }};
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class {{ namespace_abbr_upper }}_COMMON_EXPORT Dtc : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
Dtc() = default;
|
||||
public:
|
||||
virtual ~Dtc() = default;
|
||||
|
||||
/**
|
||||
* Create a new instance for {{ namespace }}::Interface::Dtc.
|
||||
*/
|
||||
static std::shared_ptr<Dtc> create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
|
||||
/**
|
||||
* A unique identifier for this DTC
|
||||
*/
|
||||
static inline const char *identifier() { return "{{ namespace }}.Interface.Dtc"; }
|
||||
|
||||
/**
|
||||
* initialize this Dts instance with all data topic readers
|
||||
*/
|
||||
virtual bool enableAll(bool enable = true) = 0;
|
||||
/**
|
||||
* only initialize the specific reader (can be called instead enableAll())
|
||||
*/
|
||||
{% for dt in dataTopics.member %} {% if dt.dtcImpl %}
|
||||
virtual bool enable{{ dt.name }}(bool enable = true) = 0;
|
||||
virtual bool is{{ dt.name }}Enabled() const = 0;
|
||||
virtual bool waitForHistoricalData{{ dt.name }}(int timeoutMSec = -1) = 0;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
{% for cp in custom_dtc_procs %}
|
||||
// custom procs, body must be implemented by user
|
||||
virtual {{ cp.signature }} = 0;
|
||||
{% endfor %}
|
||||
|
||||
{% for dt in dataTopics.member %}
|
||||
public:
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
// {% if dt.key.name %}
|
||||
virtual QMap<{{ dt.key.cppType }}, ::{{ namespace }}::{{ dt.type }}> {{ dt.nameFlc }}s() = 0;
|
||||
virtual bool {{ dt.nameFlc }}s(const std::function<void(const ::{{ namespace }}::{{ dt.type }} &data)> &cb) = 0;
|
||||
// when the cb returns true, the loop is stopped (useful when searching for a specific topic)
|
||||
virtual bool {{ dt.nameFlc }}s(const std::function<bool(const ::{{ namespace }}::{{ dt.type }} &data)> &cb) = 0;
|
||||
virtual ::{{ namespace }}::{{ dt.type }} {{ dt.nameFlc }}({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}) = 0;
|
||||
{% else %}
|
||||
virtual ::{{ namespace }}::{{ dt.type }} {{ dt.nameFlc }}() = 0;
|
||||
{% endif %}
|
||||
Q_SIGNALS:
|
||||
void {{ dt.nameFlc }}Changed(const ::{{ namespace }}::{{ dt.type }} &data, DataModification modType);
|
||||
|
||||
{% endfor %}
|
||||
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,309 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Client Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-07
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dtc_impl.cpp
|
||||
|
||||
#include "{{ namespace_abbr }}_dtc_impl.h"
|
||||
{% if custom_dtc_procs %}
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dtc_impl_custom.h>
|
||||
{% endif %}
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <DDS/DTC/generic_dtc_impl.h>
|
||||
#include <DDS/Core/logger.h>
|
||||
#include <dds/core/cond/StatusCondition.hpp>
|
||||
#include <dds/core/cond/WaitSet.hpp>
|
||||
#include <unordered_map>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
using namespace NGL;
|
||||
using namespace Core;
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
// initializer function
|
||||
std::shared_ptr<Dtc> Dtc::create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
{
|
||||
// share only for main thread
|
||||
if (qApp->thread() != QThread::currentThread())
|
||||
{% if custom_dtc_procs %}
|
||||
return std::make_shared<DtcImplCustom>(ddsConnector);
|
||||
{% else %}
|
||||
return std::make_shared<DtcImpl>(ddsConnector);
|
||||
{% endif %}
|
||||
|
||||
static std::unordered_map<DDSConnector::DdsConnector*, std::weak_ptr<Dtc>> s_availableConnectors;
|
||||
|
||||
auto it = s_availableConnectors.find(ddsConnector.get());
|
||||
if (it != s_availableConnectors.end())
|
||||
{
|
||||
auto ret = it->second.lock();
|
||||
if (ret)
|
||||
return ret;
|
||||
s_availableConnectors.erase(it);
|
||||
}
|
||||
{% if custom_dtc_procs %}
|
||||
auto ret = std::make_shared<DtcImplCustom>(ddsConnector);
|
||||
{% else %}
|
||||
auto ret = std::make_shared<DtcImpl>(ddsConnector);
|
||||
{% endif %}
|
||||
s_availableConnectors.insert(std::make_pair(ddsConnector.get(), ret));
|
||||
return ret; // moved implicitly (C++17; explicit std::move on a local triggers -Wredundant-move)
|
||||
}
|
||||
|
||||
// DtcImpl
|
||||
DtcImpl::DtcImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: Dtc()
|
||||
, m_ddsConnector(ddsConnector)
|
||||
, m_logger(getLogger("Dtc"))
|
||||
{}
|
||||
|
||||
DtcImpl::~DtcImpl()
|
||||
{
|
||||
enableAll(false);
|
||||
}
|
||||
|
||||
bool DtcImpl::enableAll(bool enable)
|
||||
{ {% for dt in dataTopics.member %} {% if dt.dtcImpl %} {% if dt.autosubscribe %}
|
||||
if (!enable{{ dt.name }}(enable))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing data topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.dtcImpl %} {% if dt.key.name %}
|
||||
template <>
|
||||
struct TopicConstraints<{{ dt.type }}>
|
||||
{
|
||||
using KEY = {{ dt.key.cppType }};
|
||||
};
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
|
||||
|
||||
template <typename DTC>
|
||||
bool DtcImpl::checkEnabled(const DTC &dtc) const
|
||||
{
|
||||
if (!dtc)
|
||||
{
|
||||
using TOPIC = typename DtcConstraints<DTC>::TOPIC ;
|
||||
WARNING_LOG(m_logger) << "Error retrieving data topic "
|
||||
<< DDS::topic_type_name<TOPIC>::value() << " - not enabled";
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DTC>
|
||||
bool DtcImpl::waitForHistoricalData(DTC &dtc, int timeoutMSec)
|
||||
{
|
||||
if (!checkEnabled(dtc))
|
||||
return false;
|
||||
return dtc->waitForHistoricalData(timeoutMSec);
|
||||
}
|
||||
|
||||
template <typename T, typename K = typename TopicConstraints<T>::KEY>
|
||||
K getKey(const T &val);
|
||||
|
||||
template <typename DTC,
|
||||
typename T,
|
||||
typename K>
|
||||
QMap<K, T> DtcImpl::getAll(const DTC &dtc) const
|
||||
{
|
||||
if (!checkEnabled(dtc))
|
||||
return {};
|
||||
|
||||
QMap<K, T> retMap;
|
||||
for (const auto &sample : dtc->readAlive())
|
||||
retMap.insert(getKey(sample.data()), sample);
|
||||
|
||||
return retMap;
|
||||
}
|
||||
|
||||
template <typename DTC, typename C, typename T, typename K>
|
||||
T DtcImpl::getOne(const DTC &dtc, const C &cont, const K &key) const
|
||||
{
|
||||
if (!checkEnabled(dtc))
|
||||
return {};
|
||||
const auto it = cont.find(key);
|
||||
return it == cont.end() ? T() : it.value();
|
||||
}
|
||||
|
||||
template <typename DTC, typename C, typename T>
|
||||
bool DtcImpl::iterateAll(const DTC &dtc, const C &cont, const std::function<void(const T &data)> &cb) const
|
||||
{
|
||||
if (!checkEnabled(dtc))
|
||||
return false;
|
||||
|
||||
for (const auto &sample : cont)
|
||||
cb(sample);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DTC, typename C, typename T>
|
||||
bool DtcImpl::iterateUntil(const DTC &dtc, const C &cont, const std::function<bool(const T &data)> &cb) const
|
||||
{
|
||||
if (!checkEnabled(dtc))
|
||||
return false;
|
||||
|
||||
for (const auto &sample : cont)
|
||||
{
|
||||
if (cb(sample))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.dtcImpl %}
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
//
|
||||
bool DtcImpl::enable{{ dt.name }}(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (m_dtc{{ dt.name }})
|
||||
{
|
||||
INFO_LOG(m_logger) << "{{ dt.name }} already enabled!";
|
||||
return true;
|
||||
}
|
||||
m_dtc{{ dt.name }}.reset(m_ddsConnector->createDTC<DTC::{{ dt.name }}Impl>());
|
||||
assert(m_dtc{{ dt.name }}.get());
|
||||
m_dtc{{ dt.name }}->setSubscriberCallback([this](const {{ namespace }}::{{ dt.name }} &data, DataModification modType)
|
||||
{
|
||||
{{ dt.nameFlc }}ChangedInternal(data, modType);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dtc{{ dt.name }} = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DtcImpl::waitForHistoricalData{{ dt.name }}(int timeoutMSec)
|
||||
{
|
||||
|
||||
if (!is{{ dt.name }}Enabled())
|
||||
{
|
||||
enable{{ dt.name }}();
|
||||
DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ;
|
||||
}
|
||||
|
||||
if (!waitForHistoricalData(m_dtc{{ dt.name }}, timeoutMSec))
|
||||
return false;
|
||||
{% if dt.key.name %}
|
||||
m_{{ dt.nameFlc }}Cont = getAll(m_dtc{{ dt.name }});
|
||||
{% else %}
|
||||
auto samples = m_dtc{{ dt.name }}->readAlive();
|
||||
if (samples.length() == 0)
|
||||
return false;
|
||||
m_{{ dt.nameFlc }} = samples[samples.length() - 1].data();
|
||||
{% endif %}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% if dt.key.name %}
|
||||
template <>
|
||||
{{ dt.key.cppType }} getKey(const {{ dt.type }} &val)
|
||||
{
|
||||
return val.{{ dt.key.name }};
|
||||
}
|
||||
|
||||
QMap<{{ dt.key.cppType }},::{{ namespace }}::{{ dt.type }}> DtcImpl::{{ dt.nameFlc }}s()
|
||||
{
|
||||
if (!is{{ dt.name }}Enabled())
|
||||
{
|
||||
enable{{ dt.name }}();
|
||||
DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ;
|
||||
waitForHistoricalData{{ dt.name }}(10);
|
||||
}
|
||||
return m_{{ dt.nameFlc }}Cont;
|
||||
}
|
||||
|
||||
bool DtcImpl::{{ dt.nameFlc }}s(const std::function<void(const ::{{ namespace }}::{{ dt.type }} &data)> &cb)
|
||||
{
|
||||
if (!is{{ dt.name }}Enabled())
|
||||
{
|
||||
enable{{ dt.name }}();
|
||||
DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ;
|
||||
waitForHistoricalData{{ dt.name }}(10);
|
||||
}
|
||||
return iterateAll(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, cb);
|
||||
}
|
||||
|
||||
bool DtcImpl::{{ dt.nameFlc }}s(const std::function<bool(const ::{{ namespace }}::{{ dt.type }} &data)> &cb)
|
||||
{
|
||||
if (!is{{ dt.name }}Enabled())
|
||||
{
|
||||
enable{{ dt.name }}();
|
||||
DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ;
|
||||
waitForHistoricalData{{ dt.name }}(10);
|
||||
}
|
||||
return iterateUntil(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, cb);
|
||||
}
|
||||
|
||||
::{{ namespace }}::{{ dt.type }} DtcImpl::{{ dt.nameFlc }}({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }})
|
||||
{
|
||||
if (!is{{ dt.name }}Enabled())
|
||||
{
|
||||
enable{{ dt.name }}();
|
||||
DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ;
|
||||
waitForHistoricalData{{ dt.name }}(10);
|
||||
}
|
||||
return getOne(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, {{ dt.key.nameFlc }});
|
||||
}
|
||||
|
||||
void DtcImpl::{{ dt.nameFlc }}ChangedInternal(const ::{{ namespace }}::{{ dt.type }} &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
m_{{ dt.nameFlc }}Cont[getKey(data)] = data;
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_{{ dt.nameFlc }}Cont.remove(getKey(data));
|
||||
break;
|
||||
}
|
||||
emit {{ dt.nameFlc }}Changed(data, modType);
|
||||
}
|
||||
|
||||
{% else %}
|
||||
::{{ namespace }}::{{ dt.type }} DtcImpl::{{ dt.nameFlc }}()
|
||||
{
|
||||
return m_{{ dt.nameFlc }};
|
||||
}
|
||||
void DtcImpl::{{ dt.nameFlc }}ChangedInternal(const ::{{ namespace }}::{{ dt.type }} &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
m_{{ dt.nameFlc }} = data;
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_{{ dt.nameFlc }} = ::{{ namespace }}::{{ dt.type }}();
|
||||
break;
|
||||
}
|
||||
emit {{ dt.nameFlc }}Changed(data, modType);
|
||||
}
|
||||
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Client Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-07
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dtc_impl.h
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DTC/generic_dtc.h>
|
||||
#include <DDS/DTC/generic_dtc_impl.h>
|
||||
#include <DDS/Generic/generic_data_reader.h>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dtc.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dtc_types.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
using namespace NGL;
|
||||
|
||||
#if !defined(MAKE_SVC{{ namespace_abbr_upper }}CLIENT_LIB)
|
||||
#error "You are not allowed to include this file in your code!"
|
||||
#endif
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
template <typename UQ_DTC>
|
||||
struct DtcConstraints
|
||||
{
|
||||
using DTC = typename UQ_DTC::element_type;
|
||||
using TOPIC = typename DTC::TopicType;
|
||||
};
|
||||
|
||||
template <typename TOPIC>
|
||||
struct TopicConstraints
|
||||
{};
|
||||
|
||||
class DtcImpl {% if not custom_dtc_procs %}final {%endif %}: public Dtc
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DtcImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
~DtcImpl();
|
||||
|
||||
bool enableAll(bool enable = true) override;
|
||||
{% for dt in dataTopics.member %} {% if dt.dtcImpl %}
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
//
|
||||
public:
|
||||
bool enable{{ dt.name }}(bool enable = true) override final;
|
||||
bool is{{ dt.name }}Enabled() const override final { return m_dtc{{ dt.name }} != nullptr; }
|
||||
bool waitForHistoricalData{{ dt.name }}(int timeoutMSec = -1) override final;
|
||||
{% if dt.key.name %}
|
||||
QMap<{{ dt.key.cppType }}, ::{{ namespace }}::{{ dt.type }}> {{ dt.nameFlc }}s() override final;
|
||||
bool {{ dt.nameFlc }}s(const std::function<void(const ::{{ namespace }}::{{ dt.type }} &data)> &cb) override final;
|
||||
bool {{ dt.nameFlc }}s(const std::function<bool(const ::{{ namespace }}::{{ dt.type }} &data)> &cb) override final;
|
||||
::{{ namespace }}::{{ dt.type }} {{ dt.nameFlc }}({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}) override final;
|
||||
{% else %}
|
||||
::{{ namespace }}::{{ dt.type }} {{ dt.nameFlc }}() override final;
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
|
||||
private:
|
||||
template <typename DTC>
|
||||
bool checkEnabled(const DTC &dtc) const;
|
||||
template <typename DTC>
|
||||
bool waitForHistoricalData(DTC &dtc, int timeoutMSec);
|
||||
template <typename DTC,
|
||||
typename T = typename DtcConstraints<DTC>::TOPIC,
|
||||
typename K = typename TopicConstraints<T>::KEY>
|
||||
QMap<K, T> getAll(const DTC &dtc) const;
|
||||
template <typename DTC, typename C,
|
||||
typename T = typename DtcConstraints<DTC>::TOPIC,
|
||||
typename K = typename TopicConstraints<T>::KEY>
|
||||
T getOne(const DTC &dtc, const C &cont, const K &key) const;
|
||||
template <typename DTC, typename C,
|
||||
typename T = typename DtcConstraints<DTC>::TOPIC>
|
||||
bool iterateAll(const DTC &dtc, const C &cont, const std::function<void(const T &data)> &cb) const;
|
||||
template <typename DTC, typename C,
|
||||
typename T = typename DtcConstraints<DTC>::TOPIC>
|
||||
bool iterateUntil(const DTC &dtc, const C &cont, const std::function<bool(const T &data)> &cb) const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
|
||||
{% for dt in dataTopics.member %}
|
||||
{% if dt.dtcImpl %}
|
||||
void {{ dt.nameFlc }}ChangedInternal(const ::{{ namespace }}::{{ dt.type }} &data, DataModification modType);
|
||||
std::unique_ptr<DTC::{{ dt.name }}> m_dtc{{ dt.name }}; {% if dt.key.name %}
|
||||
QMap<{{ dt.key.cppType }}, ::{{ namespace }}::{{ dt.type }}> m_{{ dt.nameFlc }}Cont; {% else %}
|
||||
::{{ namespace }}::{{ dt.type }} m_{{ dt.nameFlc }};
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
signals:
|
||||
{% for dt in dataTopics.member %}
|
||||
{% if dt.dtcImpl %}
|
||||
void {{ dt.nameFlc }}Changed(const ::{{ namespace }}::{{ dt.type }} &data, DataModification modType);
|
||||
{% endif %} {% endfor %}
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Server Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-01-05
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dts.h
|
||||
#pragma once
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}.hpp>
|
||||
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dts
|
||||
{
|
||||
protected:
|
||||
Dts() = default;
|
||||
public:
|
||||
virtual ~Dts() = default;
|
||||
|
||||
/**
|
||||
* Create a new instance for {{ namespace }}::Interface::Dts.
|
||||
* The caller takes ownership of the returned instance
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_SERVER_EXPORT static std::shared_ptr<Dts> create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
|
||||
/**
|
||||
* A unique identifier for this DTS
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_SERVER_EXPORT static inline const char *identifier() { return "{{ namespace }}.Interface.Dts"; }
|
||||
|
||||
/**
|
||||
* initialize this Dts instance with all data topic writers
|
||||
*/
|
||||
virtual bool enableAll(bool enable = true) = 0;
|
||||
/**
|
||||
* only initialize the specific writer (can be called instead enableAll())
|
||||
*/
|
||||
{% for dt in dataTopics.member %} {% if dt.dtsImpl %}
|
||||
virtual bool enable{{ dt.name }}(bool enable = true) = 0;
|
||||
virtual bool is{{ dt.name }}Enabled() const = 0;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
{% for dt in dataTopics.member %}
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
//
|
||||
virtual bool publish(const {{ namespace }}::{{ dt.type }} &data) = 0;
|
||||
{% if dt.key.name %}
|
||||
virtual bool remove{{ dt.name }}ByKey({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}, bool errorMsgIfSampleDoesNotExists = true) = 0;
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Server Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-07
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dts_impl.cpp
|
||||
#include "{{ namespace_abbr }}_dts_impl.h"
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
// initializer function
|
||||
std::shared_ptr<Dts> Dts::create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
{
|
||||
return std::make_shared<DtsImpl>(ddsConnector);
|
||||
}
|
||||
|
||||
// DtsImpl
|
||||
DtsImpl::DtsImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: Dts()
|
||||
, m_ddsConnector(ddsConnector)
|
||||
, m_logger(getLogger("Dts"))
|
||||
{}
|
||||
|
||||
DtsImpl::~DtsImpl()
|
||||
{
|
||||
enableAll(false);
|
||||
}
|
||||
|
||||
bool DtsImpl::enableAll(bool enable)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.dtsImpl %}
|
||||
if (!enable{{ dt.name }}(enable))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error initializing data topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
{% endif %} {% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.dtsImpl %}
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
//
|
||||
bool DtsImpl::enable{{ dt.name }}(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (m_dts{{ dt.name }})
|
||||
{
|
||||
INFO_LOG(m_logger) << "{{ ft.name }} already enabled!";
|
||||
return true;
|
||||
}
|
||||
m_dts{{ dt.name }}.reset(m_ddsConnector->createDTS<DTS::{{ dt.name }}Impl>());
|
||||
assert(m_dts{{ dt.name }}.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dts{{ dt.name }} = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DtsImpl::publish(const {{ namespace }}::{{ dt.type }} &data)
|
||||
{
|
||||
if (!m_dts{{ dt.name }})
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error publishing data topic {{ dt.name }} - not enabled";
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
return m_dts{{ dt.name }}->write(data);
|
||||
}
|
||||
|
||||
{% if dt.key.name %}
|
||||
bool DtsImpl::remove{{ dt.name }}ByKey({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}, bool errorMsgIfSampleDoesNotExists)
|
||||
{
|
||||
if (!m_dts{{ dt.name }})
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error removing data topic {{ dt.name }} - not enabled";
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
{{ namespace }}::{{ dt.name }} data;
|
||||
// rtiddsgen -stl generates plain public data members, so the key is
|
||||
// assigned directly instead of the old setter call data.{{ dt.key.name }}(...).
|
||||
data.{{ dt.key.name }} = {{ dt.key.name }};
|
||||
return m_dts{{ dt.name }}->remove(data, errorMsgIfSampleDoesNotExists);
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* {{ namespace_abbr_upper }} Data Topic Server Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-04-07
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_dts_impl.h
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dts.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dts_types.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#if !defined(MAKE_SVC{{ namespace_abbr_upper }}SERVER_LIB)
|
||||
#error "You are not allowed to include this file in your code!"
|
||||
#endif
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class DtsImpl final : public Dts
|
||||
{
|
||||
public:
|
||||
explicit DtsImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
~DtsImpl();
|
||||
|
||||
bool enableAll(bool enable = true) override;
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.dtsImpl %}
|
||||
//
|
||||
// Data Topic '{{ dt.name }}'
|
||||
//
|
||||
bool enable{{ dt.name }}(bool enable = true) override;
|
||||
bool is{{ dt.name }}Enabled() const override final { return m_dts{{ dt.name }} != nullptr; }
|
||||
bool publish(const {{ namespace }}::{{ dt.type }} &data) override;
|
||||
{% if dt.key.name %}
|
||||
bool remove{{ dt.name }}ByKey({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}, bool errorMsgIfSampleDoesNotExists = true) override;
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
{% for dt in dataTopics.member %} {% if dt.dtsImpl %}
|
||||
std::unique_ptr<DTS::{{ dt.name }}> m_dts{{ dt.name }};
|
||||
{% endif %} {% endfor %}
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Template for idl struct definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-19
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_enums.idl
|
||||
#ifndef {{ namespace_abbr }}_enums_idl_included
|
||||
#define {{ namespace_abbr }}_enums_idl_included
|
||||
|
||||
//@copy #include <{{ include_prefix }}/{{ namespace_abbr }}_export.h> // #define NDDSUSERDllExport for linux
|
||||
|
||||
|
||||
module {{ namespace }}
|
||||
{
|
||||
{% for idl_enum in idl_enums %}
|
||||
enum {{ idl_enum.name }}
|
||||
{
|
||||
{% for idl_member in idl_enum.member %}
|
||||
{{ idl_member.key }} = {{ idl_member.value }}{% if not forloop.last %},{% endif %} {% endfor %}
|
||||
};
|
||||
|
||||
{% endfor %}
|
||||
|
||||
}; // module {{ namespace }}
|
||||
|
||||
#endif
|
||||
{% endautoescape %}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Client interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_ftc.h
|
||||
#pragma once
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}.hpp>
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Ftc
|
||||
{
|
||||
protected:
|
||||
Ftc() = default;
|
||||
public:
|
||||
virtual ~Ftc() = default;
|
||||
|
||||
/**
|
||||
* Create a new instance for {{ namespace }}::Interface::Ftc.
|
||||
* The caller takes ownership of the returned instance!
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_CLIENT_EXPORT static std::shared_ptr<Ftc> create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, bool forceCreate = false);
|
||||
|
||||
/**
|
||||
* A unique identifier for this FTC
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_CLIENT_EXPORT static inline const char *identifier() { return "{{ namespace }}.Interface.Ftc"; }
|
||||
|
||||
/**
|
||||
* initialize this Ftc instance with all function topic clients
|
||||
*/
|
||||
virtual bool enableAll(bool enable = true) = 0;
|
||||
/**
|
||||
* only initialize the specific function topic client (can be called instead enableAll())
|
||||
*/
|
||||
{% for ft in functionTopics.member %}
|
||||
virtual bool enable{{ ft.name }}(bool enable = true) = 0;
|
||||
virtual bool is{{ ft.name }}Enabled() const = 0;
|
||||
{% endfor %}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// Function Topic '{{ ft.name }}'
|
||||
//
|
||||
class {{ ft.replyHandler }}
|
||||
{
|
||||
public:
|
||||
{{ ft.replyHandler }}() = default;
|
||||
virtual ~{{ ft.replyHandler }}() = default;
|
||||
virtual void {{ ft.onReply }}(const {{ ft.replyTypeFro }} &reply) = 0;
|
||||
};
|
||||
virtual int64_t {{ ft.requestFlc }}(const {{ ft.requestType }} &request, {{ ft.replyHandler }} *handler) = 0;
|
||||
virtual int64_t {{ ft.requestFlc }}(const {{ ft.requestType }} &request, const std::function<void(const {{ ft.replyTypeFro }}&)> &cb) = 0;
|
||||
virtual {% if ft.isCoreFt %}int32_t{% else %}{{ ft.replyTypeFro }}{% endif %} {{ ft.requestFlc }}(const {{ ft.requestType }} &request) noexcept(false) = 0; // await
|
||||
virtual int64_t last{{ ft.request }}UniqueId() const = 0;
|
||||
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,254 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Client implementation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_ftc_impl.cpp
|
||||
#include "{{ namespace_abbr }}_ftc_impl.h"
|
||||
|
||||
#include <DDS/FTC/generic_ftc_impl.h>
|
||||
#include <LtsUtilsCore/await.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
//using namespace std::literals::chrono_literals;
|
||||
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
// initializer function
|
||||
Q_DECL_EXPORT std::shared_ptr<Ftc> Ftc::create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, bool forceCreate)
|
||||
{
|
||||
// share only for main thread
|
||||
if (qApp->thread() != QThread::currentThread() || forceCreate)
|
||||
return std::make_shared<FtcImpl>(ddsConnector);
|
||||
|
||||
static std::unordered_map<DDSConnector::DdsConnector*, std::weak_ptr<Ftc>> s_availableConnectors;
|
||||
|
||||
auto it = s_availableConnectors.find(ddsConnector.get());
|
||||
if (it != s_availableConnectors.end())
|
||||
{
|
||||
auto ret = it->second.lock();
|
||||
if (ret)
|
||||
return ret;
|
||||
s_availableConnectors.erase(it);
|
||||
}
|
||||
|
||||
auto ret = std::make_shared<FtcImpl>(ddsConnector);
|
||||
s_availableConnectors.insert(std::make_pair(ddsConnector.get(), ret));
|
||||
return ret; // moved implicitly (C++17; explicit std::move on a local triggers -Wredundant-move)
|
||||
}
|
||||
|
||||
// FtcImpl
|
||||
FtcImpl::FtcImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: Ftc()
|
||||
, m_ddsConnector(ddsConnector)
|
||||
, m_logger(getLogger("Ftc"))
|
||||
{}
|
||||
|
||||
bool FtcImpl::enableAll(bool enable)
|
||||
{ {% for ft in functionTopics.member %}
|
||||
if (!enable{{ ft.name }}(enable))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing function topic {{ ft.name }}";
|
||||
return false;
|
||||
}
|
||||
{% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
FtcImpl::~FtcImpl()
|
||||
{
|
||||
enableAll(false);
|
||||
}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
// Function Topic '{{ ft.name }}'
|
||||
bool FtcImpl::enable{{ ft.name }}(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (m_ftc{{ ft.name }})
|
||||
{
|
||||
INFO_LOG(m_logger) << "{{ ft.name }} already enabled!";
|
||||
return true;
|
||||
}
|
||||
m_ftc{{ ft.name }}.reset(
|
||||
m_ddsConnector->createFTC<FTC::{{ ft.name }}>(this));
|
||||
assert(m_ftc{{ ft.name }}.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ftc{{ ft.name }} = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
template<typename T>
|
||||
static T buildErrorReason(int reason, int requestId)
|
||||
{
|
||||
std::string errString;
|
||||
std::vector<std::string> errArgs;
|
||||
switch (reason)
|
||||
{
|
||||
case 1:
|
||||
errString = tr_lts("dds", "Service could not handle request");
|
||||
break;
|
||||
case 3:
|
||||
errString = tr_lts("dds", "Timeout while waiting for answer from server");
|
||||
break;
|
||||
default:
|
||||
errString = tr_lts("dds", "Unknown error reason: %1");
|
||||
errArgs.push_back(std::to_string(reason));
|
||||
break;
|
||||
}
|
||||
|
||||
T reply;
|
||||
reply.id = requestId;
|
||||
reply.errorString = errString;
|
||||
reply.errorParams = errArgs;
|
||||
return reply;
|
||||
}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// {{ ft.name }}
|
||||
//
|
||||
int64_t FtcImpl::{{ ft.requestFlc }}(const {{ ft.requestType }} &request, {{ ft.replyHandler }} *handler)
|
||||
{
|
||||
return {{ ft.requestFlc }}(request, [ handler ](const {{ ft.replyTypeFro }} &reply) { if (handler) handler->{{ ft.onReply }}(reply); });
|
||||
}
|
||||
|
||||
int64_t FtcImpl::{{ ft.requestFlc }}(const {{ ft.requestType }} &request, const std::function<void(const {{ ft.replyTypeFro }}&)> &cb)
|
||||
{
|
||||
if (!m_ftc{{ ft.name }})
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error requesting function topic {{ ft.name }} - not enabled";
|
||||
Q_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const slotReply = SLOT({{ ft.onReply }}({{ namespace }}::{{ ft.reply }},int,bool));
|
||||
static const char * const slotError = SLOT({{ ft.onError }}(int,int,int));
|
||||
int uniqueId = 0;
|
||||
if (!m_ftc{{ ft.name }}->requestDataClassic(request, slotReply, slotError, uniqueId))
|
||||
return 0;
|
||||
|
||||
m_{{ ft.replyHandlerFlc }}[uniqueId] = cb;
|
||||
// first 16 hex bytes from Sha3_512 hash for '{{ ft.name }}' converted to an int64
|
||||
m_last{{ ft.request }}UniqueId = uniqueId + {{ ft.replyHandlerHash }};
|
||||
return m_last{{ ft.request }}UniqueId;
|
||||
}
|
||||
|
||||
// NOTE: do not use if you call an FTC which returns an id while also containing an error as "error doesn't mean that the service might not reply with an id - so always take the id"
|
||||
{% if ft.isCoreFt %}int32_t{% else %}{{ ft.replyTypeFro }}{% endif %} FtcImpl::{{ ft.requestFlc }}(const {{ ft.requestType }} &request) noexcept(false)
|
||||
{
|
||||
if (!m_ftc{{ ft.name }})
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
throw std::runtime_error("Error requesting function topic {{ ft.name }} - not enabled");
|
||||
}
|
||||
|
||||
auto *requestWatcher = new Request2();
|
||||
auto future = m_ftc{{ ft.name }}->requestDataModern(request, requestWatcher);
|
||||
|
||||
m_currentlyOpen_{{ ft.requestFlc }}Requests++;
|
||||
//fprintf(stderr, "{{ ft.requestFlc }}: waiting for reply... (currently open requests: %d)\n", m_currentlyOpen_{{ ft.requestFlc }}Requests);
|
||||
LtsUtils::await(requestWatcher, &Request2::finished, true); // blocks until request has reply or failed
|
||||
m_currentlyOpen_{{ ft.requestFlc }}Requests--;
|
||||
//fprintf(stderr, "{{ ft.requestFlc }}: request done!\n");
|
||||
|
||||
// the generic ftc impl's 'requestDataModern' + 'exec()' guarantees that calling 'future.get()' will not result in a 'wait()' call by 'get()' - but we should still check!
|
||||
switch (future.wait_for(std::chrono::seconds(1)))
|
||||
{
|
||||
case std::future_status::deferred:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
// fprintf(stderr, "{{ ft.requestFlc }}: deferred...\n");
|
||||
break;
|
||||
}
|
||||
case std::future_status::timeout:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
// fprintf(stderr, "{{ ft.requestFlc }}: future timeout!\n");
|
||||
throw std::runtime_error("Future timeout!");
|
||||
}
|
||||
case std::future_status::ready:
|
||||
{
|
||||
// fprintf(stderr, "{{ ft.requestFlc }}: ready\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{% if ft.isCoreFt %}
|
||||
const auto _reply = future.get(); // throws if exception set
|
||||
|
||||
Core::FunctionReplyObject fro(
|
||||
{% for rp in ft.replyParams %} _reply.{{ rp.nameGetter }}{% if not forloop.last %},{% endif %} {% endfor %}
|
||||
);
|
||||
fro.setUniqueId(m_last{{ ft.request }}UniqueId);
|
||||
|
||||
if (fro.error())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "FTC call failed: " << fro.translated();
|
||||
throw std::runtime_error(fro.translated().toStdString().c_str());
|
||||
}
|
||||
|
||||
const auto reply = fro.id();
|
||||
{% else %}
|
||||
const auto reply = future.get(); // throws if exception set
|
||||
{% endif %}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void FtcImpl::{{ ft.onReply }}(const {{ namespace }}::{{ ft.reply }} &reply, int uniqueId, bool bRequestFinished)
|
||||
{
|
||||
auto it = m_{{ ft.replyHandlerFlc }}.find(uniqueId);
|
||||
if (it == m_{{ ft.replyHandlerFlc }}.end())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error replying function topic {{ ft.name }} - no replyHandler";
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto cb = it.value();
|
||||
if (bRequestFinished)
|
||||
m_{{ ft.replyHandlerFlc }}.erase(it);
|
||||
if (!cb)
|
||||
return;
|
||||
|
||||
m_last{{ ft.request }}UniqueId = uniqueId + {{ ft.replyHandlerHash }};
|
||||
{% if ft.isCoreFt %}
|
||||
Core::FunctionReplyObject fro(
|
||||
{% for rp in ft.replyParams %}
|
||||
reply.{{ rp.nameGetter }}{% if not forloop.last %},{% endif %} {% endfor %}
|
||||
);
|
||||
fro.setUniqueId(m_last{{ ft.request }}UniqueId);
|
||||
cb(fro);
|
||||
{% else %}
|
||||
cb(reply);
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
void FtcImpl::{{ ft.onError }}(int reason, int uniqueId, int requestId)
|
||||
{
|
||||
{{ ft.onReply }}(buildErrorReason<{{ namespace }}::{{ ft.reply }}>(reason, requestId), uniqueId, true);
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Client implementation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_ftc_impl.h
|
||||
#pragma once
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_ftc.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_ftc_types.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
#include <DDS/FTC/abstract_requester.h>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
#if !defined(MAKE_SVC{{ namespace_abbr_upper }}CLIENT_LIB)
|
||||
#error "You are not allowed to include this file in your code!"
|
||||
#endif
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class FtcImpl final : public QObject, public Ftc
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FtcImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
~FtcImpl();
|
||||
|
||||
bool enableAll(bool enable = true) override;
|
||||
{% for ft in functionTopics.member %}
|
||||
bool enable{{ ft.name }}(bool enable = true) override;
|
||||
bool is{{ ft.name }}Enabled() const override { return m_ftc{{ ft.name }} != nullptr; }
|
||||
{% endfor %}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// Function Topic '{{ ft.name }}'
|
||||
//
|
||||
|
||||
/// Classic request:
|
||||
public:
|
||||
int64_t {{ ft.requestFlc }}(const {{ ft.requestType }} &request, {{ ft.replyHandler }} *handler) override; // returns the uniqueId used for this request
|
||||
int64_t {{ ft.requestFlc }}(const {{ ft.requestType }} &request, const std::function<void(const {{ ft.replyTypeFro }}&)> &cb) override; // returns the uniqueId used for this request
|
||||
int64_t last{{ ft.request }}UniqueId() const override { return m_last{{ ft.request }}UniqueId; }
|
||||
|
||||
private Q_SLOTS:
|
||||
void {{ ft.onReply }}(const {{ namespace }}::{{ ft.reply }} &reply, int uniqueId, bool bRequestFinished);
|
||||
void {{ ft.onError }}(int reason, int uniqueId, int requestId);
|
||||
|
||||
private:
|
||||
QHash<int, std::function<void(const {{ ft.replyTypeFro }}&)>> m_{{ ft.replyHandlerFlc }};
|
||||
int64_t m_last{{ ft.request }}UniqueId = -1;
|
||||
|
||||
/// Modern request:
|
||||
public:
|
||||
/* Executes the request and blocks (enters Qt's event loop) until the reply has arrived.
|
||||
* NOTE: If reply has a FunctionReplyWithState, this function only returns the first reply and returns.
|
||||
{% if ft.isCoreFt %} * Returns the id of the FunctionReply.{% endif %}*/
|
||||
{% if ft.isCoreFt %}int32_t{% else %}{{ ft.replyTypeFro }}{% endif %} {{ ft.requestFlc }}(const {{ ft.requestType }} &request) noexcept(false) override;
|
||||
|
||||
private:
|
||||
int m_currentlyOpen_{{ ft.requestFlc }}Requests { 0 };
|
||||
std::unique_ptr<FTC::{{ ft.name }}> m_ftc{{ ft.name }};
|
||||
{% endfor %}
|
||||
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Server interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_fts.h
|
||||
#pragma once
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}.hpp>
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Fts
|
||||
{
|
||||
protected:
|
||||
Fts() = default;
|
||||
public:
|
||||
virtual ~Fts() = default;
|
||||
|
||||
/**
|
||||
* Create a new instance for {{ namespace }}::Interface::Dts.
|
||||
* The caller takes ownership of the returned instance
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_SERVER_EXPORT static std::shared_ptr<Fts> create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
|
||||
/**
|
||||
* A unique identifier for this FTC
|
||||
*/
|
||||
{{ namespace_abbr_upper }}_SERVER_EXPORT static inline const char *identifier() { return "{{ namespace }}.Interface.Fts"; }
|
||||
|
||||
/**
|
||||
* initialize this Fts instance with all function topic servers
|
||||
*/
|
||||
virtual bool enableAll(bool enable = true) = 0;
|
||||
/**
|
||||
* only initialize the specific function topic writer (can be called instead enableAll())
|
||||
*/
|
||||
{% for ft in functionTopics.member %}
|
||||
virtual bool enable{{ ft.name }}(bool enable = true) = 0;
|
||||
virtual bool is{{ ft.name }}Enabled() const = 0;
|
||||
{% endfor %}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// Function Topic '{{ ft.name }}'
|
||||
//
|
||||
class {{ ft.requestHandler }}
|
||||
{
|
||||
public:
|
||||
explicit {{ ft.requestHandler }}(const std::shared_ptr<Fts> &fts)
|
||||
: m_fts(fts)
|
||||
{
|
||||
if (fts)
|
||||
fts->set{{ ft.requestHandler }}(this);
|
||||
}
|
||||
virtual ~{{ ft.requestHandler }}()
|
||||
{
|
||||
auto sp = m_fts.lock();
|
||||
if (sp)
|
||||
sp->set{{ ft.requestHandler }}(nullptr);
|
||||
}
|
||||
virtual void {{ ft.onRequest }}(const rti::core::SampleIdentity &cookie,
|
||||
const {{ ft.requestType }} &request) = 0;
|
||||
private:
|
||||
std::weak_ptr<Fts> m_fts;
|
||||
};
|
||||
virtual void set{{ ft.requestHandler }}({{ ft.requestHandler }} *handler) = 0;
|
||||
virtual bool {{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const {{ ft.replyType }} &reply) = 0;
|
||||
{% if ft.isCoreFt %}
|
||||
virtual bool {{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const Core::FunctionReplyObject &replyObject) = 0;
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,114 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Server implementation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_fts_impl.cpp
|
||||
#include "{{ namespace_abbr }}_fts_impl.h"
|
||||
#include <DDS/FTS/generic_fts_impl.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
// initializer function
|
||||
std::shared_ptr<Fts> Fts::create(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
{
|
||||
return std::make_shared<FtsImpl>(ddsConnector);
|
||||
}
|
||||
|
||||
// FtsImpl
|
||||
FtsImpl::FtsImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: Fts()
|
||||
, m_ddsConnector(ddsConnector)
|
||||
, m_logger(getLogger("Fts"))
|
||||
{}
|
||||
|
||||
FtsImpl::~FtsImpl()
|
||||
{
|
||||
enableAll(false);
|
||||
}
|
||||
|
||||
bool FtsImpl::enableAll(bool enable)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "FtsImpl::enableAll(" << (enable ? "true" : "false") << ")";
|
||||
{% for ft in functionTopics.member %}
|
||||
if (!enable{{ ft.name }}(enable))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing function topic {{ ft.name }}";
|
||||
return false;
|
||||
}
|
||||
{% endfor %}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// Function Topic '{{ ft.name }}'
|
||||
//
|
||||
bool FtsImpl::enable{{ ft.name }}(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (m_fts{{ ft.name }})
|
||||
{
|
||||
INFO_LOG(m_logger) << "{{ ft.name }} already enabled!";
|
||||
return true;
|
||||
}
|
||||
m_fts{{ ft.name }}.reset(m_ddsConnector->createFTS<FTS::{{ ft.name }}>());
|
||||
assert(m_fts{{ ft.name }}.get());
|
||||
m_fts{{ ft.name }}->setSubscriberCallback([this] (const rti::core::SampleIdentity &identity, const {{ namespace }}::{{ ft.request }} &request) { this->{{ ft.onRequest }}(identity, request); });
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fts{{ ft.name }}.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FtsImpl::{{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const {{ ft.replyType }} &reply)
|
||||
{
|
||||
if (!m_fts{{ ft.name }})
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error publishing function topic {{ dt.name }} - not enabled";
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_fts{{ ft.name }}->sendReply(cookie, reply);
|
||||
}
|
||||
{% if ft.isCoreFt %}
|
||||
bool FtsImpl::{{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
return {{ ft.replyFlc }}(cookie, {{ ft.replyType }}(replyObject.id(), replyObject.str(), replyObject.args(), replyObject.additionalInfo()));
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
|
||||
void FtsImpl::set{{ ft.requestHandler }}({{ ft.requestHandler }} *handler)
|
||||
{
|
||||
m_{{ ft.requestHandlerFlc }} = handler;
|
||||
}
|
||||
|
||||
void FtsImpl::{{ ft.onRequest }}(const rti::core::SampleIdentity &cookie,
|
||||
const {{ namespace }}::{{ ft.request }} &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "{{ ft.onRequest }}";
|
||||
if (!m_{{ ft.requestHandlerFlc }})
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Incoming {{ ft.request }} without registered handler!";
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_{{ ft.requestHandlerFlc }}->{{ ft.onRequest }}(cookie, request);
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* {{ namespace }} Function Topic Server implementation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_fts_impl.h
|
||||
#pragma once
|
||||
#include <DDS/FTS/generic_fts_impl.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_fts.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_fts_types.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <QObject>
|
||||
|
||||
#if !defined(MAKE_SVC{{ namespace_abbr_upper }}SERVER_LIB)
|
||||
#error "You are not allowed to include this file in your code!"
|
||||
#endif
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class FtsImpl final : public QObject, public Fts
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FtsImpl(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
~FtsImpl();
|
||||
|
||||
bool enableAll(bool enable = true) override;
|
||||
|
||||
{% for ft in functionTopics.member %}
|
||||
//
|
||||
// {{ ft.name }}
|
||||
//
|
||||
public:
|
||||
bool enable{{ ft.name }}(bool enable = true) override;
|
||||
bool is{{ ft.name }}Enabled() const override { return m_fts{{ ft.name }} != nullptr && m_{{ ft.requestHandlerFlc }} != nullptr; }
|
||||
bool {{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const {{ ft.replyType }} &reply) override;
|
||||
{% if ft.isCoreFt %}
|
||||
bool {{ ft.replyFlc }}(const rti::core::SampleIdentity &cookie, const Core::FunctionReplyObject &replyObject) override;
|
||||
{% endif %}
|
||||
|
||||
void set{{ ft.requestHandler }}({{ ft.requestHandler }} *handler) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void {{ ft.onRequest }}(const rti::core::SampleIdentity &cookie,
|
||||
const {{ namespace }}::{{ ft.request }} &request);
|
||||
private:
|
||||
std::unique_ptr<FTS::{{ ft.name }}> m_fts{{ ft.name }};
|
||||
{{ ft.requestHandler }} *m_{{ ft.requestHandlerFlc }} = nullptr;
|
||||
|
||||
{% endfor %}
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
} // namespace Interface
|
||||
} // namespace {{ namespace }}
|
||||
{% endautoescape %}
|
||||
@@ -1,172 +0,0 @@
|
||||
/**
|
||||
* Json <-> DDS conversion routines
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-11-30
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_json.cpp
|
||||
|
||||
#include "{{ namespace_abbr }}_json.h"
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
#include <dds/core/String.hpp>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
template<>
|
||||
int fromJson(const QJsonValue &val, type<int>)
|
||||
{
|
||||
return val.toInt();
|
||||
}
|
||||
|
||||
template<>
|
||||
double fromJson(const QJsonValue &val, type<double>)
|
||||
{
|
||||
return val.toDouble();
|
||||
}
|
||||
|
||||
template<>
|
||||
qint64 fromJson(const QJsonValue &val, type<qint64>)
|
||||
{
|
||||
return val.toString().toLongLong();
|
||||
}
|
||||
|
||||
QJsonValue toJson(int vec)
|
||||
{
|
||||
return QJsonValue(vec);
|
||||
}
|
||||
QJsonValue toJson(double vec)
|
||||
{
|
||||
return QJsonValue(vec);
|
||||
}
|
||||
QJsonValue toJson(qint64 vec)
|
||||
{
|
||||
return QJsonValue(QString::number(vec));
|
||||
}
|
||||
// IDL 64-bit integers map to int64_t, which is 'long' on LP64 and therefore
|
||||
// distinct from qint64 ('long long'); without this overload the generic
|
||||
// toJson(std::vector<T>) is ambiguous for sequence<int64_t> members.
|
||||
QJsonValue toJson(long vec)
|
||||
{
|
||||
return QJsonValue(QString::number(vec));
|
||||
}
|
||||
template<>
|
||||
long fromJson(const QJsonValue &val, type<long>)
|
||||
{
|
||||
return val.toString().toLong();
|
||||
}
|
||||
|
||||
// std::string
|
||||
QJsonValue toJson(const std::string &element)
|
||||
{
|
||||
return QJsonValue(QString::fromStdString(element));
|
||||
}
|
||||
template<>
|
||||
std::string fromJson(const QJsonValue &val, type<std::string>)
|
||||
{
|
||||
return val.toString().toStdString();
|
||||
}
|
||||
|
||||
// std::vector<T>
|
||||
template<typename T>
|
||||
QJsonArray toJson(const std::vector<T> &vec)
|
||||
{
|
||||
QJsonArray arr;
|
||||
for (const auto &element : vec)
|
||||
arr.push_back(toJson(element));
|
||||
return arr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromJson(const QJsonValue &val, type<std::vector<T>>)
|
||||
{
|
||||
std::vector<T> ret;
|
||||
if (!val.isArray())
|
||||
return ret;
|
||||
const QJsonArray array(val.toArray());
|
||||
ret.reserve(array.size());
|
||||
for(int i = 0; i < array.size(); ++i)
|
||||
ret.push_back(fromJson(array.at(i), type<T>{}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// dds::core:vector<uint8_t> (bytestream)
|
||||
inline QJsonValue toJson(const std::vector<uint8_t> &element)
|
||||
{
|
||||
return QJsonValue(QString::fromLatin1(QByteArray::fromRawData(reinterpret_cast<const char *>(&element.at(0)),
|
||||
static_cast<int>(element.size())).toBase64()));
|
||||
}
|
||||
template<>
|
||||
std::vector<uint8_t> fromJson(const QJsonValue &val, type<std::vector<uint8_t>>)
|
||||
{
|
||||
const QByteArray ba(QByteArray::fromBase64(val.toString().toLatin1()));
|
||||
return LtsUtils::convert<std::vector<uint8_t>>(ba);
|
||||
}
|
||||
|
||||
{% for dt in jsonTopics %}
|
||||
// {{ dt.name }}
|
||||
QJsonObject toJson(const {{ dt.name }} &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
{% for row in dt.cppMember %}
|
||||
{{ row.ddsToJsonElement }};
|
||||
{% endfor %}
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
{{ dt.name }} fromJson(const QJsonValue &value, type<{{ dt.name }}>)
|
||||
{
|
||||
const QJsonObject objElement(value.toObject());
|
||||
{{ dt.name }} element;
|
||||
|
||||
{% for row in dt.cppMember %}
|
||||
{ {{ row.jsonElementToDds }}; } {% endfor %}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
//
|
||||
// extensions to support sequence of seqence of Non-POD :
|
||||
//
|
||||
|
||||
QJsonValue toJson(const std::vector <{{ dt.name }} > &element)
|
||||
{
|
||||
|
||||
if (element.size() == 0)
|
||||
return QJsonValue();
|
||||
QJsonArray array;
|
||||
for(size_t i = 0; i < element.size(); ++i)
|
||||
array.push_back(toJson(element.at(i)));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector<{{ dt.name }}> fromJson(const QJsonValue &value, type< std::vector <{{ dt.name }} > >)
|
||||
{
|
||||
std::vector < {{ dt.name }} > ret;
|
||||
if (value.isNull())
|
||||
return ret;
|
||||
if (!value.isArray())
|
||||
return ret;
|
||||
|
||||
const QJsonArray array = value.toArray();
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<{{ dt.name }}>{}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Json <-> DDS conversion routines
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2017-11-30
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_json.h
|
||||
#pragma once
|
||||
|
||||
#include "{{ namespace_abbr }}.hpp"
|
||||
#include "{{ namespace_abbr }}_export.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
template<typename T>
|
||||
struct type{};
|
||||
|
||||
template<typename T>
|
||||
T fromJson(const QJsonValue &val, type<T>);
|
||||
|
||||
template<typename T>
|
||||
T fromJson(const QJsonValue &val)
|
||||
{
|
||||
return fromJson(val, type<T>{});
|
||||
}
|
||||
|
||||
{% for dt in jsonTopics %}
|
||||
// {{ dt.name }}
|
||||
{{ namespace_abbr_upper }}_COMMON_EXPORT QJsonObject toJson(const {{ dt.name }} &element);
|
||||
template<> {{ namespace_abbr_upper }}_COMMON_EXPORT {{ dt.name }} fromJson(const QJsonValue &val, type<{{ dt.name }}>);
|
||||
{{ namespace_abbr_upper }}_COMMON_EXPORT QJsonValue toJson(const std::vector< {{ dt.name }} > &element);
|
||||
template<> {{ namespace_abbr_upper }}_COMMON_EXPORT std::vector<{{ dt.name }}> fromJson(const QJsonValue &value, type< std::vector< {{ dt.name }} > >);
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
//
|
||||
// extensions to support sequence of seqence of Non-POD :
|
||||
//
|
||||
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
-919
@@ -1,919 +0,0 @@
|
||||
/**
|
||||
* RecordReplay Plugin
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-07-21
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_record_replay_plugin.cpp
|
||||
|
||||
#include "{{ namespace_abbr }}_record_replay_plugin.h"
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
#include <DDS/DTC/generic_dtc_impl.h>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <LtsUtilsCore/dds_vector.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct type{};
|
||||
|
||||
// conversion DDS -> QVariant, encapsulate complex members into json
|
||||
template<typename T>
|
||||
QJsonValue toJson(const T &val);
|
||||
|
||||
template<typename T>
|
||||
QVariant toQVariant(const T &val)
|
||||
{
|
||||
return QVariant::fromValue(val);
|
||||
}
|
||||
|
||||
template<>
|
||||
QJsonValue toJson(const int &vec)
|
||||
{
|
||||
return QJsonValue(vec);
|
||||
}
|
||||
template<>
|
||||
QJsonValue toJson(const double &vec)
|
||||
{
|
||||
return QJsonValue(vec);
|
||||
}
|
||||
template<>
|
||||
QJsonValue toJson(const qint64 &val)
|
||||
{
|
||||
return QJsonValue(QString::number(val));
|
||||
}
|
||||
|
||||
template<>
|
||||
QJsonValue toJson(const std::vector<int> &val)
|
||||
{
|
||||
if (val.size() == 0)
|
||||
return QJsonValue();
|
||||
QJsonArray array;
|
||||
for(size_t i = 0; i < val.size(); ++i)
|
||||
array.push_back(toJson(val.at(i)));
|
||||
|
||||
return QJsonValue(array);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
QVariant toQVariant(const dds::core::safe_enum<T> &val)
|
||||
{
|
||||
// do not use T here - otherwise the implicit ctor dds::core::safe_enum<T>() is used which leads to infinite recursion
|
||||
return toQVariant<int>(val.underlying());
|
||||
}
|
||||
|
||||
template<>
|
||||
QJsonValue toJson(const std::string &element)
|
||||
{
|
||||
return QJsonValue(QString::fromStdString(element));
|
||||
}
|
||||
|
||||
template<>
|
||||
QVariant toQVariant(const std::string &val)
|
||||
{
|
||||
return QString::fromStdString(val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QVariant toQVariant(const std::vector<T> &data)
|
||||
{
|
||||
if (data.size() == 0)
|
||||
return QString();
|
||||
QJsonArray array;
|
||||
for(size_t i = 0; i < data.size(); ++i)
|
||||
array.push_back(toJson(data.at(i)));
|
||||
|
||||
return QString::fromUtf8(QJsonDocument(array).toJson());
|
||||
}
|
||||
|
||||
template<>
|
||||
QVariant toQVariant(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (data.size() == 0)
|
||||
return QVariant();
|
||||
return QVariant(LtsUtils::convert<QByteArray>(data));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static QVariant toQVariant(const dds::core::optional<T> &val)
|
||||
{
|
||||
if (val.is_set())
|
||||
return toQVariant(val.get());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// conversion QVariant -> DDS, decode complex members from json
|
||||
template<typename T>
|
||||
T fromJson(const QJsonValue &val, type<T>);
|
||||
|
||||
template<>
|
||||
int fromJson(const QJsonValue &val, type<int>)
|
||||
{
|
||||
return val.toInt();
|
||||
}
|
||||
template<>
|
||||
double fromJson(const QJsonValue &val, type<double>)
|
||||
{
|
||||
return val.toDouble();
|
||||
}
|
||||
template<>
|
||||
qint64 fromJson(const QJsonValue &val, type<qint64>)
|
||||
{
|
||||
return val.toString().toLongLong();
|
||||
}
|
||||
/*
|
||||
template<>
|
||||
std::vector<int> fromJson(const QJsonValue &val, type<std::vector<int>>)
|
||||
{
|
||||
std::vector<int> ret;
|
||||
if (val.isNull())
|
||||
return ret;
|
||||
const QJsonArray array(QJsonDocument::fromJson(val.toString().toUtf8()).array());
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<int>{} ));
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromJson(const QJsonValue &jsonData, type<std::vector<T>>)
|
||||
{
|
||||
std::vector<T> ret;
|
||||
if (jsonData.isNull())
|
||||
return ret;
|
||||
const QJsonArray array(jsonData.toArray());
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<T>{}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromJson(const QVariant &jsonData, type<std::vector<T>>)
|
||||
{
|
||||
std::vector<T> ret;
|
||||
if (jsonData.isNull())
|
||||
return ret;
|
||||
const QJsonArray array(QJsonDocument::fromJson(jsonData.toString().toUtf8()).array()); // warning: ugly and didn't work in the fromJson version above
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<T>{}));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Primary fallback for any migrated plain-`enum class` enumerators that have no
|
||||
// explicit specialization below - most importantly the nested foreign
|
||||
// ProjectDataManagement / Core enums a plugin reads back from the database (they are
|
||||
// not in this service's idl_enums, so the per-own-enum specializations do not cover
|
||||
// them). Giving the primary template a body (rather than leaving it declaration-only)
|
||||
// is what lets those foreign-enum instantiations resolve, so the plugin .so links. The
|
||||
// explicit specializations for primitives / own enums / structs / vectors / optionals
|
||||
// all take precedence over this fallback, so it is only ever instantiated for an enum
|
||||
// type, where `static_cast<T>(val.toInt())` is the correct conversion.
|
||||
template<typename T>
|
||||
T fromQVariant(const QVariant &val, type<T>)
|
||||
{
|
||||
return static_cast<T>(val.toInt());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool fromQVariant(const QVariant &val, type<bool>)
|
||||
{
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
template<>
|
||||
short fromQVariant(const QVariant &val, type<short>)
|
||||
{
|
||||
return static_cast<short>(val.toInt());
|
||||
}
|
||||
|
||||
template<>
|
||||
int fromQVariant(const QVariant &val, type<int>)
|
||||
{
|
||||
return val.toInt();
|
||||
}
|
||||
|
||||
template<>
|
||||
long long fromQVariant(const QVariant &val, type<long long>)
|
||||
{
|
||||
return val.toLongLong();
|
||||
}
|
||||
|
||||
// rtiddsgen 4.7 spells the 64 bit integer members int64_t, which is `long` on LP64 and thus
|
||||
// a different type from the Qt side's qint64 (`long long`). The tag dispatch above is keyed on
|
||||
// the exact type, so the generated type needs its own conversion even though the two are the
|
||||
// same width. GrantleeWrappers::cppDdsType() names the generated member type, so this is the
|
||||
// overload the record replay code instantiates for those members.
|
||||
template<>
|
||||
int64_t fromQVariant(const QVariant &val, type<int64_t>)
|
||||
{
|
||||
return static_cast<int64_t>(val.toLongLong());
|
||||
}
|
||||
|
||||
template<>
|
||||
double fromQVariant(const QVariant &val, type<double>)
|
||||
{
|
||||
return val.toDouble();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string fromJson(const QJsonValue &val, type<std::string>)
|
||||
{
|
||||
return val.toString().toStdString();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string fromQVariant(const QVariant &val, type<std::string>)
|
||||
{
|
||||
return val.toString().toStdString();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
dds::core::safe_enum<T> fromQVariant(const QVariant &val, type<dds::core::safe_enum<T>>)
|
||||
{
|
||||
using inner = typename dds::core::safe_enum<T>::inner_enum;
|
||||
return static_cast<inner>(val.toInt());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromQVariant(const QVariant &val, type<std::vector<T>> t)
|
||||
{
|
||||
return fromJson(val, t);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector<uint8_t> fromQVariant(const QVariant &in, type<std::vector<uint8_t>>)
|
||||
{
|
||||
return LtsUtils::convert<std::vector<uint8_t>>(in.toByteArray());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static dds::core::optional<T> fromQVariant(const QVariant &val, type<dds::core::optional<T>>)
|
||||
{
|
||||
if (val.isNull())
|
||||
return dds::core::optional<T>();
|
||||
return fromQVariant(val, type<T>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T fromJson(const QJsonValue &val)
|
||||
{
|
||||
return fromJson(val, type<T>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T fromQVariant(const QVariant &val)
|
||||
{
|
||||
return fromQVariant(val, type<T>{});
|
||||
}
|
||||
|
||||
// rtiddsgen 7.7 spells the migrated enumerators as plain `enum class` in the service
|
||||
// namespace (the legacy dds::core::safe_enum<T> wrapper is gone). The record_replay
|
||||
// plugin still instantiates fromQVariant<Enum>() for each enum member it reads back,
|
||||
// and none of the generic overloads above are ever deduced for those types, so each of
|
||||
// this service's own enumerations needs its own explicit specialization. `idl_enums`
|
||||
// carries the service's own enumerations by local name and this block runs inside
|
||||
// `namespace {{ namespace }}`, so the local name resolves to the fully-qualified enum
|
||||
// type. (Nested foreign PDM enumerations are still not covered - same limitation as the
|
||||
// documented svcBuildings exclusion.)
|
||||
{% for enumeration in idl_enums %}
|
||||
template<>
|
||||
{{ enumeration.name }} fromQVariant(const QVariant &val, type<{{ enumeration.name }}>)
|
||||
{
|
||||
return static_cast<{{ enumeration.name }}>(val.toInt());
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
{% for dt in serializeTopics.member %}
|
||||
//
|
||||
// Begin {{ dt.typeFq }}
|
||||
//
|
||||
template<>
|
||||
{{ dt.typeFq }} fromJson(const QJsonValue &val, type<{{ dt.typeFq }}>)
|
||||
{
|
||||
const QJsonObject objElement(val.toObject());
|
||||
{{ dt.typeFq }} element;
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
{ {{ row.jsonElementToDds }}; } {% endfor %}
|
||||
|
||||
return element;
|
||||
}
|
||||
template<>
|
||||
QJsonValue toJson(const {{ dt.typeFq }} &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
{{ row.ddsToJsonElement }}; {% endfor %}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <>
|
||||
QVariant toQVariant(const {{ dt.typeFq }} &val)
|
||||
{
|
||||
return QString::fromUtf8(QJsonDocument(toJson(val).toObject()).toJson());
|
||||
}
|
||||
|
||||
template<>
|
||||
{{ dt.typeFq }} fromQVariant(const QVariant &val, type<{{ dt.typeFq }}>)
|
||||
{
|
||||
return fromJson(QJsonDocument::fromJson(val.toString().toUtf8()).object(), type<{{ dt.typeFq }}>{});
|
||||
}
|
||||
|
||||
//
|
||||
// extensions to support sequence of seqence of Non-POD :
|
||||
//
|
||||
|
||||
template<>
|
||||
QJsonValue toJson(const std::vector < {{ dt.typeFq }} > &data)
|
||||
{
|
||||
if (data.size() == 0)
|
||||
return QJsonValue();
|
||||
QJsonArray array;
|
||||
for(size_t i = 0; i < data.size(); ++i)
|
||||
array.push_back(toJson(data.at(i)));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector < {{ dt.typeFq }} > fromJson(const QJsonValue &val)
|
||||
{
|
||||
std::vector < {{ dt.typeFq }} > ret;
|
||||
if (val.isNull())
|
||||
return ret;
|
||||
if (!val.isArray())
|
||||
return ret;
|
||||
const QJsonArray array = val.toArray();
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<{{ dt.typeFq }}>{}));
|
||||
return ret;
|
||||
}
|
||||
//
|
||||
// : extensions to support sequence of seqence of Non-POD
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// End {{ dt.typeFq }}
|
||||
//
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
RecordReplayPlugin::RecordReplayPlugin()
|
||||
: m_exerciseId(0)
|
||||
, m_bCanHandleSchemasRead(true)
|
||||
, m_bCanHandleSchemasWrite(true)
|
||||
, m_logger(getLogger("RecordReplay"))
|
||||
{}
|
||||
|
||||
RecordReplayPlugin::~RecordReplayPlugin() = default;
|
||||
|
||||
QString RecordReplayPlugin::getTableName(const QString &tableName, bool bCanHandleSchemas) const
|
||||
{
|
||||
if (!bCanHandleSchemas)
|
||||
return tableName;
|
||||
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initDtc(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId)
|
||||
{
|
||||
m_ddsConnector = ddsConnector;
|
||||
m_exerciseId = exerciseId;
|
||||
if (!m_ddsConnector)
|
||||
return false;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
m_dtc{{ dt.name }}.reset(m_ddsConnector->createDTC<DTC::{{ dt.name }}Impl>());
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query)
|
||||
{
|
||||
Q_UNUSED(query);
|
||||
m_ddsConnector = ddsConnector;
|
||||
m_exerciseId = exerciseId;
|
||||
m_bCanHandleSchemasRead = bCanHandleSchemas;
|
||||
m_bCanHandleSchemasWrite = bCanHandleSchemas;
|
||||
if (!m_ddsConnector)
|
||||
return false;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
m_dts{{ dt.name }}.reset(m_ddsConnector->createDTS<DTS::{{ dt.name }}Impl>());
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initCopy(int exerciseId, bool bCanHandleSchemasRead, bool bCanHandleSchemasWrite)
|
||||
{
|
||||
m_exerciseId = exerciseId;
|
||||
m_bCanHandleSchemasRead = bCanHandleSchemasRead;
|
||||
m_bCanHandleSchemasWrite = bCanHandleSchemasWrite;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyData(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
// {{ dt.name }}
|
||||
if (!copyInitialData{{ dt.name }}(queryFrom, queryTo, fromTime)) return false;
|
||||
if (!copyData{{ dt.name }}(queryFrom, queryTo, fromTime, toTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::ddsTopicsToDatabase(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!write{{ dt.name }}(q, minRecordSampleTimes)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::setReplayStartTime(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!read{{ dt.name }}At(q, startTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!read{{ dt.name }}(q, fromTime, toTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::publishData(qint64 desiredTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!publish{{ dt.name }}(desiredTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordReplayPlugin::clearData()
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
clearData{{ dt.name }}();
|
||||
{% endif %} {% endfor %}
|
||||
}
|
||||
|
||||
std::map<QString, std::vector<RecordReplayPlugin::RecSnapshot>> RecordReplayPlugin::getSnapshotTimes(NSqlQuery &q,
|
||||
qint64 toTime,
|
||||
qint64 interval,
|
||||
const QHash<QString, qint64> &minRecordedSampleTimes)
|
||||
{
|
||||
std::map<QString, std::vector<RecordReplayPlugin::RecSnapshot>> ret;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
{
|
||||
const QString &topicName(QStringLiteral("{{ dt.name }}"));
|
||||
std::vector<RecordReplayPlugin::RecSnapshot> vec;
|
||||
auto it = minRecordedSampleTimes.find(topicName);
|
||||
if (it != minRecordedSampleTimes.end())
|
||||
{
|
||||
qint64 nextSampleTime = getNextSampleTimeFor{{ dt.name }}(q, it.value()); // is 0 or -1 if no samples are available
|
||||
nextSampleTime -= (nextSampleTime % interval); // sync to interval - only needed for better debugging
|
||||
|
||||
if (nextSampleTime != m_snapshot{{ dt.name }}MapTime)
|
||||
{
|
||||
// the current snapshot data does not match the starting time -> reread m_{{ dt.nameFlc }}Keys
|
||||
readLastSnapshotKeysFor{{ dt.name }}(q, nextSampleTime);
|
||||
//DEBUG_LOG(m_logger) << "fromTime: " << fromTime << ", m_snapshotParticipantMapTime: " << m_snapshotParticipantMapTime
|
||||
// << " - rereading snapshot times! Map now contains " << m_snapshot{{ dt.name }}Map.size() << " entries";
|
||||
}
|
||||
|
||||
while (nextSampleTime > 0 && nextSampleTime <= toTime)
|
||||
{
|
||||
const qint64 intervalStart = nextSampleTime;
|
||||
const qint64 intervalEnd = intervalStart + interval;
|
||||
updateSnapshotKeys{{ dt.name }}(q, intervalStart, intervalEnd);
|
||||
|
||||
vec.emplace_back(RecSnapshot(intervalEnd, m_snapshot{{ dt.name }}Map));
|
||||
|
||||
nextSampleTime = getNextSampleTimeFor{{ dt.name }}(q, intervalEnd);
|
||||
nextSampleTime -= (nextSampleTime % interval); // sync to interval - only needed for better debugging
|
||||
}
|
||||
}
|
||||
if (!vec.empty())
|
||||
ret.insert({topicName, std::move(vec)});
|
||||
}
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<QString> RecordReplayPlugin::getRecordTopicNames() const
|
||||
{
|
||||
return {{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
QStringLiteral("{{ dt.name }}"){% if not forloop.last %}, {% endif %} {% endif %} {% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
QVector<QString> RecordReplayPlugin::getRecordTableNames() const
|
||||
{
|
||||
return {{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
QStringLiteral("{{ dt.recTable.name }}"){% if not forloop.last %}, {% endif %} {% endif %} {% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
qint64 RecordReplayPlugin::getMinimumSampleTime(NSqlQuery &q, const QString &topicName, qint64 defaultValue) const
|
||||
{
|
||||
QString tableName;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (topicName == QLatin1String("{{ dt.name }}"))
|
||||
tableName = QStringLiteral("{{ dt.recTable.name }}");
|
||||
{% endif %} {% endfor %}
|
||||
if (tableName.isEmpty())
|
||||
return defaultValue;
|
||||
const QString stmt(QStringLiteral("SELECT MIN(sample_time) FROM ") + tableName);
|
||||
if (!q.execAndFetch(stmt))
|
||||
return defaultValue;
|
||||
const QVariant val = q.value(0);
|
||||
return val.isNull() ? defaultValue : val.toLongLong();
|
||||
}
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
|
||||
bool RecordReplayPlugin::read{{ dt.name }}At(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
// read snapshot data for {{ dt.name }}
|
||||
if (!readLastSnapshotFor{{ dt.name }}(q, startTime)) return false;
|
||||
// read other samples between snapshot time and startTime
|
||||
if (!read{{ dt.name }}(q, m_snapshot{{ dt.name }}MapTime, startTime)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::write{{ dt.name }}(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes)
|
||||
{
|
||||
using DATA = {{ namespace }}::{{ dt.name }};
|
||||
|
||||
if (!m_dtc{{ dt.name }})
|
||||
return false;
|
||||
|
||||
qint64 minRecordSampleTime = std::numeric_limits<qint64>::max();
|
||||
|
||||
if (m_dtc{{ dt.name }}->hasSamples())
|
||||
{
|
||||
TRACE_LOG(m_logger) << "m_dtc{{ dt.name }}->hasSamples() == true ";
|
||||
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, {% for row in dt.recTable.cppMember %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}) VALUES "
|
||||
" (:dds_is_alive, {% for row in dt.recTable.cppMember %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %});"));
|
||||
|
||||
if (!q.prepare(stmt))
|
||||
return false;
|
||||
|
||||
dds::sub::LoanedSamples<DATA> samples = m_dtc{{ dt.name }}->takeAlive();
|
||||
TRACE_LOG(m_logger) << "samples count: " << samples.length();
|
||||
for (const auto &sample : samples)
|
||||
{
|
||||
const DATA &data = sample.data();
|
||||
INFO_LOG(m_logger) << "m_dtc{{ dt.name }} {{ dt.recTable.ddsKey.cppMemberName }}: " << data.{{ dt.recTable.ddsKey.cppMemberName }};
|
||||
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
q.bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.ddsToQVariant }});
|
||||
{% endfor %}
|
||||
q.bindValue(QStringLiteral(":dds_is_alive"), true);
|
||||
|
||||
if (!q.exec())
|
||||
return false;
|
||||
|
||||
// rtiddsgen 4.7 declares sample_time as int64_t (long), while the record
|
||||
// boundary is qint64 (long long); std::min requires both arguments to be
|
||||
// the same type, so narrow the generated member explicitly.
|
||||
minRecordSampleTime = std::min(minRecordSampleTime, static_cast<qint64>(data.sampleTime));
|
||||
}
|
||||
}
|
||||
|
||||
dds::sub::LoanedSamples<DATA> disposedSamples = m_dtc{{ dt.name }}->takeDisposed();
|
||||
if (disposedSamples.length() != 0)
|
||||
{
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, sample_time, {{ dt.recTable.ddsKey.dbColumnName }}) VALUES "
|
||||
" (:dds_is_alive,:sample_time,:{{ dt.recTable.ddsKey.dbColumnName }});"));
|
||||
|
||||
if (!q.prepare(stmt))
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "disposedSamples count: " << disposedSamples.length();
|
||||
auto dr = m_dtc{{ dt.name }}->dataReader()->dataReader();
|
||||
{{ dt.name }} data;
|
||||
for (const auto &sample : disposedSamples)
|
||||
{
|
||||
const qint64 sampleTime = sample.info().source_timestamp().to_millisecs();
|
||||
dr.key_value(data, sample.info().instance_handle());
|
||||
q.bindValue(QStringLiteral(":dds_is_alive"), false);
|
||||
q.bindValue(QStringLiteral(":sample_time"), sampleTime);
|
||||
q.bindValue(QStringLiteral(":{{ dt.recTable.ddsKey.cppMemberName }}"), {{ dt.recTable.ddsKey.ddsToQVariant }});
|
||||
|
||||
if (!q.exec())
|
||||
return false;
|
||||
|
||||
minRecordSampleTime = std::min(minRecordSampleTime, sampleTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (minRecordSampleTime != std::numeric_limits<qint64>::max())
|
||||
minRecordSampleTimes[QStringLiteral("{{ dt.name }}")] = minRecordSampleTime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read the last snapshot which is <= startTime, set m_snapshot{{ dt.name }}MapTime to the snapshot time
|
||||
bool RecordReplayPlugin::readLastSnapshotFor{{ dt.name }}(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
// rebuild m_{{ dt.nameFlc }}Map content for given startTime
|
||||
clearData{{ dt.name }}();
|
||||
|
||||
const QString stmt(QStringLiteral("SELECT id, time_stamp FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(startTime));
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while fetch max(time_stamp) for topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
if (!q.next() || q.value(0).isNull())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No snapshot available for topic {{ dt.name }}";
|
||||
return true;
|
||||
}
|
||||
const qint64 idSnapshot = q.value(0).toLongLong();
|
||||
const qint64 timeSnapshot = q.value(1).toLongLong();
|
||||
|
||||
const QString stmt2(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE rec_id IN (SELECT reduce_dim2(rec_id_array) FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE id = ") + QString::number(idSnapshot) + QLatin1Char(')'));
|
||||
|
||||
if (!q.exec(stmt2))
|
||||
return false;
|
||||
|
||||
{{ namespace }}::{{ dt.name }} data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
const bool bIsAlive = q.value(i++).toBool();
|
||||
{% for row in dt.recTable.viewMember %}
|
||||
{{ row.qVariantToDds }};
|
||||
{% endfor %}
|
||||
|
||||
if (bIsAlive)
|
||||
m_{{ dt.nameFlc }}Map.insert(data.sampleTime, data);
|
||||
else
|
||||
m_{{ dt.nameFlc }}DisposedMap.insert(data.sampleTime, data);
|
||||
m_{{ dt.nameFlc }}Keys.insert(data.{{ dt.key.name }});
|
||||
}
|
||||
m_snapshot{{ dt.name }}MapTime = timeSnapshot;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPlugin::read{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > " ) + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) + QLatin1Char(';'));
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
{{ namespace }}::{{ dt.name }} data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
const bool bIsAlive = q.value(i++).toBool();
|
||||
|
||||
{% for row in dt.recTable.viewMember %}
|
||||
{{ row.qVariantToDds }};
|
||||
{% endfor %}
|
||||
|
||||
if (bIsAlive)
|
||||
m_{{ dt.nameFlc }}Map.insert(data.sampleTime, data);
|
||||
else
|
||||
m_{{ dt.nameFlc }}DisposedMap.insert(data.sampleTime, data);
|
||||
m_{{ dt.nameFlc }}Keys.insert(data.{{ dt.key.name }});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::updateSnapshotKeys{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT {{ dt.recTable.ddsKey.dbColumnName }}, {{ dt.recTable.primaryKey.dbColumnName }}, dds_is_alive FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > ") + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) +
|
||||
QStringLiteral(" ORDER BY sample_time "));
|
||||
|
||||
DEBUG_LOG(m_logger) << "stmt: " << stmt;
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
while (q.next())
|
||||
{
|
||||
const qint64 key = q.value(0){{ dt.recTable.ddsKey.cppFromQvPost }};
|
||||
const qint64 pk = q.value(1){{ dt.recTable.primaryKey.cppFromQvPost }};
|
||||
const bool isAlive = q.value(2).toBool();
|
||||
if (isAlive)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "INSERT {{ dt.name }} key: " << key << ", pk: " << pk << ", isAlive: " << isAlive;
|
||||
m_snapshot{{ dt.name }}Map[key] = pk;
|
||||
m_{{ dt.nameFlc }}Keys.insert(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "REMOVE {{ dt.name }} key: " << key << ", pk: " << pk << ", isAlive: " << isAlive;
|
||||
m_snapshot{{ dt.name }}Map.erase(key);
|
||||
m_{{ dt.nameFlc }}Keys.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
// new validity time for snapshot data
|
||||
m_snapshot{{ dt.name }}MapTime = toTime;
|
||||
|
||||
DEBUG_LOG(m_logger) << "updateSnapshotKeys{{ dt.name }}(" << fromTime << ", " << toTime << ") = "
|
||||
<< m_snapshot{{ dt.name }}Map.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::readLastSnapshotKeysFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT rec_id_array FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(fromTime));
|
||||
|
||||
// no previous snapshot found?
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
if (!q.next() || q.value(0).isNull())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "no snapshot entry for {{ dt.name }} found";
|
||||
return true;
|
||||
}
|
||||
|
||||
m_snapshot{{ dt.name }}Map = LtsUtils::BigintArray2D::fromPgString(q.value(0).toString())();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Map size {{ dt.name }}: " << m_snapshot{{ dt.name }}Map.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
qint64 RecordReplayPlugin::getNextSampleTimeFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT MIN(sample_time) FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > ") + QString::number(fromTime));
|
||||
qint64 ret = -1;
|
||||
if (q.execAndFetch(stmt) && !q.value(0).isNull())
|
||||
ret = q.value(0).toLongLong();
|
||||
|
||||
DEBUG_LOG(m_logger) << "next min sampleTime for {{ dt.name }} is " << ret << " (> " << fromTime << ")";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPlugin::publish{{ dt.name }}(qint64 desiredTime)
|
||||
{
|
||||
if (!m_dts{{ dt.name }})
|
||||
return false;
|
||||
{
|
||||
auto it = m_{{ dt.nameFlc }}Map.begin();
|
||||
while (it != m_{{ dt.nameFlc }}Map.end() && it.key() <= desiredTime)
|
||||
{
|
||||
m_dts{{ dt.name }}->write(it.value());
|
||||
it = m_{{ dt.nameFlc }}Map.erase(it);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto it = m_{{ dt.nameFlc }}DisposedMap.begin();
|
||||
while (it != m_{{ dt.nameFlc }}DisposedMap.end() && it.key() <= desiredTime)
|
||||
{
|
||||
m_dts{{ dt.name }}->remove(it.value());
|
||||
it = m_{{ dt.nameFlc }}DisposedMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordReplayPlugin::clearData{{ dt.name }}()
|
||||
{
|
||||
if (m_dts{{ dt.name }})
|
||||
{
|
||||
{{ dt.name }} tmpData;
|
||||
for (auto key : m_{{ dt.nameFlc }}Keys)
|
||||
{
|
||||
tmpData.{{ dt.key.name }} = key;
|
||||
m_dts{{ dt.name }}->remove(tmpData);
|
||||
}
|
||||
}
|
||||
m_{{ dt.nameFlc }}Keys.clear();
|
||||
m_{{ dt.nameFlc }}Map.clear();
|
||||
m_{{ dt.nameFlc }}DisposedMap.clear();
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyInitialData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 startTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT id FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(startTime));
|
||||
|
||||
if (!queryFrom.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while fetch max(time_stamp) for topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
if (!queryFrom.next() || queryFrom.value(0).isNull())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No snapshot available for topic {{ dt.name }}";
|
||||
return true;
|
||||
}
|
||||
const qint64 idSnapshot = queryFrom.value(0).toLongLong();
|
||||
|
||||
const QString stmtSelect(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE rec_id IN (SELECT reduce_dim2(rec_id_array) FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE id = ") + QString::number(idSnapshot) + QLatin1Char(')'));
|
||||
|
||||
if (!queryFrom.exec(stmtSelect))
|
||||
return false;
|
||||
|
||||
return copyDataPrepared{{ dt.name }}(queryFrom, queryTo);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > " ) + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) + QLatin1Char(';'));
|
||||
|
||||
if (!queryFrom.exec(stmt))
|
||||
return false;
|
||||
|
||||
return copyDataPrepared{{ dt.name }}(queryFrom, queryTo);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyDataPrepared{{ dt.name }}(NSqlQuery &queryFromPrepared, NSqlQuery &queryTo)
|
||||
{
|
||||
const QString stmtInsert(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, {% for row in dt.recTable.cppMember %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}) VALUES "
|
||||
" (:dds_is_alive, {% for row in dt.recTable.cppMember %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %});"));
|
||||
|
||||
if (!queryTo.prepare(stmtInsert))
|
||||
return false;
|
||||
|
||||
while (queryFromPrepared.next())
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
queryTo.bindValue(QStringLiteral(":dds_is_alive"), queryFromPrepared.value(i++));
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
queryTo.bindValue(QStringLiteral(":{{ row.dbColumnName }}"), queryFromPrepared.value(i++));
|
||||
{% endfor %}
|
||||
if (!queryTo.exec())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
-637
@@ -1,637 +0,0 @@
|
||||
/**
|
||||
* RecordReplay Plugin
|
||||
* $Id: svc_record_replay_plugin.cpp.grantlee 50268 2020-03-06 07:42:09Z ehrlicher $
|
||||
* $HeadURL: svn://slssvn/TDS/branches/product/iterations/21_07_assault_energy/Lts/Common/CodeGen/svc_record_replay_plugin.cpp.grantlee $
|
||||
* $Author: ehrlicher $
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-07-21
|
||||
*/
|
||||
|
||||
|
||||
Leider gibnt es Probleme, wenn man Sequenzen von Sequenzen von Non-PODs erstellt.
|
||||
Es erbgaben sich unresolved symbols... (Compiler war zufrieden, Linker aber nicht - hmm)
|
||||
|
||||
Mit dem folgenden Konstrukt konnten ich diese "beheben", doch je nach Konstellation in der XYZ_service.xml
|
||||
ergaben sich Fehler a la "template specialication after instatiation"
|
||||
|
||||
Daher haben wir (zumindest zunächst) Abstand von dieser Erweiterung genommen.
|
||||
|
||||
...
|
||||
|
||||
{% for dt in serializeTopics.member %}
|
||||
//
|
||||
// Begin {{ dt.typeFq }}
|
||||
//
|
||||
template<>
|
||||
{{ dt.typeFq }} fromJson(const QJsonValue &val, type<{{ dt.typeFq }}>)
|
||||
{
|
||||
const QJsonObject objElement(val.toObject());
|
||||
{{ dt.typeFq }} element;
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
{ {{ row.jsonElementToDds }}; } {% endfor %}
|
||||
|
||||
return element;
|
||||
}
|
||||
template<>
|
||||
QJsonValue toJson(const {{ dt.typeFq }} &element)
|
||||
{
|
||||
QJsonObject obj;
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
{{ row.ddsToJsonElement }}; {% endfor %}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <>
|
||||
QVariant toQVariant(const {{ dt.typeFq }} &val)
|
||||
{
|
||||
return QString::fromUtf8(QJsonDocument(toJson(val).toObject()).toJson());
|
||||
}
|
||||
|
||||
template<>
|
||||
{{ dt.typeFq }} fromQVariant(const QVariant &val, type<{{ dt.typeFq }}>)
|
||||
{
|
||||
return fromJson(QJsonDocument::fromJson(val.toString().toUtf8()).object(), type<{{ dt.typeFq }}>{});
|
||||
}
|
||||
|
||||
//
|
||||
// extensions to support sequence of seqence of Non-POD :
|
||||
//
|
||||
|
||||
template<>
|
||||
QJsonValue toJson(const std::vector < {{ dt.typeFq }} > &data)
|
||||
{
|
||||
if (data.size() == 0)
|
||||
return QJsonValue();
|
||||
QJsonArray array;
|
||||
for(size_t i = 0; i < data.size(); ++i)
|
||||
array.push_back(toJson(data.at(i)));
|
||||
|
||||
return QJsonDocument(array).object();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::vector < {{ dt.typeFq }} > fromJson(const QJsonValue &val)
|
||||
{
|
||||
std::vector < {{ dt.typeFq }} > ret;
|
||||
if (val.isNull() == 0)
|
||||
return ret;
|
||||
if (val.isArray() == 0) return ret;
|
||||
const QJsonArray array = val.toArray();
|
||||
ret.reserve(array.size());
|
||||
for(const auto &ele : array)
|
||||
ret.push_back(fromJson(ele, type<{{ dt.typeFq }}>{}));
|
||||
return ret;
|
||||
}
|
||||
//
|
||||
// : extensions to support sequence of seqence of Non-POD
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// End {{ dt.typeFq }}
|
||||
//
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
RecordReplayPlugin::RecordReplayPlugin()
|
||||
: m_exerciseId(0)
|
||||
, m_bCanHandleSchemasRead(true)
|
||||
, m_bCanHandleSchemasWrite(true)
|
||||
, m_logger(getLogger("RecordReplay"))
|
||||
{}
|
||||
|
||||
RecordReplayPlugin::~RecordReplayPlugin() = default;
|
||||
|
||||
QString RecordReplayPlugin::getTableName(const QString &tableName, bool bCanHandleSchemas) const
|
||||
{
|
||||
if (!bCanHandleSchemas)
|
||||
return tableName;
|
||||
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initDtc(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId)
|
||||
{
|
||||
m_ddsConnector = ddsConnector;
|
||||
m_exerciseId = exerciseId;
|
||||
if (!m_ddsConnector)
|
||||
return false;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
m_dtc{{ dt.name }}.reset(m_ddsConnector->createDTC<DTC::{{ dt.name }}Impl>());
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query)
|
||||
{
|
||||
Q_UNUSED(query);
|
||||
m_ddsConnector = ddsConnector;
|
||||
m_exerciseId = exerciseId;
|
||||
m_bCanHandleSchemasRead = bCanHandleSchemas;
|
||||
m_bCanHandleSchemasWrite = bCanHandleSchemas;
|
||||
if (!m_ddsConnector)
|
||||
return false;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
m_dts{{ dt.name }}.reset(m_ddsConnector->createDTS<DTS::{{ dt.name }}Impl>());
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::initCopy(int exerciseId, bool bCanHandleSchemasRead, bool bCanHandleSchemasWrite)
|
||||
{
|
||||
m_exerciseId = exerciseId;
|
||||
m_bCanHandleSchemasRead = bCanHandleSchemasRead;
|
||||
m_bCanHandleSchemasWrite = bCanHandleSchemasWrite;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyData(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
// {{ dt.name }}
|
||||
if (!copyInitialData{{ dt.name }}(queryFrom, queryTo, fromTime)) return false;
|
||||
if (!copyData{{ dt.name }}(queryFrom, queryTo, fromTime, toTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::ddsTopicsToDatabase(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!write{{ dt.name }}(q, minRecordSampleTimes)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::setReplayStartTime(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!read{{ dt.name }}At(q, startTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!read{{ dt.name }}(q, fromTime, toTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::publishData(qint64 desiredTime)
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (!publish{{ dt.name }}(desiredTime)) return false;
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordReplayPlugin::clearData()
|
||||
{
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
clearData{{ dt.name }}();
|
||||
{% endif %} {% endfor %}
|
||||
}
|
||||
|
||||
std::map<QString, std::vector<RecordReplayPlugin::RecSnapshot>> RecordReplayPlugin::getSnapshotTimes(NSqlQuery &q,
|
||||
qint64 toTime,
|
||||
qint64 interval,
|
||||
const QHash<QString, qint64> &minRecordedSampleTimes)
|
||||
{
|
||||
std::map<QString, std::vector<RecordReplayPlugin::RecSnapshot>> ret;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
{
|
||||
const QString &topicName(QStringLiteral("{{ dt.name }}"));
|
||||
std::vector<RecordReplayPlugin::RecSnapshot> vec;
|
||||
auto it = minRecordedSampleTimes.find(topicName);
|
||||
if (it != minRecordedSampleTimes.end())
|
||||
{
|
||||
qint64 nextSampleTime = getNextSampleTimeFor{{ dt.name }}(q, it.value()); // is 0 or -1 if no samples are available
|
||||
nextSampleTime -= (nextSampleTime % interval); // sync to interval - only needed for better debugging
|
||||
|
||||
if (nextSampleTime != m_snapshot{{ dt.name }}MapTime)
|
||||
{
|
||||
// the current snapshot data does not match the starting time -> reread m_{{ dt.nameFlc }}Keys
|
||||
readLastSnapshotKeysFor{{ dt.name }}(q, nextSampleTime);
|
||||
//DEBUG_LOG(m_logger) << "fromTime: " << fromTime << ", m_snapshotParticipantMapTime: " << m_snapshotParticipantMapTime
|
||||
// << " - rereading snapshot times! Map now contains " << m_snapshot{{ dt.name }}Map.size() << " entries";
|
||||
}
|
||||
|
||||
while (nextSampleTime > 0 && nextSampleTime <= toTime)
|
||||
{
|
||||
const qint64 intervalStart = nextSampleTime;
|
||||
const qint64 intervalEnd = intervalStart + interval;
|
||||
updateSnapshotKeys{{ dt.name }}(q, intervalStart, intervalEnd);
|
||||
|
||||
vec.emplace_back(RecSnapshot(intervalEnd, m_snapshot{{ dt.name }}Map));
|
||||
|
||||
nextSampleTime = getNextSampleTimeFor{{ dt.name }}(q, intervalEnd);
|
||||
nextSampleTime -= (nextSampleTime % interval); // sync to interval - only needed for better debugging
|
||||
}
|
||||
}
|
||||
if (!vec.empty())
|
||||
ret.insert({topicName, std::move(vec)});
|
||||
}
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<QString> RecordReplayPlugin::getRecordTopicNames() const
|
||||
{
|
||||
return {{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
QStringLiteral("{{ dt.name }}"){% if not forloop.last %}, {% endif %} {% endif %} {% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
QVector<QString> RecordReplayPlugin::getRecordTableNames() const
|
||||
{
|
||||
return {{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
QStringLiteral("{{ dt.recTable.name }}"){% if not forloop.last %}, {% endif %} {% endif %} {% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
qint64 RecordReplayPlugin::getMinimumSampleTime(NSqlQuery &q, const QString &topicName, qint64 defaultValue) const
|
||||
{
|
||||
QString tableName;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
if (topicName == QLatin1String("{{ dt.name }}"))
|
||||
tableName = QStringLiteral("{{ dt.recTable.name }}");
|
||||
{% endif %} {% endfor %}
|
||||
if (tableName.isEmpty())
|
||||
return defaultValue;
|
||||
const QString stmt(QStringLiteral("SELECT MIN(sample_time) FROM ") + tableName);
|
||||
if (!q.execAndFetch(stmt))
|
||||
return defaultValue;
|
||||
const QVariant val = q.value(0);
|
||||
return val.isNull() ? defaultValue : val.toLongLong();
|
||||
}
|
||||
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
|
||||
bool RecordReplayPlugin::read{{ dt.name }}At(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
// read snapshot data for {{ dt.name }}
|
||||
if (!readLastSnapshotFor{{ dt.name }}(q, startTime)) return false;
|
||||
// read other samples between snapshot time and startTime
|
||||
if (!read{{ dt.name }}(q, m_snapshot{{ dt.name }}MapTime, startTime)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::write{{ dt.name }}(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes)
|
||||
{
|
||||
using DATA = {{ namespace }}::{{ dt.name }};
|
||||
|
||||
if (!m_dtc{{ dt.name }})
|
||||
return false;
|
||||
|
||||
qint64 minRecordSampleTime = std::numeric_limits<qint64>::max();
|
||||
|
||||
if (m_dtc{{ dt.name }}->hasSamples())
|
||||
{
|
||||
TRACE_LOG(m_logger) << "m_dtc{{ dt.name }}->hasSamples() == true ";
|
||||
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, {% for row in dt.recTable.cppMember %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}) VALUES "
|
||||
" (:dds_is_alive, {% for row in dt.recTable.cppMember %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %});"));
|
||||
|
||||
if (!q.prepare(stmt))
|
||||
return false;
|
||||
|
||||
dds::sub::LoanedSamples<DATA> samples = m_dtc{{ dt.name }}->takeAlive();
|
||||
TRACE_LOG(m_logger) << "samples count: " << samples.length();
|
||||
for (const auto &sample : samples)
|
||||
{
|
||||
const DATA &data = sample.data();
|
||||
INFO_LOG(m_logger) << "m_dtc{{ dt.name }} {{ dt.recTable.ddsKey.cppMemberName }}: " << data.{{ dt.recTable.ddsKey.cppMemberName }}();
|
||||
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
q.bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.ddsToQVariant }});
|
||||
{% endfor %}
|
||||
q.bindValue(QStringLiteral(":dds_is_alive"), true);
|
||||
|
||||
if (!q.exec())
|
||||
return false;
|
||||
|
||||
minRecordSampleTime = std::min(minRecordSampleTime, data.sampleTime());
|
||||
}
|
||||
}
|
||||
|
||||
dds::sub::LoanedSamples<DATA> disposedSamples = m_dtc{{ dt.name }}->takeDisposed();
|
||||
if (disposedSamples.length() != 0)
|
||||
{
|
||||
const QString stmt(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, sample_time, {{ dt.recTable.ddsKey.dbColumnName }}) VALUES "
|
||||
" (:dds_is_alive,:sample_time,:{{ dt.recTable.ddsKey.dbColumnName }});"));
|
||||
|
||||
if (!q.prepare(stmt))
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "disposedSamples count: " << disposedSamples.length();
|
||||
auto dr = m_dtc{{ dt.name }}->dataReader()->dataReader();
|
||||
{{ dt.name }} data;
|
||||
for (const auto &sample : disposedSamples)
|
||||
{
|
||||
const qint64 sampleTime = sample.info().source_timestamp().to_millisecs();
|
||||
dr.key_value(data, sample.info().instance_handle());
|
||||
q.bindValue(QStringLiteral(":dds_is_alive"), false);
|
||||
q.bindValue(QStringLiteral(":sample_time"), sampleTime);
|
||||
q.bindValue(QStringLiteral(":{{ dt.recTable.ddsKey.cppMemberName }}"), {{ dt.recTable.ddsKey.ddsToQVariant }});
|
||||
|
||||
if (!q.exec())
|
||||
return false;
|
||||
|
||||
minRecordSampleTime = std::min(minRecordSampleTime, sampleTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (minRecordSampleTime != std::numeric_limits<qint64>::max())
|
||||
minRecordSampleTimes[QStringLiteral("{{ dt.name }}")] = minRecordSampleTime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read the last snapshot which is <= startTime, set m_snapshot{{ dt.name }}MapTime to the snapshot time
|
||||
bool RecordReplayPlugin::readLastSnapshotFor{{ dt.name }}(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
// rebuild m_{{ dt.nameFlc }}Map content for given startTime
|
||||
clearData{{ dt.name }}();
|
||||
|
||||
const QString stmt(QStringLiteral("SELECT id, time_stamp FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(startTime));
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while fetch max(time_stamp) for topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
if (!q.next() || q.value(0).isNull())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No snapshot available for topic {{ dt.name }}";
|
||||
return true;
|
||||
}
|
||||
const qint64 idSnapshot = q.value(0).toLongLong();
|
||||
const qint64 timeSnapshot = q.value(1).toLongLong();
|
||||
|
||||
const QString stmt2(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE rec_id IN (SELECT reduce_dim2(rec_id_array) FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE id = ") + QString::number(idSnapshot) + QLatin1Char(')'));
|
||||
|
||||
if (!q.exec(stmt2))
|
||||
return false;
|
||||
|
||||
{{ namespace }}::{{ dt.name }} data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
const bool bIsAlive = q.value(i++).toBool();
|
||||
{% for row in dt.recTable.viewMember %}
|
||||
{{ row.qVariantToDds }};
|
||||
{% endfor %}
|
||||
|
||||
if (bIsAlive)
|
||||
m_{{ dt.nameFlc }}Map.insert(data.sampleTime(), data);
|
||||
else
|
||||
m_{{ dt.nameFlc }}DisposedMap.insert(data.sampleTime(), data);
|
||||
m_{{ dt.nameFlc }}Keys.insert(data.{{ dt.key.name }}());
|
||||
}
|
||||
m_snapshot{{ dt.name }}MapTime = timeSnapshot;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPlugin::read{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > " ) + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) + QLatin1Char(';'));
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
{{ namespace }}::{{ dt.name }} data;
|
||||
while (q.next())
|
||||
{
|
||||
int i = 0;
|
||||
const bool bIsAlive = q.value(i++).toBool();
|
||||
|
||||
{% for row in dt.recTable.viewMember %}
|
||||
{{ row.qVariantToDds }};
|
||||
{% endfor %}
|
||||
|
||||
if (bIsAlive)
|
||||
m_{{ dt.nameFlc }}Map.insert(data.sampleTime(), data);
|
||||
else
|
||||
m_{{ dt.nameFlc }}DisposedMap.insert(data.sampleTime(), data);
|
||||
m_{{ dt.nameFlc }}Keys.insert(data.{{ dt.key.name }}());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::updateSnapshotKeys{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT {{ dt.recTable.ddsKey.dbColumnName }}, {{ dt.recTable.primaryKey.dbColumnName }}, dds_is_alive FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > ") + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) +
|
||||
QStringLiteral(" ORDER BY sample_time "));
|
||||
|
||||
DEBUG_LOG(m_logger) << "stmt: " << stmt;
|
||||
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
|
||||
while (q.next())
|
||||
{
|
||||
const qint64 key = q.value(0){{ dt.recTable.ddsKey.cppFromQvPost }};
|
||||
const qint64 pk = q.value(1){{ dt.recTable.primaryKey.cppFromQvPost }};
|
||||
const bool isAlive = q.value(2).toBool();
|
||||
if (isAlive)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "INSERT {{ dt.name }} key: " << key << ", pk: " << pk << ", isAlive: " << isAlive;
|
||||
m_snapshot{{ dt.name }}Map[key] = pk;
|
||||
m_{{ dt.nameFlc }}Keys.insert(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "REMOVE {{ dt.name }} key: " << key << ", pk: " << pk << ", isAlive: " << isAlive;
|
||||
m_snapshot{{ dt.name }}Map.erase(key);
|
||||
m_{{ dt.nameFlc }}Keys.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
// new validity time for snapshot data
|
||||
m_snapshot{{ dt.name }}MapTime = toTime;
|
||||
|
||||
DEBUG_LOG(m_logger) << "updateSnapshotKeys{{ dt.name }}(" << fromTime << ", " << toTime << ") = "
|
||||
<< m_snapshot{{ dt.name }}Map.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::readLastSnapshotKeysFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT rec_id_array FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(fromTime));
|
||||
|
||||
// no previous snapshot found?
|
||||
if (!q.exec(stmt))
|
||||
return false;
|
||||
if (!q.next() || q.value(0).isNull())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "no snapshot entry for {{ dt.name }} found";
|
||||
return true;
|
||||
}
|
||||
|
||||
m_snapshot{{ dt.name }}Map = LtsUtils::BigintArray2D::fromPgString(q.value(0).toString())();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Map size {{ dt.name }}: " << m_snapshot{{ dt.name }}Map.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
qint64 RecordReplayPlugin::getNextSampleTimeFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT MIN(sample_time) FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > ") + QString::number(fromTime));
|
||||
qint64 ret = -1;
|
||||
if (q.execAndFetch(stmt) && !q.value(0).isNull())
|
||||
ret = q.value(0).toLongLong();
|
||||
|
||||
DEBUG_LOG(m_logger) << "next min sampleTime for {{ dt.name }} is " << ret << " (> " << fromTime << ")";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPlugin::publish{{ dt.name }}(qint64 desiredTime)
|
||||
{
|
||||
if (!m_dts{{ dt.name }})
|
||||
return false;
|
||||
{
|
||||
auto it = m_{{ dt.nameFlc }}Map.begin();
|
||||
while (it != m_{{ dt.nameFlc }}Map.end() && it.key() <= desiredTime)
|
||||
{
|
||||
m_dts{{ dt.name }}->write(it.value());
|
||||
it = m_{{ dt.nameFlc }}Map.erase(it);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto it = m_{{ dt.nameFlc }}DisposedMap.begin();
|
||||
while (it != m_{{ dt.nameFlc }}DisposedMap.end() && it.key() <= desiredTime)
|
||||
{
|
||||
m_dts{{ dt.name }}->remove(it.value());
|
||||
it = m_{{ dt.nameFlc }}DisposedMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordReplayPlugin::clearData{{ dt.name }}()
|
||||
{
|
||||
if (m_dts{{ dt.name }})
|
||||
{
|
||||
{{ dt.name }} tmpData;
|
||||
for (auto key : m_{{ dt.nameFlc }}Keys)
|
||||
{
|
||||
tmpData.{{ dt.key.name }}(key);
|
||||
m_dts{{ dt.name }}->remove(tmpData);
|
||||
}
|
||||
}
|
||||
m_{{ dt.nameFlc }}Keys.clear();
|
||||
m_{{ dt.nameFlc }}Map.clear();
|
||||
m_{{ dt.nameFlc }}DisposedMap.clear();
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyInitialData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 startTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT id FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE svc_name = '{{ namespace_abbr}}' AND topic_name = '{{ dt.name }}' AND time_stamp <= %1 "
|
||||
" ORDER BY time_stamp DESC LIMIT 1").arg(startTime));
|
||||
|
||||
if (!queryFrom.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while fetch max(time_stamp) for topic {{ dt.name }}";
|
||||
return false;
|
||||
}
|
||||
if (!queryFrom.next() || queryFrom.value(0).isNull())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No snapshot available for topic {{ dt.name }}";
|
||||
return true;
|
||||
}
|
||||
const qint64 idSnapshot = queryFrom.value(0).toLongLong();
|
||||
|
||||
const QString stmtSelect(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE rec_id IN (SELECT reduce_dim2(rec_id_array) FROM ") + getTableName(QStringLiteral("rec_snapshot"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE id = ") + QString::number(idSnapshot) + QLatin1Char(')'));
|
||||
|
||||
if (!queryFrom.exec(stmtSelect))
|
||||
return false;
|
||||
|
||||
return copyDataPrepared{{ dt.name }}(queryFrom, queryTo);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
const QString stmt(QStringLiteral("SELECT dds_is_alive, {% for row in dt.recTable.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} FROM ") +
|
||||
getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasRead) +
|
||||
QStringLiteral(" WHERE sample_time > " ) + QString::number(fromTime) +
|
||||
QStringLiteral(" AND sample_time <= ") + QString::number(toTime) + QLatin1Char(';'));
|
||||
|
||||
if (!queryFrom.exec(stmt))
|
||||
return false;
|
||||
|
||||
return copyDataPrepared{{ dt.name }}(queryFrom, queryTo);
|
||||
}
|
||||
|
||||
bool RecordReplayPlugin::copyDataPrepared{{ dt.name }}(NSqlQuery &queryFromPrepared, NSqlQuery &queryTo)
|
||||
{
|
||||
const QString stmtInsert(QStringLiteral("INSERT INTO ") + getTableName(QStringLiteral("{{ dt.recTable.name }}"), m_bCanHandleSchemasWrite) +
|
||||
QStringLiteral(" ( dds_is_alive, {% for row in dt.recTable.cppMember %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}) VALUES "
|
||||
" (:dds_is_alive, {% for row in dt.recTable.cppMember %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %});"));
|
||||
|
||||
if (!queryTo.prepare(stmtInsert))
|
||||
return false;
|
||||
|
||||
while (queryFromPrepared.next())
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
queryTo.bindValue(QStringLiteral(":dds_is_alive"), queryFromPrepared.value(i++));
|
||||
{% for row in dt.recTable.cppMember %}
|
||||
queryTo.bindValue(QStringLiteral(":{{ row.dbColumnName }}"), queryFromPrepared.value(i++));
|
||||
{% endfor %}
|
||||
if (!queryTo.exec())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* RecordReplay Plugin
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-07-21
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_record_replay_plugin.h
|
||||
#pragma once
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QVector>
|
||||
#include <set>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dtc_types.h>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_dts_types.h>
|
||||
#include <{{ include_prefix }}/logger.h>
|
||||
|
||||
// Resolved from the Lts include root (see include_directories(BEFORE .../Lts)
|
||||
// in the root CMakeLists); the old <../../Common/...> spelling only worked
|
||||
// for in-source builds.
|
||||
#include <Common/PluginInterfaces/record_replay_plugin.h>
|
||||
|
||||
#include <LtsUtilsCore/pgarray.h>
|
||||
|
||||
{% if custom_record_replay %}
|
||||
#ifndef {{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define {{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_{{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_LIB)
|
||||
# define {{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define {{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
{% endif %}
|
||||
|
||||
namespace {{ namespace }} {
|
||||
|
||||
class {% if custom_record_replay %}{{ namespace_abbr_upper }}RECORDREPLAYPLUGIN_EXPORT{% endif %}
|
||||
RecordReplayPlugin {% if not custom_record_replay %}final{% endif %}: public QObject, public RecordReplay::RecordReplayPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
{% if not custom_record_replay %}
|
||||
Q_PLUGIN_METADATA(IID "special:3:recordreplay.{{ namespace_abbr }}")
|
||||
{% endif %}
|
||||
Q_INTERFACES(RecordReplay::RecordReplayPlugin)
|
||||
public:
|
||||
RecordReplayPlugin();
|
||||
~RecordReplayPlugin();
|
||||
QString pluginName() const override { return QStringLiteral("{{ namespace_abbr }}RecordReplayPlugin"); }
|
||||
|
||||
bool initDtc(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId) override;
|
||||
bool initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query) override;
|
||||
bool initCopy(int exerciseId, bool bCanHandleSchemasRead, bool bCanHandleSchemasWrite) override;
|
||||
bool copyData(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime) override;
|
||||
QString svcShortName() const override { return QStringLiteral("{{ namespace_abbr }}"); }
|
||||
// recording functions
|
||||
bool ddsTopicsToDatabase(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes) override;
|
||||
// publishing functions
|
||||
bool setReplayStartTime(NSqlQuery &q, qint64 startTime) override;
|
||||
bool ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime) override;
|
||||
bool publishData(qint64 desiredTime) override;
|
||||
void clearData() override;
|
||||
|
||||
// structure/functions for snapshot creation
|
||||
std::map<QString, std::vector<RecSnapshot>> getSnapshotTimes(NSqlQuery &query,
|
||||
qint64 toTime,
|
||||
qint64 interval,
|
||||
const QHash<QString, qint64> &minRecordedSampleTimes) override;
|
||||
QVector<QString> getRecordTopicNames() const override;
|
||||
QVector<QString> getRecordTableNames() const override;
|
||||
qint64 getMinimumSampleTime(NSqlQuery &q, const QString &topicName, qint64 defaultValue) const override;
|
||||
|
||||
// getter for initial service startup
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
// {{ dt.name }}
|
||||
QMultiMap<qint64, {{ include_prefix }}::{{ dt.name }}> &get{{ dt.name }}Map() { return m_{{ dt.nameFlc }}Map; }
|
||||
const QMultiMap<qint64, {{ include_prefix }}::{{ dt.name }}> &get{{ dt.name }}Map() const { return m_{{ dt.nameFlc }}Map; }
|
||||
bool read{{ dt.name }}At(NSqlQuery &q, qint64 startTime);
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
protected:
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
// {{ dt.name }}
|
||||
bool write{{ dt.name }}(NSqlQuery &q, QHash<QString, qint64> &minRecordSampleTimes);
|
||||
bool read{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime);
|
||||
bool readLastSnapshotFor{{ dt.name }}(NSqlQuery &q, qint64 startTime);
|
||||
bool updateSnapshotKeys{{ dt.name }}(NSqlQuery &q, qint64 fromTime, qint64 toTime);
|
||||
bool readLastSnapshotKeysFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime);
|
||||
qint64 getNextSampleTimeFor{{ dt.name }}(NSqlQuery &q, qint64 fromTime);
|
||||
bool publish{{ dt.name }}(qint64 desiredTime);
|
||||
void clearData{{ dt.name }}();
|
||||
bool copyInitialData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 startTime);
|
||||
bool copyData{{ dt.name }}(NSqlQuery &queryFrom, NSqlQuery &queryTo, qint64 fromTime, qint64 toTime);
|
||||
bool copyDataPrepared{{ dt.name }}(NSqlQuery &queryFromPrepared, NSqlQuery &queryTo);
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
QString getTableName(const QString &tableName, bool bCanHandleSchemas) const;
|
||||
protected:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
int m_exerciseId;
|
||||
bool m_bCanHandleSchemasRead;
|
||||
bool m_bCanHandleSchemasWrite;
|
||||
{% for dt in dataTopics.member %} {% if dt.recordTopic %}
|
||||
// {{ dt.name }}
|
||||
std::unique_ptr<DTC::{{ dt.name }}> m_dtc{{ dt.name }};
|
||||
std::unique_ptr<DTS::{{ dt.name }}> m_dts{{ dt.name }};
|
||||
QMultiMap<qint64, {{ include_prefix }}::{{ dt.name }}> m_{{ dt.nameFlc }}Map;
|
||||
QMultiMap<qint64, {{ include_prefix }}::{{ dt.name }}> m_{{ dt.nameFlc }}DisposedMap;
|
||||
std::set<qint64> m_{{ dt.nameFlc }}Keys;
|
||||
std::map<int64_t,int64_t> m_snapshot{{ dt.name }}Map;
|
||||
int64_t m_snapshot{{ dt.name }}MapTime = -1; // time for which the snapshot is valid
|
||||
{% endif %} {% endfor %}
|
||||
|
||||
NGL::INGLLogger& m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
{% endautoescape %}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* DDS Type Plugin to provide custom types to other applications like ddsview
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-07-08
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_topic_type_plugin.cpp
|
||||
|
||||
#include "{{ namespace_abbr }}_topic_type_plugin.h"
|
||||
#include <{{ namespace_abbr }}_dtc_types.h>
|
||||
#include <{{ namespace_abbr }}_ftc_types.h>
|
||||
#include <{{ namespace_abbr }}_fts_types.h>
|
||||
#include <DDS/FTC/generic_ftc_impl.h>
|
||||
#include <DDS/FTS/generic_fts_impl.h>
|
||||
#include <DDS/Routing/routing_plugin.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
QMap<std::string, DDSGeneric::TopicDescription> TopicTypePlugin::getDataTopics() const
|
||||
{
|
||||
return
|
||||
{{% for dt in dataTopics.member %}
|
||||
{
|
||||
dds::topic::topic_type_name<{{ dt.name }}>::value(),
|
||||
{
|
||||
DDS::Helper::getShortTopicName(dds::topic::topic_type_name<{{ dt.name }}>::value()),
|
||||
dds::topic::topic_type_name<{{ dt.name }}>::value(),
|
||||
rti::topic::dynamic_type<{{ dt.name }}>::get()
|
||||
}
|
||||
}{% if not forloop.last %}, {% endif %}{% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
QMap<std::string, DDSGeneric::TopicDescription> TopicTypePlugin::getFunctionTopics() const
|
||||
{
|
||||
return
|
||||
{{% for ft in functionTopics.member %}
|
||||
{
|
||||
FTC::TopicNames<FTC::{{ ft.name }}>::requestTopicName(),
|
||||
{
|
||||
FTC::TopicNames<FTC::{{ ft.name }}>::requestTopicName(),
|
||||
dds::topic::topic_type_name<FTC::{{ ft.name }}::RequestTopic>::value(),
|
||||
rti::topic::dynamic_type<FTC::{{ ft.name }}::RequestTopic>::get()
|
||||
}
|
||||
},
|
||||
{
|
||||
FTC::TopicNames<FTC::{{ ft.name }}>::replyTopicName(),
|
||||
{
|
||||
FTC::TopicNames<FTC::{{ ft.name }}>::replyTopicName(),
|
||||
dds::topic::topic_type_name<FTC::{{ ft.name }}::ReplyTopic>::value(),
|
||||
rti::topic::dynamic_type<FTC::{{ ft.name }}::ReplyTopic>::get()
|
||||
}
|
||||
}{% if not forloop.last %}, {% endif %}{% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
inline NGL::INGLLogger &logger(const char *name)
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(name);
|
||||
}
|
||||
|
||||
std::vector<RoutingService::TopicDispatcherInterface *> TopicTypePlugin::topicsToRouteToWs(IDL::PartitionType partitionType) const
|
||||
{
|
||||
if (partitionType == IDL::PartitionType::Replay)
|
||||
return
|
||||
{{% for dt in dataTopics.topicsToRouteInReplay %}
|
||||
new RoutingService::DataTopicDispatcher<{{ dt.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ dt.name }}")),{% endfor %}
|
||||
{% for ft in functionTopics.topicsToRouteInReplay %}
|
||||
new RoutingService::FunctionTopicReplyDispatcher<FTS::{{ ft.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ ft.name }}.Reply")){% if not forloop.last %},{% endif %}{% endfor %}
|
||||
};
|
||||
|
||||
return
|
||||
{{% for dt in dataTopics.topicsToRouteToClient %}
|
||||
new RoutingService::DataTopicDispatcher<{{ dt.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ dt.name }}")),{% endfor %}
|
||||
{% for ft in functionTopics.member %}
|
||||
new RoutingService::FunctionTopicReplyDispatcher<FTS::{{ ft.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ ft.name }}.Reply")){% if not forloop.last %},{% endif %}{% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<RoutingService::TopicDispatcherInterface *> TopicTypePlugin::topicsToRouteToSv(IDL::PartitionType partitionType) const
|
||||
{
|
||||
if (partitionType == IDL::PartitionType::Replay)
|
||||
return
|
||||
{{% for ft in functionTopics.topicsToRouteInReplay %}
|
||||
new RoutingService::FunctionTopicRequestDispatcher<FTC::{{ ft.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ ft.name }}.Request")){% if not forloop.last %},{% endif %}{% endfor %}
|
||||
};
|
||||
|
||||
return
|
||||
{{% for dt in dataTopics.topicsToRouteToServer %}
|
||||
new RoutingService::DataTopicDispatcher<{{ dt.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ dt.name }}")),{% endfor %}
|
||||
{% for ft in functionTopics.member %}
|
||||
new RoutingService::FunctionTopicRequestDispatcher<FTC::{{ ft.name }}>(logger("RSC.{{ namespace_abbr_upper }}.{{ ft.name }}.Request")){% if not forloop.last %},{% endif %}{% endfor %}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* DDS Type Plugin to provide custom types to other applications like ddsview
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-07-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_topic_type_plugin.h
|
||||
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}.hpp>
|
||||
#include <Common/ProjectConfig/project_defines.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
// Resolved from the Lts include root (see include_directories(BEFORE .../Lts)
|
||||
// in the root CMakeLists); the old <../../DDS/...> spelling only worked for
|
||||
// in-source builds because moc/gcc do not resolve it relative to this file.
|
||||
#include <DDS/Generic/topic_type_plugin.h>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
class TopicTypePlugin final : public QObject, public DDSGeneric::TopicTypePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "topic_type:3:{{ namespace_abbr }}")
|
||||
Q_INTERFACES(DDSGeneric::TopicTypePlugin)
|
||||
public:
|
||||
TopicTypePlugin() = default;
|
||||
|
||||
QMap<std::string, DDSGeneric::TopicDescription> getDataTopics() const override final;
|
||||
QMap<std::string, DDSGeneric::TopicDescription> getFunctionTopics() const override final;
|
||||
std::vector<RoutingService::TopicDispatcherInterface *> topicsToRouteToWs(IDL::PartitionType partitionType) const override final;
|
||||
std::vector<RoutingService::TopicDispatcherInterface *> topicsToRouteToSv(IDL::PartitionType partitionType) const override final;
|
||||
QString getServiceShortName() const override final { return QStringLiteral("{{ namespace_abbr_upper }}"); }
|
||||
};
|
||||
}
|
||||
|
||||
{% endautoescape %}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Convert DSS enumerations to translatable strings
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
// filename: {{ namespace_abbr }}_translation.cpp
|
||||
|
||||
#include "{{ namespace_abbr }}_translation.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
{% for idl_enum in idl_enums %}
|
||||
//
|
||||
// {{ idl_enum.name }}
|
||||
//
|
||||
QString toString({{ idl_enum.name }} state)
|
||||
{
|
||||
switch(state)
|
||||
{{% for idl_member in idl_enum.member %}
|
||||
case {{ idl_enum.name }}::{{ idl_member.key }}: return QCoreApplication::translate("{{ idl_enum.name }}", "{{ idl_member.key }}");
|
||||
{% endfor %}
|
||||
default: break;
|
||||
}
|
||||
return QCoreApplication::translate("{{ idl_enum.name }}", "Unknown (%1)").arg(static_cast<int>(state));
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
{% for dt in dataTopics.member %}{% if dt.hasTrColumns %}{% for tr in dt.trColumns %}
|
||||
// {{ dt.name }}::{{ tr.name }}
|
||||
QString tr{{ dt.name }}{{ tr.nameCc }}(const std::string &text)
|
||||
{
|
||||
return QCoreApplication::translate("{{ dt.name }}", text.c_str(), "{{ tr.name }}");
|
||||
}
|
||||
{% endfor %}{% endif %}{% endfor %}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Convert DSS enumerations to translatable strings
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
{% autoescape off %}
|
||||
#pragma once
|
||||
|
||||
// filename: {{ namespace_abbr }}_translation.h
|
||||
|
||||
#include <string>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_enums.hpp>
|
||||
#include <{{ include_prefix }}/{{ namespace_abbr }}_export.h>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace {{ namespace }}
|
||||
{
|
||||
// Translatable enumerations:
|
||||
{% for idl_enum in idl_enums %}
|
||||
{{ namespace_abbr_upper }}_COMMON_EXPORT QString toString({{ idl_enum.name }} state);{% endfor %}
|
||||
|
||||
// Translatable struct members:
|
||||
{% for dt in dataTopics.member %}{% if dt.hasTrColumns %}{% for tr in dt.trColumns %}
|
||||
{{ namespace_abbr_upper }}_COMMON_EXPORT QString tr{{ dt.nameCc }}{{ tr.nameCc }}(const std::string &text); // {{ dt.nameCc }}::{{ tr.name }} {% endfor %}{% endif %}{% endfor %}
|
||||
|
||||
} // namespace {{ namespace }}
|
||||
|
||||
{% endautoescape %}
|
||||
@@ -1,70 +0,0 @@
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <ktexttemplate/engine.h>
|
||||
#include <ktexttemplate/templateloader.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QString templatesDir = QDir::currentPath();
|
||||
if (argc > 1)
|
||||
{
|
||||
templatesDir = QString::fromLocal8Bit(argv[1]);
|
||||
}
|
||||
|
||||
KTextTemplate::Engine engine;
|
||||
auto loader = QSharedPointer<KTextTemplate::FileSystemTemplateLoader>::create();
|
||||
loader->setTemplateDirs(QStringList() << templatesDir);
|
||||
engine.addTemplateLoader(loader);
|
||||
|
||||
QDir d(templatesDir);
|
||||
QStringList files = d.entryList(QStringList() << QStringLiteral("*.grantlee"), QDir::Files);
|
||||
if (files.isEmpty())
|
||||
{
|
||||
qDebug() << "No .grantlee templates found in" << templatesDir;
|
||||
// Treat absence as successful parse (nothing to check) to avoid failing
|
||||
// when directory is empty in different setups.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
for (const QString& f : files)
|
||||
{
|
||||
KTextTemplate::Template t;
|
||||
try
|
||||
{
|
||||
t = engine.loadByName(f);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qDebug() << "Exception while loading" << f;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
if (!t)
|
||||
{
|
||||
qDebug() << "Failed to load template" << f;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
if (t->error() != KTextTemplate::NoError)
|
||||
{
|
||||
qDebug() << "Parse error in" << f << ":" << t->errorString();
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
// Render with empty context to ensure rendering path also works.
|
||||
KTextTemplate::Context ctx;
|
||||
QString out = t->render(&ctx);
|
||||
if (out.isNull())
|
||||
{
|
||||
qDebug() << "Rendering produced null for" << f;
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ok ? 0 : 2;
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#include "AppChooser/app_chooser_model.h"
|
||||
#include "ui_app.h"
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
CustomViewApp::CustomViewApp(QWidget* parent) : AbstractDisplayWidget(parent), m_ui(new Ui::CustomViewApp)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->image->setMenuEnabled(false);
|
||||
}
|
||||
|
||||
CustomViewApp::~CustomViewApp()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool CustomViewApp::init(const QModelIndex& idx)
|
||||
{
|
||||
if (!idx.isValid())
|
||||
return false;
|
||||
|
||||
m_ui->lbAppName->setText(rowData(idx, AppChooserModel::Name).toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <QtCore/QObject>
|
||||
#include <Viewer/LtsDataView/abstract_display_widget.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class CustomViewApp;
|
||||
}
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
class CustomViewApp final : public LtsDataView::AbstractDisplayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CustomViewApp(QWidget* parent = nullptr);
|
||||
~CustomViewApp();
|
||||
bool init(const QModelIndex& idx) override;
|
||||
|
||||
private:
|
||||
Ui::CustomViewApp* m_ui;
|
||||
};
|
||||
|
||||
} // namespace LtsAppManager
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CustomViewApp</class>
|
||||
<widget class="QWidget" name="CustomViewApp">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsImageEditor" name="image">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbAppName">
|
||||
<property name="text">
|
||||
<string notr="true"><App Name></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbDescription">
|
||||
<property name="text">
|
||||
<string notr="true"><html><head/><body><p>&lt;Description with wordwrap&gt;</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsImageEditor</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsWidgets/lts_image_editor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
|
||||
#include "AppChooser/app_chooser.h"
|
||||
|
||||
#include "AppChooser/CustomViews/app.h"
|
||||
#include "AppChooser/app_chooser_model.h"
|
||||
#include "lts_app_manager.h"
|
||||
#include "ui_app_chooser.h"
|
||||
|
||||
#include <QtGui/QCloseEvent>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
AppChooser::AppChooser() : QWidget(nullptr), m_ui(new Ui::AppChooser), m_model(), m_madeSelection(false)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(m_ui->widget, &LtsDataView::LtsDataView::LtsDataView::signalDoubleClicked, this,
|
||||
&AppChooser::slotAppSelected);
|
||||
connect(m_ui->widget, &LtsDataView::LtsDataView::LtsDataView::signalEnterPressed, this,
|
||||
&AppChooser::slotAppSelected);
|
||||
connect(m_ui->widget, &LtsDataView::LtsDataView::LtsDataView::signalSelectionChanged, this, &AppChooser::enaDisa);
|
||||
connect(m_ui->pbQuit, &QPushButton::clicked, this, &QWidget::close);
|
||||
connect(m_ui->pbSelect, &QPushButton::clicked, this, &AppChooser::slotAppSelected);
|
||||
|
||||
m_model = new AppChooserModel(this);
|
||||
m_model->initModel(LtsAppManager::getInstance()->getAvailableApps());
|
||||
|
||||
m_ui->widget->seamless();
|
||||
|
||||
m_ui->widget->setModel(m_model);
|
||||
m_ui->widget->hideColumn(AppChooserModel::Columns::Visible);
|
||||
}
|
||||
|
||||
AppChooser::~AppChooser()
|
||||
{
|
||||
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void AppChooser::slotQuit()
|
||||
{
|
||||
if (m_alreadyCloseEmitted)
|
||||
return;
|
||||
m_alreadyCloseEmitted = true;
|
||||
emit signalLogout();
|
||||
}
|
||||
|
||||
void AppChooser::closeEvent(QCloseEvent*)
|
||||
{
|
||||
if (!m_madeSelection)
|
||||
slotQuit();
|
||||
}
|
||||
|
||||
void AppChooser::slotAppSelected()
|
||||
{
|
||||
const QModelIndex idx = m_ui->widget->currentIndex();
|
||||
const LtsAppDescriptor::AppDescription app = m_model->getRowData(idx.row());
|
||||
|
||||
if (!app.active)
|
||||
return;
|
||||
|
||||
hide();
|
||||
m_madeSelection = true;
|
||||
emit signalAppSelected(app.id);
|
||||
close();
|
||||
}
|
||||
|
||||
void AppChooser::enaDisa()
|
||||
{
|
||||
const QModelIndexList selectedRows = m_ui->widget->selectedRows();
|
||||
const int cntSelectedRows = selectedRows.size();
|
||||
|
||||
m_ui->pbSelect->setEnabled(cntSelectedRows == 1);
|
||||
}
|
||||
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
#include <LtsAppDescriptor/lts_app_descriptor.h>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AppChooser;
|
||||
}
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
class AppChooserModel;
|
||||
|
||||
class AppChooser : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AppChooser();
|
||||
~AppChooser();
|
||||
|
||||
private:
|
||||
Ui::AppChooser* m_ui;
|
||||
AppChooserModel* m_model;
|
||||
bool m_madeSelection;
|
||||
bool m_alreadyCloseEmitted{false};
|
||||
|
||||
void enaDisa();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent*);
|
||||
|
||||
signals:
|
||||
void signalAppSelected(LtsAppDescriptor::App appId);
|
||||
void signalLogout();
|
||||
|
||||
private slots:
|
||||
void slotAppSelected();
|
||||
void slotQuit();
|
||||
};
|
||||
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AppChooser</class>
|
||||
<widget class="QWidget" name="AppChooser">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>App Chooser</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../LtsWidgets/resources/lts_resources.qrc">
|
||||
<normaloff>:/rde_icon_256.png</normaloff>:/rde_icon_256.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Select App:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">Viewer/LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../LtsWidgets/resources/lts_resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
|
||||
|
||||
#include "app_chooser_model.h"
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
AppChooserModel::AppChooserModel(QObject* parent)
|
||||
: LtsWidgets::LtsAbstractTableModel<LtsAppDescriptor::AppDescription>({tr("Name")}, parent)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
bool AppChooserModel::initModel(const LtsAppDescriptor::AppDescriptionVector& availableApps)
|
||||
{
|
||||
for (auto i = availableApps.constBegin(); i != availableApps.constEnd(); ++i)
|
||||
{
|
||||
const LtsAppDescriptor::AppDescription& appDesc = *i;
|
||||
|
||||
if (!appDesc.visible)
|
||||
continue;
|
||||
|
||||
insertRow(appDesc);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant AppChooserModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || !indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
const LtsAppDescriptor::AppDescription& ad = m_vecData.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case Name:
|
||||
return LtsSession::LtsSession::appToString(ad.id);
|
||||
case Visible:
|
||||
return ad.visible;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
} // namespace LtsAppManager
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
#include <LtsAppDescriptor/lts_app_descriptor.h>
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
class AppChooserModel final : public LtsWidgets::LtsAbstractTableModel<LtsAppDescriptor::AppDescription>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns {
|
||||
Name = 0,
|
||||
Visible,
|
||||
};
|
||||
|
||||
explicit AppChooserModel(QObject* parent = nullptr);
|
||||
|
||||
bool initModel(const LtsAppDescriptor::AppDescriptionVector& availableApps);
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override final;
|
||||
};
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,71 +0,0 @@
|
||||
# Make ${Qt6_Gui} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Gui)
|
||||
set(Qt6_Gui ${Qt6_Gui})
|
||||
else()
|
||||
set(Qt6_Gui "")
|
||||
endif()
|
||||
|
||||
# Make ${Qt6_Widgets} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Widgets)
|
||||
set(Qt6_Widgets ${Qt6_Widgets})
|
||||
else()
|
||||
set(Qt6_Widgets "")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Mike Wille, SLSE, 2016-10-27
|
||||
#
|
||||
|
||||
|
||||
# LtsAppManager
|
||||
|
||||
set(LtsAppManager_SRCS
|
||||
lts_app_manager.cpp
|
||||
AppChooser/app_chooser.cpp
|
||||
AppChooser/app_chooser_model.cpp
|
||||
AppChooser/CustomViews/app.cpp
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(LtsAppManager_SRCS
|
||||
AppChooser/app_chooser.ui
|
||||
AppChooser/CustomViews/app.ui
|
||||
)
|
||||
|
||||
IF(BUILD_RTI)
|
||||
NGL_ADD_LIBRARY2(WS LtsAppManager SHARED ${LtsAppManager_SRCS})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsAppManager
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AppChooser/
|
||||
)
|
||||
|
||||
if(QT6_GUI_AVAILABLE)
|
||||
NGL_TARGET_LINK_LIBRARIES(LtsAppManager
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
LtsDataView
|
||||
LtsWidgets
|
||||
LtsLogin
|
||||
LtsPluginManager
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
LtsUtilsSettings
|
||||
LtsMultiMonitor
|
||||
ProjectConfig
|
||||
${Qt6_Gui}
|
||||
${Qt6_Widgets}
|
||||
Qt6::Network # debug server
|
||||
OpmSettingsGuiPluginInterface
|
||||
LtsPluginLoader
|
||||
PUBLIC
|
||||
Qt6::Core
|
||||
LtsAppDescriptor
|
||||
)
|
||||
endif()
|
||||
|
||||
NGL_INSTALL_TARGET(LtsAppManager)
|
||||
ENDIF(BUILD_RTI)
|
||||
@@ -1,963 +0,0 @@
|
||||
#include "lts_app_manager.h"
|
||||
|
||||
#include "AppChooser/app_chooser.h"
|
||||
|
||||
#include <LtsLogin/lts_login.h>
|
||||
#include <LtsMultiMonitor/lts_multi_monitor.h>
|
||||
#include <LtsPluginManager/lts_plugin_manager.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <LtsWidgets/lts_events.h>
|
||||
#include <LtsWidgets/lts_global_wait_dialog.h>
|
||||
#include <OperatorManagement/opm_settings_gui_plugin_interface.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonValue>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtNetwork/QTcpServer>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QUuid>
|
||||
#include <utility>
|
||||
|
||||
#ifndef LTS_VERSION_MAJOR
|
||||
#define LTS_VERSION_MAJOR "undefined"
|
||||
#endif
|
||||
#ifndef LTS_VERSION_MINOR
|
||||
#define LTS_VERSION_MINOR "undefined"
|
||||
#endif
|
||||
#ifndef LTS_VERSION_PATCH
|
||||
#define LTS_VERSION_PATCH "undefined"
|
||||
#endif
|
||||
#ifndef JENKINS_BUILD_NUMBER
|
||||
#define JENKINS_BUILD_NUMBER "unknown"
|
||||
#endif
|
||||
static const char ver_major[] = LTS_VERSION_MAJOR;
|
||||
static const char ver_minor[] = LTS_VERSION_MINOR;
|
||||
static const char ver_patch[] = LTS_VERSION_PATCH;
|
||||
static const char ver_jenkins[] = JENKINS_BUILD_NUMBER;
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
struct LtsAppManagerHandler
|
||||
{
|
||||
LtsAppManager ltsAppManager;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(LtsAppManagerHandler, s_ltsAppManager)
|
||||
|
||||
LtsAppManager* LtsAppManager::getInstance()
|
||||
{
|
||||
return &s_ltsAppManager->ltsAppManager;
|
||||
}
|
||||
|
||||
LtsAppManager::LtsAppManager() : m_login(nullptr)
|
||||
{
|
||||
|
||||
qRegisterMetaType<LtsAppDescriptor::App>("LtsAppDescriptor::App");
|
||||
slotStartDebugServer();
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, this, [this] {
|
||||
delete m_login;
|
||||
m_login = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
LtsAppManager::~LtsAppManager()
|
||||
{
|
||||
|
||||
delete m_login;
|
||||
m_login = nullptr;
|
||||
}
|
||||
|
||||
void LtsAppManager::setAvailableApps(const LtsAppDescriptor::AppDescriptionVector& availableApps)
|
||||
{
|
||||
m_availableApps = availableApps;
|
||||
|
||||
#ifndef LTS_DEBUG
|
||||
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(
|
||||
QStringLiteral("PluginManager.CheckAppRequirements")) == QVariant(true))
|
||||
{
|
||||
QMessageBox::information(nullptr, QStringLiteral("LtsAppManager"),
|
||||
QStringLiteral("Checking App Requirements now"));
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
QStringList errors;
|
||||
LtsPluginManager::LtsPluginLoader::getInstance()->checkPlugins(availableApps, errors);
|
||||
|
||||
if (!errors.isEmpty())
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("LtsAppManager"),
|
||||
QStringLiteral("App Requirements check failed!<br> - %1").arg(errors.join(QStringLiteral("<br> - "))));
|
||||
}
|
||||
|
||||
if (m_availableApps.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("App Manager"),
|
||||
tr("There are no apps available for this project.\nPlease contact Support."));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void LtsAppManager::slotStartDebugServer()
|
||||
{
|
||||
QTcpServer* debugServer = new QTcpServer(this);
|
||||
|
||||
if (!debugServer->listen(QHostAddress::Any, 20000))
|
||||
{
|
||||
debugServer->deleteLater();
|
||||
const int waitTryAgain = 5;
|
||||
#ifdef LTS_DEBUG
|
||||
|
||||
#endif
|
||||
QTimer::singleShot(waitTryAgain * 1000, this, &LtsAppManager::slotStartDebugServer);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(debugServer, &QTcpServer::newConnection, this, [this]() {
|
||||
QTcpServer* server = qobject_cast<QTcpServer*>(sender());
|
||||
|
||||
if (server == nullptr)
|
||||
return;
|
||||
|
||||
QTcpSocket* client = server->nextPendingConnection();
|
||||
|
||||
if (client == nullptr)
|
||||
return;
|
||||
|
||||
connect(client, &QTcpSocket::readyRead, this, [this]() {
|
||||
QTcpSocket* client = qobject_cast<QTcpSocket*>(sender());
|
||||
|
||||
if (client == nullptr)
|
||||
return;
|
||||
|
||||
QString commandStr(
|
||||
QString::fromUtf8(client->readLine(100)).remove(QStringLiteral("\r")).remove(QStringLiteral("\n")));
|
||||
|
||||
QStringList argList = commandStr.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
||||
|
||||
if (argList.count() < 1)
|
||||
return;
|
||||
|
||||
const QString& command = argList.at(0);
|
||||
|
||||
LtsSessionData::LtsSessionData* sessionData = LtsSessionData::LtsSessionData::getInstance();
|
||||
static QStringList commands;
|
||||
commands << QStringLiteral("showSessions") << QStringLiteral("operator") << QStringLiteral("help")
|
||||
<< QStringLiteral("logout") << QStringLiteral("flag") << QStringLiteral("setFlag")
|
||||
<< QStringLiteral("start") << QStringLiteral("voiceCommand") << QStringLiteral("ftcmock");
|
||||
|
||||
switch (commands.indexOf(command))
|
||||
{
|
||||
case 0: {
|
||||
sessionData->setDebugFlagValue(QStringLiteral("DeveloperTools.ShowSessionsOnce"), true);
|
||||
client->write("K");
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
QString operatorName(sessionData->getOperatorName());
|
||||
|
||||
if (operatorName.isEmpty())
|
||||
operatorName = QStringLiteral("(none)");
|
||||
|
||||
QString result(QStringLiteral("%1").arg(operatorName));
|
||||
client->write(result.toUtf8());
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
QString result(QStringLiteral("Available Commands: %1").arg(commands.join(QStringLiteral(", "))));
|
||||
client->write(result.toUtf8());
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
client->write("...");
|
||||
slotLogout();
|
||||
client->write("\r\nK");
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
if (argList.count() != 2)
|
||||
{
|
||||
client->write("Usage: flag <flag name>");
|
||||
break;
|
||||
}
|
||||
|
||||
const QString& debugFlagName = argList.at(1);
|
||||
if (!sessionData->hasDebugFlag(debugFlagName))
|
||||
{
|
||||
client->write("(unknown)");
|
||||
break;
|
||||
}
|
||||
|
||||
client->write(sessionData->debugFlagValue(argList.at(1)).toString().toUtf8());
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: {
|
||||
if (argList.count() < 3)
|
||||
{
|
||||
client->write("Usage: setFlag <flag name> <flag type> <value>\r\nFlag types: int, string (no "
|
||||
"spaces allowed yet), boolean, double");
|
||||
break;
|
||||
}
|
||||
|
||||
static QStringList flagTypes;
|
||||
flagTypes << QStringLiteral("int") << QStringLiteral("string") << QStringLiteral("boolean")
|
||||
<< QStringLiteral("double");
|
||||
|
||||
const QString& flagType = argList.at(2);
|
||||
bool k = false;
|
||||
|
||||
const QString& flagName = argList.at(1);
|
||||
|
||||
switch (flagTypes.indexOf(flagType))
|
||||
{
|
||||
case 0: {
|
||||
int value = argList.at(3).toInt(&k);
|
||||
if (k)
|
||||
sessionData->setDebugFlagValue(flagName, value);
|
||||
else
|
||||
client->write("cannot convert value to integer");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
sessionData->setDebugFlagValue(flagName, argList.at(3));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
QString value(argList.at(3).toLower().simplified());
|
||||
if (value == QStringLiteral("true"))
|
||||
sessionData->setDebugFlagValue(flagName, true);
|
||||
else if (value == QStringLiteral("false"))
|
||||
sessionData->setDebugFlagValue(flagName, false);
|
||||
else
|
||||
client->write("cannot convert value to boolean");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
double value = argList.at(3).toDouble(&k);
|
||||
if (k)
|
||||
sessionData->setDebugFlagValue(flagName, value);
|
||||
else
|
||||
client->write("cannot convert value to double");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
client->write("unknown flag type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 6: {
|
||||
if (argList.count() < 3)
|
||||
{
|
||||
client->write("Usage: start <app id> <domain id> ");
|
||||
break;
|
||||
}
|
||||
|
||||
client->write("not implemented yet");
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: {
|
||||
if (argList.count() < 2)
|
||||
{
|
||||
client->write("Usage: voiceCommand <keyword> <optional description>");
|
||||
break;
|
||||
}
|
||||
|
||||
static QStringList keywords;
|
||||
keywords << QStringLiteral("AddMarker") << QStringLiteral("SetMarker")
|
||||
<< QStringLiteral("AddSnapshot") << QStringLiteral("SaveSnapshot");
|
||||
|
||||
const QString& keyword = argList.at(1);
|
||||
|
||||
switch (keywords.indexOf(keyword))
|
||||
{
|
||||
case 0: {
|
||||
auto ev = new LtsWidgets::AddMarkerEvent;
|
||||
ev->setAccepted(false);
|
||||
sessionData->setDebugFlagValue(command, keyword);
|
||||
QCoreApplication::postEvent(qApp, ev);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
auto ev = new LtsWidgets::SetMarkerEvent(QString());
|
||||
if (argList.size() > 2)
|
||||
ev->setDescription(argList.at(2));
|
||||
ev->setAccepted(false);
|
||||
sessionData->setDebugFlagValue(command, keyword);
|
||||
QCoreApplication::postEvent(qApp, ev);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
auto ev = new LtsWidgets::AddSnapshotEvent;
|
||||
ev->setAccepted(false);
|
||||
sessionData->setDebugFlagValue(command, keyword);
|
||||
QCoreApplication::postEvent(qApp, ev);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
auto ev = new LtsWidgets::SaveSnapshotEvent(QString());
|
||||
if (argList.size() > 2)
|
||||
ev->setDescription(argList.at(2));
|
||||
ev->setAccepted(false);
|
||||
sessionData->setDebugFlagValue(command, keyword);
|
||||
QCoreApplication::postEvent(qApp, ev);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sessionData->hasDebugFlag(command))
|
||||
{
|
||||
client->write("(unknown)");
|
||||
break;
|
||||
}
|
||||
|
||||
client->write(sessionData->debugFlagValue(argList.at(1)).toString().toUtf8());
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
auto usage = [client]() {
|
||||
client->write("Usage: ftcmock start <sessionId> <min ms> <max ms> <timer count> - See 'Session "
|
||||
"id' in DevDialog "
|
||||
"\nftcmock stop <sessionId>");
|
||||
};
|
||||
|
||||
if (argList.count() < 3)
|
||||
{
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
|
||||
bool k = false;
|
||||
switch (QStringList({QStringLiteral("start"), QStringLiteral("stop")}).indexOf(argList.at(1)))
|
||||
{
|
||||
case 0: {
|
||||
if (argList.count() < 6)
|
||||
{
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
const int min = argList.at(3).toInt(&k);
|
||||
if (!k || min < 0)
|
||||
{
|
||||
client->write("min must be a positive integer!");
|
||||
return;
|
||||
}
|
||||
|
||||
const int max = argList.at(4).toInt(&k);
|
||||
if (!k || max < 0)
|
||||
{
|
||||
client->write("max must be a positive integer!");
|
||||
return;
|
||||
}
|
||||
|
||||
const int timers = argList.at(5).toInt(&k);
|
||||
if (!k || timers < 1)
|
||||
{
|
||||
client->write("'timer count' must be a positive integer and greater than 0!");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const int sessionId = argList.at(2).toInt(&k);
|
||||
if (!k || sessionId < 0)
|
||||
{
|
||||
client->write("sessionId must be a positive integer!");
|
||||
return;
|
||||
}
|
||||
|
||||
emit signalCommand(client, argList);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
QString result(QStringLiteral("Unknown command '%1'").arg(command));
|
||||
client->write(result.toUtf8());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
client->write("\r\n> ");
|
||||
});
|
||||
|
||||
QString versionString = QStringLiteral("%1.%2-%3 (rev: %4)")
|
||||
.arg(QString::fromLatin1(ver_major), QString::fromLatin1(ver_minor),
|
||||
QString::fromLatin1(ver_jenkins), QString::fromLatin1(ver_patch));
|
||||
|
||||
QString motd(QStringLiteral("\r\nOperatorApplication - Version %1").arg(versionString));
|
||||
client->write(motd.toUtf8());
|
||||
client->write("\r\n> ");
|
||||
});
|
||||
}
|
||||
|
||||
void LtsAppManager::showLogin()
|
||||
{
|
||||
|
||||
QTimer::singleShot(0, this, &LtsAppManager::slotShowLogin);
|
||||
}
|
||||
|
||||
void LtsAppManager::slotShowLogin()
|
||||
{
|
||||
|
||||
if (m_login == nullptr)
|
||||
{
|
||||
m_login = new LtsLogin::LtsLogin;
|
||||
connect(m_login, &LtsLogin::LtsLogin::signalLoginDone, this, [&] {
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
|
||||
#endif
|
||||
if (m_appList.isEmpty())
|
||||
if (!startAppOrLetUserChoose(m_app, {}))
|
||||
QTimer::singleShot(100, this, &LtsAppManager::slotLogout);
|
||||
});
|
||||
|
||||
connect(m_login, &LtsLogin::LtsLogin::signalLogoffDone, this, &LtsAppManager::signalLogoffDone);
|
||||
|
||||
connect(m_login, &LtsLogin::LtsLogin::signalLogoffDone, this, &LtsAppManager::slotShowLogin,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(m_login, &LtsLogin::LtsLogin::signalLogout, this, &LtsAppManager::slotLogout);
|
||||
|
||||
m_login->setLoginPlugin(m_loginPluginIid);
|
||||
}
|
||||
|
||||
m_login->login();
|
||||
}
|
||||
|
||||
bool LtsAppManager::hasRightForApp(const LtsAppDescriptor::AppDescription& appDescription) const
|
||||
{
|
||||
const QSet<int>& acls = LtsSessionData::LtsSessionData::getInstance()->getOperatorRights();
|
||||
for (int reqRight : appDescription.requiredAcls)
|
||||
{
|
||||
if (!acls.contains(reqRight))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, tr("App Manager"),
|
||||
tr("The minimal required operator rights are not met. Therefore, the app cannot be started."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LtsAppManager::taskSwitch(QObject* _caller)
|
||||
{
|
||||
LtsSession::LtsSession* caller = qobject_cast<LtsSession::LtsSession*>(_caller);
|
||||
|
||||
if (caller == nullptr)
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<LtsSession::LtsSession*> sessions;
|
||||
|
||||
for (const LtsPluginManager::LtsPluginManager* app : m_appList)
|
||||
sessions += app->sessions();
|
||||
|
||||
if (sessions.isEmpty())
|
||||
return;
|
||||
|
||||
int sessionCount = sessions.count();
|
||||
|
||||
if (sessionCount < 2)
|
||||
return;
|
||||
|
||||
auto sessionIt = std::find_if(sessions.begin(), sessions.end(),
|
||||
[caller](const LtsSession::LtsSession* session) { return (session == caller); });
|
||||
|
||||
if (sessionIt == sessions.end())
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = ++sessionIt;
|
||||
|
||||
int x = 0;
|
||||
do
|
||||
{
|
||||
|
||||
if (x > 100)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
x++;
|
||||
|
||||
if (it == sessions.end())
|
||||
{
|
||||
|
||||
if (sessions.begin() == sessionIt)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
it = sessions.begin();
|
||||
}
|
||||
|
||||
LtsSession::LtsSession* session = *it;
|
||||
|
||||
QWidget* blw = session->baseLayoutWidget();
|
||||
|
||||
if (blw == nullptr || session->isForeverInvisible() || session == caller)
|
||||
{
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
caller->baseLayoutWidget()->hide();
|
||||
blw->showFullScreen();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (++it != sessionIt);
|
||||
}
|
||||
|
||||
void LtsAppManager::hideAllOtherBLWs(QObject* _caller)
|
||||
{
|
||||
|
||||
if (!LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
return;
|
||||
|
||||
LtsSession::LtsSession* caller = qobject_cast<LtsSession::LtsSession*>(_caller);
|
||||
|
||||
QVector<LtsSession::LtsSession*> sessions;
|
||||
for (const LtsPluginManager::LtsPluginManager* app : m_appList)
|
||||
sessions += app->sessions();
|
||||
|
||||
for (LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
|
||||
QWidget* blw = session->baseLayoutWidget();
|
||||
|
||||
if (blw != nullptr && !session->isForeverInvisible() && session != caller)
|
||||
{
|
||||
|
||||
blw->hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (caller != nullptr)
|
||||
return;
|
||||
|
||||
for (LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
|
||||
QWidget* blw = session->baseLayoutWidget();
|
||||
|
||||
if (blw == nullptr || session->isForeverInvisible())
|
||||
{
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
blw->showFullScreen();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool LtsAppManager::startAppOrLetUserChoose(LtsAppDescriptor::App appId,
|
||||
const LtsSession::DdsConnectionParams& connParams, bool force)
|
||||
{
|
||||
return startAppOrLetUserChoose(getApp(appId), connParams, force);
|
||||
}
|
||||
|
||||
bool LtsAppManager::startAppOrLetUserChoose(const LtsAppDescriptor::AppDescription& appDescription,
|
||||
const LtsSession::DdsConnectionParams& connParams, bool force)
|
||||
{
|
||||
if (!appDescription.active && !force)
|
||||
{
|
||||
|
||||
AppChooser* appChooser = new AppChooser();
|
||||
appChooser->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(appChooser, &AppChooser::signalLogout, this, &LtsAppManager::slotLogout);
|
||||
|
||||
connect(
|
||||
appChooser, &AppChooser::signalAppSelected, this,
|
||||
[this, connParams](LtsAppDescriptor::App appId) {
|
||||
if (createApp(appId, connParams) == nullptr)
|
||||
QTimer::singleShot(100, this, &LtsAppManager::slotLogout);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
appChooser->show();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (createApp(appDescription, connParams, {}, false, force) == nullptr)
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("App Manager"), tr("Could not create app.\nPlease contact support."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LtsPluginManager::LtsPluginManager* LtsAppManager::createApp(LtsAppDescriptor::App appId,
|
||||
const LtsSession::DdsConnectionParams& connParams,
|
||||
const QString& workspaceId, bool hidden, bool force)
|
||||
{
|
||||
return createApp(getApp(appId), connParams, workspaceId, hidden, force);
|
||||
}
|
||||
|
||||
LtsPluginManager::LtsPluginManager* LtsAppManager::createApp(const LtsAppDescriptor::AppDescription& appDescription,
|
||||
const LtsSession::DdsConnectionParams& connParams,
|
||||
const QString& workspaceId, bool hidden, bool force)
|
||||
{
|
||||
if (!appDescription.isValid())
|
||||
{
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!hasRightForApp(appDescription) && !force)
|
||||
return nullptr;
|
||||
|
||||
const bool bDesiredAppHasSituationMapInstance =
|
||||
LtsPluginManager::LtsPluginManager::hasSituationMapInstance(appDescription, true);
|
||||
if (bDesiredAppHasSituationMapInstance)
|
||||
{
|
||||
const int curInstances = getNumberOfSituationMapInstances();
|
||||
|
||||
if (curInstances >= 3 && !force)
|
||||
{
|
||||
if (QMessageBox::Yes !=
|
||||
QMessageBox::question(nullptr, tr("App Manager"),
|
||||
tr("Are you sure you want to launch another resource-intensive app? <br />"
|
||||
"Please note that you are currently running three apps containing the "
|
||||
"resource-intensive map componment. <br />"
|
||||
"It may lead to potential performance issues.")))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto* pluginManager = new LtsPluginManager::LtsPluginManager();
|
||||
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::signalQuit, this, &LtsAppManager::slotQuit);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::signalSoftQuit, this, &LtsAppManager::slotSoftQuit);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::signalLogout, this, &LtsAppManager::slotLogout);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::signalInitializationFinished, this,
|
||||
&LtsAppManager::signalInitializationFinished);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::destroyed, this, &LtsAppManager::slotAppDestroyed);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::hideAllOtherBLWs, this,
|
||||
&LtsAppManager::hideAllOtherBLWs);
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::taskSwitch, this, &LtsAppManager::taskSwitch);
|
||||
#ifdef LTS_DEBUG
|
||||
connect(pluginManager, &LtsPluginManager::LtsPluginManager::signalStillAlive, this, [this]() {
|
||||
auto* app = qobject_cast<LtsPluginManager::LtsPluginManager*>(sender());
|
||||
if (!app)
|
||||
return;
|
||||
|
||||
for (auto i = m_appList.constBegin(); i != m_appList.constEnd(); ++i)
|
||||
{
|
||||
if (*i == app)
|
||||
return;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
if (!pluginManager->startApp(appDescription, false, connParams, workspaceId, hidden))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, tr("App Manager"),
|
||||
tr("The Plugin Manager failed to start the app due to plugin errors.\nPlease contact support."));
|
||||
pluginManager->deleteLater();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_appList.append(pluginManager);
|
||||
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
bool LtsAppManager::hasApp(LtsAppDescriptor::App appId) const
|
||||
{
|
||||
return (std::find_if(m_availableApps.constBegin(), m_availableApps.constEnd(),
|
||||
[appId](const LtsAppDescriptor::AppDescription& app) {
|
||||
bool ret = (app.id == appId);
|
||||
|
||||
return ret;
|
||||
}) != m_availableApps.constEnd());
|
||||
}
|
||||
|
||||
int LtsAppManager::getNumberOfSituationMapInstances() const
|
||||
{
|
||||
int numberOfSituationMapInstances = 0;
|
||||
for (const LtsPluginManager::LtsPluginManager* app : std::as_const(m_appList))
|
||||
{
|
||||
if (!app)
|
||||
continue;
|
||||
|
||||
if (app->hasSituationMapInstance())
|
||||
++numberOfSituationMapInstances;
|
||||
}
|
||||
|
||||
return numberOfSituationMapInstances;
|
||||
}
|
||||
|
||||
LtsAppDescriptor::AppDescription LtsAppManager::getApp(LtsAppDescriptor::App appId) const
|
||||
{
|
||||
for (const LtsAppDescriptor::AppDescription& app : m_availableApps)
|
||||
{
|
||||
|
||||
if (app.id == appId)
|
||||
return app;
|
||||
}
|
||||
|
||||
return LtsAppDescriptor::AppDescription();
|
||||
}
|
||||
|
||||
void LtsAppManager::setMainApp(LtsAppDescriptor::App appId)
|
||||
{
|
||||
m_app = getApp(appId);
|
||||
}
|
||||
|
||||
void LtsAppManager::saveState()
|
||||
{
|
||||
|
||||
if (LtsSessionData::LtsSessionData::getInstance()->getOperatorId() == 0)
|
||||
return;
|
||||
|
||||
QStringList unsavedWorkspaces =
|
||||
LtsUtils::OperatorSettings::getInstance()->identifiers(QStringLiteral("UnsavedWorkspace"));
|
||||
for (auto i = unsavedWorkspaces.constBegin(); i != unsavedWorkspaces.constEnd(); ++i)
|
||||
LtsUtils::OperatorSettings::getInstance()->removeValue(QStringLiteral("UnsavedWorkspace"), *i);
|
||||
|
||||
QStringList unsavedFilterPreset =
|
||||
LtsUtils::OperatorSettings::getInstance()->identifiers(QStringLiteral("UnsavedFilterPreset"));
|
||||
for (auto i = unsavedFilterPreset.constBegin(); i != unsavedFilterPreset.constEnd(); ++i)
|
||||
LtsUtils::OperatorSettings::getInstance()->removeValue(QStringLiteral("UnsavedFilterPreset"), *i);
|
||||
|
||||
QJsonArray root;
|
||||
for (const LtsPluginManager::LtsPluginManager* app : std::as_const(m_appList))
|
||||
{
|
||||
const QVector<LtsSession::LtsSession*> sessions = app->sessions();
|
||||
|
||||
const auto appId = app->appDescription().id;
|
||||
|
||||
if (appId == LtsAppDescriptor::App::Login || sessions.count() < 1)
|
||||
continue;
|
||||
|
||||
QJsonObject appState;
|
||||
appState[QStringLiteral("id")] = static_cast<int>(appId);
|
||||
|
||||
QJsonArray sessionStates;
|
||||
|
||||
for (LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
if (session->baseLayout() != nullptr && session->baseLayout()->isSecondaryWidget())
|
||||
continue;
|
||||
|
||||
QJsonObject sessionState;
|
||||
|
||||
int screenId = session->screenId();
|
||||
|
||||
int screenContainerId = session->screenContainerId();
|
||||
|
||||
sessionState[QStringLiteral("screenId")] = screenId;
|
||||
sessionState[QStringLiteral("screenContainerId")] = screenContainerId;
|
||||
sessionState[QStringLiteral("exerciseId")] = session->exerciseId();
|
||||
sessionState[QStringLiteral("partitionId")] = session->partitionId();
|
||||
sessionState[QStringLiteral("partitionType")] = int(session->partitionType());
|
||||
sessionState[QStringLiteral("savegame")] = session->getSavegame();
|
||||
|
||||
const QString newId(QUuid::createUuid().toString());
|
||||
sessionState[QStringLiteral("workspaceId")] = newId;
|
||||
|
||||
std::shared_ptr<OperatorManagement::ForeignSettingsGuiInterface> ifcOpm;
|
||||
if (session->getForeignGuiInterface<OperatorManagement::ForeignSettingsGuiInterface>(ifcOpm))
|
||||
{
|
||||
|
||||
ifcOpm->callWorkspaceSaveUnsaved(newId);
|
||||
}
|
||||
|
||||
sessionStates.append(sessionState);
|
||||
}
|
||||
|
||||
if (!sessionStates.isEmpty())
|
||||
{
|
||||
appState[QStringLiteral("sessions")] = sessionStates;
|
||||
root.append(appState);
|
||||
}
|
||||
}
|
||||
|
||||
QJsonDocument doc(root);
|
||||
|
||||
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("app"), QStringLiteral("LastAppStates"),
|
||||
doc.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void LtsAppManager::slotLogout()
|
||||
{
|
||||
for (LtsPluginManager::LtsPluginManager* app : std::as_const(m_appList))
|
||||
{
|
||||
const QVector<LtsSession::LtsSession*> sessions = app->sessions();
|
||||
for (LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
if (session->notifyUnsavedChanges() == false)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
saveState();
|
||||
|
||||
const QVector<LtsPluginManager::LtsPluginManager*> apps = m_appList;
|
||||
|
||||
if (apps.isEmpty() && m_login != nullptr)
|
||||
m_login->logoff();
|
||||
|
||||
for (LtsPluginManager::LtsPluginManager* app : apps)
|
||||
app->deleteLater();
|
||||
}
|
||||
|
||||
void LtsAppManager::slotAppDestroyed()
|
||||
{
|
||||
LtsPluginManager::LtsPluginManager* app = static_cast<LtsPluginManager::LtsPluginManager*>(sender());
|
||||
|
||||
m_appList.removeOne(app);
|
||||
|
||||
if (m_appList.isEmpty() && m_login != nullptr)
|
||||
{
|
||||
|
||||
m_login->logoff();
|
||||
}
|
||||
}
|
||||
|
||||
void LtsAppManager::slotQuit()
|
||||
{
|
||||
|
||||
QObject* object = sender();
|
||||
|
||||
if (!object)
|
||||
qCritical()
|
||||
<< "ERROR: LtsAppManager: slot called without object - so it cannot be deleted from the app assignments!";
|
||||
|
||||
LtsPluginManager::LtsPluginManager* app = qobject_cast<LtsPluginManager::LtsPluginManager*>(object);
|
||||
|
||||
if (app == nullptr)
|
||||
{
|
||||
qCritical() << "ERROR: LtsAppManager: quit requested for invalid app";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_appList.count() == 1)
|
||||
{
|
||||
m_appList.removeAll(app);
|
||||
saveState();
|
||||
}
|
||||
|
||||
app->deleteLater();
|
||||
}
|
||||
|
||||
void LtsAppManager::slotSoftQuit()
|
||||
{
|
||||
|
||||
QObject* object = sender();
|
||||
|
||||
LtsPluginManager::LtsPluginManager* app = qobject_cast<LtsPluginManager::LtsPluginManager*>(object);
|
||||
|
||||
if (app == nullptr)
|
||||
{
|
||||
qCritical() << "ERROR: LtsAppManager: quit requested for invalid app";
|
||||
return;
|
||||
}
|
||||
|
||||
app->_softQuit();
|
||||
|
||||
if (m_appList.count() == 1)
|
||||
{
|
||||
m_appList.removeAll(app);
|
||||
saveState();
|
||||
}
|
||||
}
|
||||
|
||||
bool LtsAppManager::otherSessionsResponsibility(LtsSession::LtsSession* thisSession,
|
||||
const QVector<LtsAppDescriptor::App>& requiredAppTypes,
|
||||
const QVector<IDL::PartitionType>& requiredPartitionTypes,
|
||||
const QString& menuGroup, const QString& identifier,
|
||||
LtsWidgets::LayoutArea area)
|
||||
{
|
||||
const QVector<LtsPluginManager::LtsPluginManager*> apps = LtsAppManager::LtsAppManager::getInstance()->getAppList();
|
||||
QVector<LtsPluginManager::LtsPluginManager*> worthyApps;
|
||||
|
||||
for (LtsPluginManager::LtsPluginManager* app : apps)
|
||||
{
|
||||
if (!requiredAppTypes.contains(static_cast<LtsAppDescriptor::App>(app->appDescription().id)))
|
||||
continue;
|
||||
|
||||
worthyApps.append(app);
|
||||
}
|
||||
|
||||
for (const LtsPluginManager::LtsPluginManager* app : std::as_const(worthyApps))
|
||||
{
|
||||
const QVector<LtsSession::LtsSession*> sessions = app->sessions();
|
||||
for (const LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
if (session->widgetExists(menuGroup, identifier, area))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LtsMultiMonitor::LtsMultiMonitor* mm = LtsMultiMonitor::LtsMultiMonitor::getInstance();
|
||||
LtsMultiMonitor::LtsScreenBase* mainScreen = mm->mainScreen();
|
||||
|
||||
for (const LtsPluginManager::LtsPluginManager* app : std::as_const(worthyApps))
|
||||
{
|
||||
const QVector<LtsSession::LtsSession*> sessions = app->sessions();
|
||||
for (LtsSession::LtsSession* session : sessions)
|
||||
{
|
||||
if (session != thisSession && mm->widgetsScreen(session->baseLayoutWidget()) == mainScreen &&
|
||||
requiredPartitionTypes.contains(session->partitionType()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,136 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Lts/Common/ProjectConfig/project_defines.h>
|
||||
#include <LtsAppDescriptor/lts_app_descriptor.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
#include <memory>
|
||||
|
||||
#ifndef LTSAPPMANAGER_EXPORT
|
||||
#ifdef BUILD_STATIC_LIBRARIES
|
||||
#define LTSAPPMANAGER_EXPORT
|
||||
#else
|
||||
#if defined(MAKE_LTSAPPMANAGER_LIB)
|
||||
#define LTSAPPMANAGER_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define LTSAPPMANAGER_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
class LtsPluginManager;
|
||||
}
|
||||
|
||||
namespace LtsLogin
|
||||
{
|
||||
class LtsLogin;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
struct DdsConnectionParams;
|
||||
} // namespace LtsSession
|
||||
|
||||
namespace DeveloperTools
|
||||
{
|
||||
class DevDialog;
|
||||
}
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
namespace LtsAppManager
|
||||
{
|
||||
|
||||
class LTSAPPMANAGER_EXPORT LtsAppManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static LtsAppManager* getInstance();
|
||||
|
||||
void showLogin();
|
||||
|
||||
LtsPluginManager::LtsPluginManager* createApp(LtsAppDescriptor::App appId,
|
||||
const LtsSession::DdsConnectionParams& connParams,
|
||||
const QString& workspaceId = QString(), bool hidden = false,
|
||||
bool force = false);
|
||||
bool startAppOrLetUserChoose(LtsAppDescriptor::App appId, const LtsSession::DdsConnectionParams& connParams,
|
||||
bool force = false);
|
||||
|
||||
void setLoginPluginIid(const QString& loginPluginIid)
|
||||
{
|
||||
m_loginPluginIid = loginPluginIid;
|
||||
}
|
||||
|
||||
void setMainApp(LtsAppDescriptor::App appId = LtsAppDescriptor::App::Login);
|
||||
|
||||
QVector<LtsPluginManager::LtsPluginManager*> getAppList() const
|
||||
{
|
||||
return m_appList;
|
||||
}
|
||||
|
||||
LtsAppDescriptor::AppDescriptionVector getAvailableApps() const
|
||||
{
|
||||
return m_availableApps;
|
||||
}
|
||||
|
||||
void setAvailableApps(const LtsAppDescriptor::AppDescriptionVector& availableApps);
|
||||
bool hasRightForApp(const LtsAppDescriptor::AppDescription& appDescription) const;
|
||||
LtsAppDescriptor::AppDescription getApp(LtsAppDescriptor::App appId) const;
|
||||
bool hasApp(LtsAppDescriptor::App appId) const;
|
||||
int getNumberOfSituationMapInstances() const;
|
||||
void debugSendMessage(const QString& msg);
|
||||
|
||||
bool otherSessionsResponsibility(LtsSession::LtsSession* thisSession,
|
||||
const QVector<LtsAppDescriptor::App>& requiredAppTypes,
|
||||
const QVector<IDL::PartitionType>& requiredPartitionTypes,
|
||||
const QString& menuGroup, const QString& identifier, LtsWidgets::LayoutArea area);
|
||||
|
||||
private:
|
||||
friend struct LtsAppManagerHandler;
|
||||
friend class DeveloperTools::DevDialog;
|
||||
|
||||
LtsAppManager();
|
||||
~LtsAppManager();
|
||||
|
||||
bool startAppOrLetUserChoose(const LtsAppDescriptor::AppDescription& appDescription,
|
||||
const LtsSession::DdsConnectionParams& connParams, bool force = false);
|
||||
LtsPluginManager::LtsPluginManager* createApp(const LtsAppDescriptor::AppDescription& appDescription,
|
||||
const LtsSession::DdsConnectionParams& connParams,
|
||||
const QString& workspaceId = QString(), bool hidden = false,
|
||||
bool force = false);
|
||||
void saveState();
|
||||
|
||||
LtsAppDescriptor::AppDescriptionVector m_availableApps;
|
||||
QVector<LtsPluginManager::LtsPluginManager*> m_appList;
|
||||
LtsLogin::LtsLogin* m_login;
|
||||
LtsAppDescriptor::AppDescription m_app;
|
||||
QString m_loginPluginIid;
|
||||
|
||||
public slots:
|
||||
void slotLogout();
|
||||
|
||||
private slots:
|
||||
void slotQuit();
|
||||
void slotSoftQuit();
|
||||
void slotShowLogin();
|
||||
void slotAppDestroyed();
|
||||
void slotStartDebugServer();
|
||||
void hideAllOtherBLWs(QObject* _caller);
|
||||
void taskSwitch(QObject* _caller);
|
||||
|
||||
signals:
|
||||
void signalLoginDone();
|
||||
void signalLogoffDone();
|
||||
void signalShowLogin();
|
||||
void signalInitializationFinished();
|
||||
void signalCommand(QTcpSocket* client, const QStringList argList);
|
||||
};
|
||||
|
||||
} // namespace LtsAppManager
|
||||
@@ -1,12 +0,0 @@
|
||||
find_package(Botan2)
|
||||
|
||||
if (BOTAN_FOUND AND CMAKE_VERSION VERSION_GREATER 3.15.9) # botan doesn't use cmake, make it a cmake target | imported targets don't work correctly with 3.10
|
||||
add_library(LtsBotan STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(LtsBotan PROPERTIES IMPORTED_LOCATION ${BOTAN_LIBRARIES})
|
||||
set_target_properties(LtsBotan PROPERTIES INCLUDE_DIRECTORIES ${BOTAN_INCLUDE_DIRS})
|
||||
target_compile_definitions(LtsBotan INTERFACE BOTAN_FOUND)
|
||||
target_include_directories(LtsBotan SYSTEM INTERFACE ${BOTAN_INCLUDE_DIRS})
|
||||
set(LTS_BOTAN LtsBotan)
|
||||
|
||||
message(STATUS "BOTAN_INCLUDE_DIRS = ${BOTAN_INCLUDE_DIRS}, BOTAN_LIBRARIES = ${BOTAN_LIBRARIES}, LTS_BOTAN = ${LTS_BOTAN}")
|
||||
endif()
|
||||
@@ -1,30 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
NGL_ADD_LIBRARY2(WS SV HLA LtsCoordinate SHARED
|
||||
lts_coordinate.h
|
||||
lts_coordinate.cpp
|
||||
lts_coord_vector.h
|
||||
lts_coord_vector.cpp
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsCoordinate
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsCoordinate
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../LtsCoordTrans
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(LtsCoordinate
|
||||
PRIVATE
|
||||
LtsCoordTrans
|
||||
PUBLIC
|
||||
$<IF:$<TARGET_EXISTS:ddscore>,ddscore,>
|
||||
LtsUtilsCoreHeaderOnly
|
||||
Qt6::Core
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(UnitTest_Coordinate)
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# Make ${Qt6_Gui} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Gui)
|
||||
set(Qt6_Gui ${Qt6_Gui})
|
||||
else()
|
||||
set(Qt6_Gui "")
|
||||
endif()
|
||||
|
||||
|
||||
SET(UnitTestSources
|
||||
lts_coordinate_unit_test.cpp
|
||||
lts_coordinate_unit_test.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING AND TARGET LtsElevation)
|
||||
ADD_EXECUTABLE(commonUnitTestCoordinate ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(commonUnitTestCoordinate
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCoordinate
|
||||
LtsElevation
|
||||
LtsCoordTrans
|
||||
situationMapCommon
|
||||
situationMapElevationMap
|
||||
Qt6::Core
|
||||
${Qt6_Gui}
|
||||
Qt6::Test)
|
||||
|
||||
ADD_TEST(NAME commonUnitTestCoordinate COMMAND $<TARGET_FILE:commonUnitTestCoordinate>)
|
||||
|
||||
ENDIF()
|
||||
-868
@@ -1,868 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_coordinate_unit_test.h"
|
||||
|
||||
#include <ElevationMap/elevation_map_manager.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsCoordinate/lts_coord_vector.h>
|
||||
#include <LtsCoordinate/lts_coordinate.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QtTest/QTest>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
Q_DECLARE_METATYPE(LtsUtils::QPoint3D);
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
static const int s_id{4711};
|
||||
static LtsElevation::LtsElevationManager* s_eleMgr{nullptr};
|
||||
|
||||
class MyLtsElevationManagerBootstrap : public LtsElevation::LtsElevationManager
|
||||
{
|
||||
using BaseClass = LtsElevation::LtsElevationManager;
|
||||
|
||||
public:
|
||||
static LtsElevationManager* createInstanceUnitTest(int id, const QStringList& filePaths_rough_to_fine)
|
||||
{
|
||||
return BaseClass::createInstanceUnitTest(id, filePaths_rough_to_fine);
|
||||
}
|
||||
};
|
||||
|
||||
UnitTestCoordinate::UnitTestCoordinate()
|
||||
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("UnitTestCoordinate"))
|
||||
{
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::initTestCase()
|
||||
{
|
||||
|
||||
QString filePath(QStringLiteral("/usr/share/arcgis/resources/elevation/Altmark_dt1.tif"));
|
||||
|
||||
s_eleMgr = MyLtsElevationManagerBootstrap::createInstanceUnitTest(s_id, {filePath});
|
||||
|
||||
const bool bIsValid = s_eleMgr->isValid();
|
||||
std::cerr << "myBootstrapMgr->isValid() 1 = " << bIsValid << std::endl;
|
||||
|
||||
{
|
||||
s_eleMgr->waitForInitialization();
|
||||
const bool bIsValid = s_eleMgr->isValid();
|
||||
std::cerr << "myBootstrapMgr->isValid() 2 = " << bIsValid << std::endl;
|
||||
}
|
||||
|
||||
QVERIFY2(s_eleMgr, "static LtsElevationManager does not exist");
|
||||
|
||||
using namespace std::placeholders;
|
||||
LtsCoordTrans::LtsCoordinate::elevationCbFunc elevationCB =
|
||||
std::bind(&LtsElevation::LtsElevationManager::elevation, s_eleMgr, _1, _2, _3, _4);
|
||||
LtsCoordTrans::LtsCoordinate::setElevationCallback(elevationCB);
|
||||
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::hasElevationCallback(), "setElevationCallback failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::init()
|
||||
{
|
||||
QVERIFY2(s_eleMgr, "static LtsElevationManager does not exist");
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::hasElevationCallback(), "setElevationCallback failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_NaN()
|
||||
{
|
||||
bool equal = qFuzzyCompare(std::nan(""), std::nan(""));
|
||||
NOTICE_LOG(m_logger) << " qFuzzyCompare(NaN, NaN) = " << equal;
|
||||
|
||||
QVERIFY2(equal == false, "qFuzzyCompare(NaN, NaN) failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_simple1()
|
||||
{
|
||||
LtsCoordTrans::LtsCoordinate ltsCoord;
|
||||
|
||||
QVERIFY2(ltsCoord.isValid() == false, "isValid failed");
|
||||
|
||||
const Core::GeoPosition& geoPos = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << geoPos;
|
||||
QVERIFY2(qFuzzyIsNull(geoPos.lon()), "geoPosition failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos.lat()), "geoPosition failed");
|
||||
QVERIFY2(std::isnan(geoPos.z()), "geoPosition failed");
|
||||
|
||||
const QPointF& utm = ltsCoord.toUtmPointF();
|
||||
const QPointF& utm2 = ltsCoord.toUtm<QPointF>();
|
||||
const LtsCoordTrans::UtmCoordinate3D& utm3D = ltsCoord.toUtmCoordinate3D();
|
||||
NOTICE_LOG(m_logger) << " utmCoordinateAsPointF = " << utm;
|
||||
NOTICE_LOG(m_logger) << " utmCoordinateAsPointF = " << utm2;
|
||||
NOTICE_LOG(m_logger) << " UtmCoordinate3D = " << utm3D;
|
||||
|
||||
QVERIFY2(qFuzzyCompare(utm3D.x, 166021.44308053952), "data no equal");
|
||||
QVERIFY2(qFuzzyCompare(utm3D.y, 0.0), "data no equal");
|
||||
QVERIFY2(utm3D.zone == 31, "data no equal");
|
||||
QVERIFY2(utm == utm2, "data no equal");
|
||||
|
||||
const Core::GeoPosition& geoPos2 = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition2 = " << geoPos2;
|
||||
QVERIFY2(qFuzzyIsNull(geoPos2.lon()), "geoPosition2 failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos2.lat()), "geoPosition2 failed");
|
||||
QVERIFY2(std::isnan(geoPos2.z()), "geoPosition2 failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_simple2()
|
||||
{
|
||||
Core::GeoPosition defaultGeoPos;
|
||||
LtsCoordTrans::LtsCoordinate ltsCoord(defaultGeoPos);
|
||||
|
||||
QVERIFY2(ltsCoord.isValid() == false, "isValid failed");
|
||||
|
||||
const Core::GeoPosition& geoPos = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << geoPos;
|
||||
QVERIFY2(qFuzzyIsNull(geoPos.lon()), "geoPosition failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos.lat()), "geoPosition failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos.z()), "geoPosition failed");
|
||||
|
||||
const QPointF& utm = ltsCoord.toUtm<QPointF>();
|
||||
NOTICE_LOG(m_logger) << " utmCoordinateAsPointF = " << utm;
|
||||
|
||||
const Core::GeoPosition& geoPos2 = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition2 = " << geoPos2;
|
||||
QVERIFY2(qFuzzyIsNull(geoPos2.lon()), "geoPosition2 failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos2.lat()), "geoPosition2 failed");
|
||||
QVERIFY2(qFuzzyIsNull(geoPos2.z()), "geoPosition2 failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_simple3()
|
||||
{
|
||||
static const Core::GeoPosition s_invalidPos(std::nan(""), std::nan(""), std::nan(""));
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsCoord(s_invalidPos);
|
||||
|
||||
QVERIFY2(ltsCoord.isValid() == false, "isValid failed");
|
||||
|
||||
const Core::GeoPosition& geoPos = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << geoPos;
|
||||
QVERIFY2(std::isnan(geoPos.lon()), "geoPosition failed");
|
||||
QVERIFY2(std::isnan(geoPos.lat()), "geoPosition failed");
|
||||
QVERIFY2(std::isnan(geoPos.z()), "geoPosition failed");
|
||||
|
||||
const QPointF& utm = ltsCoord.toUtm<QPointF>();
|
||||
NOTICE_LOG(m_logger) << " utmCoordinateAsPointF = " << utm;
|
||||
QVERIFY2(utm.isNull(), "utm failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_simple4()
|
||||
{
|
||||
LtsCoordTrans::LtsCoordinate::resetConversionCounter();
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 0, "getConversionCounter failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const double zValue = 2.3;
|
||||
|
||||
const LtsCoordTrans::LtsCoordinate ltsCoord(utmIn.geographic(), zValue);
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoord_FirstTry = ltsCoord.utmCoordinate();
|
||||
Q_UNUSED(utmCoord_FirstTry);
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 1, "getConversionCounter failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoord_SecondTry = ltsCoord.utmCoordinate();
|
||||
Q_UNUSED(utmCoord_SecondTry);
|
||||
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 1, "getConversionCounter failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_fromUtm()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const double zValue = 2.3;
|
||||
NOTICE_LOG(m_logger) << " utmIn = " << utmIn;
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsCoord(utmIn.geographic(), zValue);
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoord = ltsCoord.utmCoordinate();
|
||||
NOTICE_LOG(m_logger) << " utmCoord = " << utmCoord;
|
||||
NOTICE_LOG(m_logger) << " utmCoord = " << utmCoord.mgrs();
|
||||
QVERIFY2(utmCoord.mgrs() == QStringLiteral("32U PD 70000 10000"), "utmCoordinate failed");
|
||||
|
||||
const Core::GeoPosition& geoPos = ltsCoord.geoPosition();
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << geoPos;
|
||||
|
||||
QVERIFY2(qFuzzyCompare(geoPos.lon(), 0.200706392814992), "geoPosition failed");
|
||||
QVERIFY2(qFuzzyCompare(geoPos.lat(), 0.914792952478694), "geoPosition failed");
|
||||
QVERIFY2(qFuzzyCompare(geoPos.z(), zValue), "geoPosition failed");
|
||||
|
||||
const QPointF& utmP2D = ltsCoord.toUtm<QPointF>();
|
||||
NOTICE_LOG(m_logger) << " utmP2D = " << utmP2D;
|
||||
QVERIFY2(qFuzzyCompare(utmP2D.x(), 670000.5), "utm1 failed");
|
||||
QVERIFY2(qFuzzyCompare(utmP2D.y(), 5810000.5), "utm2 failed");
|
||||
|
||||
const LtsUtils::QPoint3D& utmP3D = ltsCoord.toUtm<LtsUtils::QPoint3D>();
|
||||
NOTICE_LOG(m_logger) << " utmP3D = " << utmP3D;
|
||||
QVERIFY2(qFuzzyCompare(utmP3D.x(), 670000.5), "utm1 failed");
|
||||
QVERIFY2(qFuzzyCompare(utmP3D.y(), 5810000.5), "utm2 failed");
|
||||
QVERIFY2(qFuzzyCompare(utmP3D.z(), zValue), "utm3 failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate3D& utmCoord3D = ltsCoord.toUtmCoordinate3D();
|
||||
NOTICE_LOG(m_logger) << " UtmCoordinate3D = " << utmCoord3D;
|
||||
QVERIFY2(qFuzzyCompare(utmCoord3D.x, 670000.5), "utmCoord3D failed");
|
||||
QVERIFY2(qFuzzyCompare(utmCoord3D.y, 5810000.5), "utmCoord3D failed");
|
||||
QVERIFY2(qFuzzyCompare(utmCoord3D.z(), zValue), "utmCoord3D failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoord2D = utmCoord3D;
|
||||
NOTICE_LOG(m_logger) << " utmCoord2D = " << utmCoord2D;
|
||||
QVERIFY2(qFuzzyCompare(utmCoord2D.x, 670000.5), "utmCoord2D failed");
|
||||
QVERIFY2(qFuzzyCompare(utmCoord2D.y, 5810000.5), "utmCoord2D failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm = ltsCoord.utmCoordinate();
|
||||
QVERIFY2(utm.mgrs() == QStringLiteral("32U PD 70000 10000"), "utmCoordinate failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_fromUtm2()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmInZone32 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U LA 10000 00000"));
|
||||
const double zValue = 2.3;
|
||||
NOTICE_LOG(m_logger) << " utmInZone32 = " << utmInZone32;
|
||||
|
||||
const QPointF& utmInDefQPointF = utmInZone32.geographic();
|
||||
|
||||
const int zone31 = 31;
|
||||
const LtsCoordTrans::UtmCoordinate& utmInZone31 =
|
||||
LtsCoordTrans::UtmCoordinate::fromGeographic(utmInDefQPointF, zone31);
|
||||
NOTICE_LOG(m_logger) << " utmInZone31 = " << utmInZone31;
|
||||
|
||||
NOTICE_LOG(m_logger) << " utmInZone31.geographic() = " << utmInZone31.geographic();
|
||||
NOTICE_LOG(m_logger) << " utmInZone32.geographic() = " << utmInZone32.geographic();
|
||||
|
||||
QVERIFY2(utmInZone31.geographic() == utmInZone32.geographic(), "geographic failed");
|
||||
|
||||
{
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm31(utmInZone31.geographic(), zValue);
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm32(utmInZone32.geographic(), zValue);
|
||||
|
||||
double dist = ltsFromUtm31.distanceUtm3D(ltsFromUtm32);
|
||||
NOTICE_LOG(m_logger) << " dist1 = " << dist;
|
||||
QVERIFY2(qFuzzyCompare(dist, 0), "distance3D");
|
||||
}
|
||||
{
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm31(utmInZone31.geographic(), zValue);
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm32(utmInZone32.geographic(1, 0), zValue);
|
||||
|
||||
double dist = ltsFromUtm31.distanceUtm3D(ltsFromUtm32);
|
||||
NOTICE_LOG(m_logger) << " dist2 = " << dist;
|
||||
QVERIFY2(fabs(dist - 1) < 0.00001, "distance3D");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm31 =
|
||||
LtsCoordTrans::LtsCoordinate::fromUtmCoordinate(utmInZone31, zValue);
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm32 =
|
||||
LtsCoordTrans::LtsCoordinate::fromUtmCoordinate(utmInZone32, zValue);
|
||||
|
||||
double dist = ltsFromUtm31.distanceUtm3D(ltsFromUtm32);
|
||||
NOTICE_LOG(m_logger) << " dist3 = " << dist;
|
||||
QVERIFY2(qFuzzyCompare(dist, 0), "distance3D");
|
||||
}
|
||||
|
||||
{
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm32(utmInZone32.geographic(), zValue);
|
||||
|
||||
const QPointF& utmP2D_def = ltsFromUtm32.toUtm<QPointF>();
|
||||
const QPointF& utmP2D_31 = ltsFromUtm32.toUtm<QPointF>(31);
|
||||
NOTICE_LOG(m_logger) << " utmP2D_def = " << utmP2D_def;
|
||||
NOTICE_LOG(m_logger) << " utmP2D_31 = " << utmP2D_31;
|
||||
|
||||
LtsCoordTrans::LtsCoordinate lts1 = LtsCoordTrans::LtsCoordinate::fromUtm(utmP2D_def, 32, 0.0);
|
||||
LtsCoordTrans::LtsCoordinate lts2 = LtsCoordTrans::LtsCoordinate::fromUtm(utmP2D_31, 31, 0.0);
|
||||
NOTICE_LOG(m_logger) << " lts1 = " << lts1;
|
||||
NOTICE_LOG(m_logger) << " lts2 = " << lts2;
|
||||
|
||||
double dist = lts1.distanceUtm3D(lts2);
|
||||
NOTICE_LOG(m_logger) << " dist4 = " << dist;
|
||||
QVERIFY2(qFuzzyCompare(dist, 0), "distance3D");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_elevationAt()
|
||||
{
|
||||
const double zValue = 1.23;
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
NOTICE_LOG(m_logger) << " utmIn = " << utmIn;
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm(utmIn.geographic(), zValue);
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm1 = " << ltsFromUtm;
|
||||
QVERIFY2(qFuzzyCompare(ltsFromUtm.geoPosition().z(), zValue), "geoPosition failed");
|
||||
|
||||
const double ele = ltsFromUtm.elevationAt();
|
||||
QVERIFY2(qFuzzyCompare(ele, 75), "elevationAt failed");
|
||||
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm2 = " << ltsFromUtm;
|
||||
QVERIFY2(qFuzzyCompare(ltsFromUtm.geoPosition().z(), zValue), "geoPosition failed");
|
||||
|
||||
ltsFromUtm.setZValueAccordingElevation();
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm3 = " << ltsFromUtm;
|
||||
QVERIFY2(qFuzzyCompare(ltsFromUtm.geoPosition().z(), 75), "setZValueAccordingElevation failed");
|
||||
|
||||
const LtsUtils::QPoint3D& utmP3D = ltsFromUtm.toUtm<LtsUtils::QPoint3D>();
|
||||
NOTICE_LOG(m_logger) << " utmP3D_a = " << utmP3D;
|
||||
QVERIFY2(qFuzzyCompare(utmP3D.z(), 75), "utmCoordinateAsPoint3D failed");
|
||||
|
||||
{
|
||||
|
||||
const double ele3 = LtsCoordTrans::LtsCoordinate::elevationAt(ltsFromUtm);
|
||||
NOTICE_LOG(m_logger) << " ele3 = " << ele3;
|
||||
|
||||
QVERIFY2(qFuzzyCompare(ele, ele3), "LtsCoordinate::elevationAt failed");
|
||||
}
|
||||
|
||||
LtsCoordTrans::UtmCoordinate utmMoved = ltsFromUtm.utmCoordinate();
|
||||
utmMoved.x += 11;
|
||||
utmMoved.y += 22;
|
||||
const int zValueNew = 123;
|
||||
ltsFromUtm = LtsCoordTrans::LtsCoordinate(utmMoved.geographic(), zValueNew);
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm4 = " << ltsFromUtm;
|
||||
|
||||
const double ele2 = ltsFromUtm.elevationAt();
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm5 = " << ltsFromUtm;
|
||||
QVERIFY2(ele2 != 75, "setZValueAccordingElevation failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_elevationAt_isCovered()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn1 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U MD 10000 10000"));
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm1(utmIn1.geographic(), 11);
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm2(utmIn2.geographic(), 11);
|
||||
|
||||
{
|
||||
bool bIsCovered = false;
|
||||
double ele = ltsFromUtm1.elevationAt(-123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == true, "elevationAt1a failed");
|
||||
|
||||
bIsCovered = false;
|
||||
ele = ltsFromUtm1.elevationAt(-123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == true, "elevationAt1b failed");
|
||||
|
||||
bIsCovered = false;
|
||||
ele = LtsCoordTrans::LtsCoordinate::elevationAt(ltsFromUtm1, -123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == true, "elevationAt2a failed");
|
||||
|
||||
bIsCovered = false;
|
||||
ele = LtsCoordTrans::LtsCoordinate::elevationAt(ltsFromUtm1, -123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == true, "elevationAt2b failed");
|
||||
}
|
||||
|
||||
{
|
||||
bool bIsCovered = true;
|
||||
double ele = ltsFromUtm2.elevationAt(-123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == false, "elevationAt2 failed");
|
||||
|
||||
bIsCovered = true;
|
||||
ele = LtsCoordTrans::LtsCoordinate::elevationAt(ltsFromUtm2, -123, &bIsCovered);
|
||||
Q_UNUSED(ele);
|
||||
QVERIFY2(bIsCovered == false, "elevationAt1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_elevation_data()
|
||||
{
|
||||
QTest::addColumn<QString>("mgrs");
|
||||
QTest::addColumn<double>("elevationIn");
|
||||
QTest::addColumn<double>("elevationRef");
|
||||
|
||||
QTest::newRow("elevation 10 ") << QStringLiteral("32 U PD 70000 10000") << std::nan("") << 75.0;
|
||||
QTest::newRow("elevation 11 ") << QStringLiteral("32 U PD 70000 10000") << 0.0 << 75.0;
|
||||
QTest::newRow("elevation 20 ") << QStringLiteral("32 U PD 72000 13000") << std::nan("") << 80.0;
|
||||
QTest::newRow("elevation 21 ") << QStringLiteral("32 U PD 72000 13000") << 0.340 << 80.0;
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_elevation()
|
||||
{
|
||||
QFETCH(QString, mgrs);
|
||||
QFETCH(double, elevationIn);
|
||||
QFETCH(double, elevationRef);
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn = LtsCoordTrans::UtmCoordinate::fromMgrs(mgrs);
|
||||
NOTICE_LOG(m_logger) << " utmIn = " << utmIn;
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm(utmIn.geographic(), elevationIn);
|
||||
NOTICE_LOG(m_logger) << " ltsFromUtm = " << ltsFromUtm;
|
||||
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << ltsFromUtm.geoPosition();
|
||||
ltsFromUtm.replaceZValueByElevationIfValue(elevationIn);
|
||||
|
||||
NOTICE_LOG(m_logger) << " geoPosition = " << ltsFromUtm.geoPosition();
|
||||
QVERIFY2(qFuzzyCompare(ltsFromUtm.geoPosition().z(), elevationRef), "elevation failed");
|
||||
|
||||
const LtsUtils::QPoint3D& utmP3D = ltsFromUtm.toUtm<LtsUtils::QPoint3D>();
|
||||
NOTICE_LOG(m_logger) << " utmP3D = " << utmP3D;
|
||||
QVERIFY2(qFuzzyCompare(utmP3D.z(), elevationRef), "utmCoordinateAsPoint3D failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_mgrs()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
NOTICE_LOG(m_logger) << " utmIn = " << utmIn.mgrs();
|
||||
|
||||
LtsCoordTrans::LtsCoordinate ltsFromUtm(utmIn.geographic());
|
||||
|
||||
{
|
||||
const QString asMgrs = ltsFromUtm.mgrs();
|
||||
NOTICE_LOG(m_logger) << " asMgrs = " << asMgrs;
|
||||
QVERIFY2(asMgrs.compare(QStringLiteral("32U PD 70000 10000")) == 0, "UtmCoordinate::mgrs failed");
|
||||
}
|
||||
{
|
||||
const QString asMgrs = ltsFromUtm.mgrsWithZ();
|
||||
NOTICE_LOG(m_logger) << " asMgrs = " << asMgrs;
|
||||
QVERIFY2(asMgrs.compare(QStringLiteral("32U PD 70000 10000 z=75.00")) == 0, "UtmCoordinate::mgrs failed");
|
||||
}
|
||||
|
||||
{
|
||||
const LtsCoordTrans::LtsCoordinate coord(0.200706392814992, 0.914792952478694, 123);
|
||||
|
||||
const QString str1 = coord.toString();
|
||||
NOTICE_LOG(m_logger) << " str1 cheap = " << str1;
|
||||
QVERIFY2(str1.compare(QStringLiteral("LtsCoordinate(m_geo=[[lon: 0.200706392814992, lat: 0.914792952478694]z: "
|
||||
"123], m_utm2D.x 0, m_utm2D.y 0, m_utm2D.zone -1, elevation nan)")) == 0,
|
||||
"toString failed");
|
||||
|
||||
const bool fullAndExpensive = true;
|
||||
const QString str2 = coord.toString(fullAndExpensive);
|
||||
NOTICE_LOG(m_logger) << " str2 expensive = " << str2;
|
||||
QVERIFY2(str2.compare(QStringLiteral("LtsCoordinate(m_geo=[[lon: 0.200706392814992, lat: 0.914792952478694]z: "
|
||||
"123], m_utm2D.x 670000.499999998, m_utm2D.y 5810000.5, m_utm2D.zone 32, "
|
||||
"m_utm2D.mgrs '32U PD 70000 10000', elevation 75.000)")) == 0,
|
||||
"toString failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_distance()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn1 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70010 10100"));
|
||||
NOTICE_LOG(m_logger) << " XXutmIn1 = " << utmIn1;
|
||||
NOTICE_LOG(m_logger) << " XXutmIn2 = " << utmIn2;
|
||||
|
||||
QVERIFY2(qFuzzyCompare((utmIn2.x - utmIn1.x), 10), "coord failed");
|
||||
QVERIFY2(qFuzzyCompare((utmIn2.y - utmIn1.y), 100), "coord failed");
|
||||
|
||||
const LtsCoordTrans::LtsCoordinate lts1(utmIn1.geographic(), 11);
|
||||
const LtsCoordTrans::LtsCoordinate lts2(utmIn2.geographic(), 111);
|
||||
|
||||
{
|
||||
double dist2D = lts1.distanceUtm2D(lts2);
|
||||
NOTICE_LOG(m_logger) << " dist2D = " << dist2D;
|
||||
QVERIFY2(std::fabs(dist2D - 100.499) < 0.01, "distanceUtm2D failed");
|
||||
}
|
||||
|
||||
{
|
||||
double dist3D = lts1.distanceUtm3D(lts2);
|
||||
NOTICE_LOG(m_logger) << " dist3D = " << dist3D;
|
||||
QVERIFY2(std::fabs(dist3D - 141.774) < 0.01, "distanceUtm3D failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_distanceDiffZones()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn1 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("31 U FR 99999 00000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utmIn2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U LA 00000 00000"));
|
||||
NOTICE_LOG(m_logger) << " XXutmIn1 = " << utmIn1;
|
||||
NOTICE_LOG(m_logger) << " XXutmIn2 = " << utmIn2;
|
||||
|
||||
LtsCoordTrans::LtsCoordinate lts1(utmIn1.geographic(), 0);
|
||||
LtsCoordTrans::LtsCoordinate lts2(utmIn2.geographic(), 0);
|
||||
NOTICE_LOG(m_logger) << " lts1 = " << lts1;
|
||||
NOTICE_LOG(m_logger) << " lts2 = " << lts2;
|
||||
|
||||
double dist = lts1.distanceUtm3D(lts2);
|
||||
|
||||
NOTICE_LOG(m_logger) << " dist = " << dist;
|
||||
QVERIFY2(std::fabs(dist - 33382.7) < 0.1, "distance3D failed");
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_squareInDifferentZone()
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utm_bl =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utm_br =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 11000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utm_tl =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 71000 10000"));
|
||||
const LtsCoordTrans::UtmCoordinate& utm_tr =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 71000 11000"));
|
||||
|
||||
const LtsCoordTrans::LtsCoordinate lts_bl(utm_bl.geographic(), 0);
|
||||
const LtsCoordTrans::LtsCoordinate lts_br(utm_br.geographic(), 0);
|
||||
const LtsCoordTrans::LtsCoordinate lts_tl(utm_tl.geographic(), 0);
|
||||
const LtsCoordTrans::LtsCoordinate lts_tr(utm_tr.geographic(), 0);
|
||||
|
||||
{
|
||||
|
||||
QVERIFY2(qFuzzyCompare(lts_bl.distanceUtm2D(lts_br), 1000.0), "distance3D 1 failed");
|
||||
QVERIFY2(qFuzzyCompare(lts_tl.distanceUtm2D(lts_tr), 1000.0), "distance3D 2 failed");
|
||||
QVERIFY2(qFuzzyCompare(lts_br.distanceUtm2D(lts_tr), 1000.0), "distance3D 3 failed");
|
||||
QVERIFY2(qFuzzyCompare(lts_bl.distanceUtm2D(lts_tl), 1000.0), "distance3D 4 failed");
|
||||
|
||||
QVERIFY2(qFuzzyCompare(lts_bl.distanceUtm2D(lts_tr), 1414.213562373177), "distance3D 5 failed");
|
||||
QVERIFY2(qFuzzyCompare(lts_br.distanceUtm2D(lts_tl), 1414.213562373177), "distance3D 6 failed");
|
||||
}
|
||||
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utm31_bl = LtsCoordTrans::UtmCoordinate(31, utm_bl.x, utm_bl.y);
|
||||
const LtsCoordTrans::UtmCoordinate& utm31_br = LtsCoordTrans::UtmCoordinate(31, utm_br.x, utm_br.y);
|
||||
const LtsCoordTrans::UtmCoordinate& utm31_tl = LtsCoordTrans::UtmCoordinate(31, utm_tl.x, utm_tl.y);
|
||||
const LtsCoordTrans::UtmCoordinate& utm31_tr = LtsCoordTrans::UtmCoordinate(31, utm_tr.x, utm_tr.y);
|
||||
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_bl, utm31_br), 1000.0),
|
||||
"LtsCoordTrans::distance 1 failed");
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_tl, utm31_tr), 1000.0),
|
||||
"LtsCoordTrans::distance 2 failed");
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_br, utm31_tr), 1000.0),
|
||||
"LtsCoordTrans::distance 3 failed");
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_bl, utm31_tl), 1000.0),
|
||||
"LtsCoordTrans::distance 4 failed");
|
||||
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_bl, utm31_tr), 1414.213562373095),
|
||||
"LtsCoordTrans::distance 5 failed");
|
||||
QVERIFY2(qFuzzyCompare(LtsCoordTrans::distance(utm31_br, utm31_tl), 1414.213562373095),
|
||||
"LtsCoordTrans::distance 6 failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_angle()
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm_ul =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_ul(utm_ul.geographic(), 0);
|
||||
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm_2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 11000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_2(utm_2.geographic(), 0);
|
||||
double angle = LtsCoordTrans::LtsCoordinate::angleDegreeUtm2D(lts_ul, lts_2);
|
||||
QVERIFY2(qFuzzyCompare(angle, 0.0), "angleUtm2D 1 failed");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm_2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 71000 10000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_2(utm_2.geographic(), 0);
|
||||
double angle = LtsCoordTrans::LtsCoordinate::angleDegreeUtm2D(lts_ul, lts_2);
|
||||
QVERIFY2(qFuzzyCompare(angle, 90.0), "angleUtm2D 1 failed");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm_2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 09000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_2(utm_2.geographic(), 0);
|
||||
double angle = LtsCoordTrans::LtsCoordinate::angleDegreeUtm2D(lts_ul, lts_2);
|
||||
QVERIFY2(qFuzzyCompare(angle, 180.0), "angleUtm2D 1 failed");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utm_2 =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 69000 10000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_2(utm_2.geographic(), 0);
|
||||
double angle = LtsCoordTrans::LtsCoordinate::angleDegreeUtm2D(lts_ul, lts_2);
|
||||
QVERIFY2(qFuzzyCompare(angle, 270.0), "angleUtm2D 1 failed");
|
||||
}
|
||||
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utm_or =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 71000 12000"));
|
||||
const LtsCoordTrans::LtsCoordinate lts_or(utm_or.geographic(), 0);
|
||||
double angle = LtsCoordTrans::LtsCoordinate::angleDegreeUtm2D(lts_ul, lts_or);
|
||||
|
||||
QVERIFY2(qFuzzyCompare(angle, 26.565051177056659526), "angleUtm2D 1 failed");
|
||||
QVERIFY2((angle - 26.5651 < 0.001), "angleUtm2D 1 failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_cont()
|
||||
{
|
||||
std::vector<Core::GeoPosition> stdVec;
|
||||
stdVec.push_back(Core::GeoPosition(0.1, 0.11, 1));
|
||||
stdVec.push_back(Core::GeoPosition(0.2, 0.22, 2));
|
||||
stdVec.push_back(Core::GeoPosition(0.3, 0.33, 3));
|
||||
|
||||
const QVector<LtsCoordTrans::LtsCoordinate>& newCont =
|
||||
LtsCoordTrans::convert<QVector<LtsCoordTrans::LtsCoordinate>>(stdVec);
|
||||
|
||||
NOTICE_LOG(m_logger) << " newCont.size() = " << newCont.size();
|
||||
QVERIFY2(stdVec.size() == static_cast<size_t>(newCont.size()), "convert failed");
|
||||
}
|
||||
|
||||
using namespace LtsCoordTrans;
|
||||
|
||||
class ParticpantPositionStore
|
||||
{
|
||||
public:
|
||||
ParticpantPositionStore() = default;
|
||||
~ParticpantPositionStore() = default;
|
||||
|
||||
void setGeoPosition(const Core::GeoPosition& newGeoPos)
|
||||
{
|
||||
m_ltsCoord = LtsCoordinate(newGeoPos);
|
||||
m_ltsCoord_NoImplicitCopy.updateGeoPosition(newGeoPos);
|
||||
}
|
||||
|
||||
LtsCoordinate getLtsCoord_copy()
|
||||
{
|
||||
return m_ltsCoord;
|
||||
}
|
||||
|
||||
const LtsCoordinateNoImplicitCopy& getLtsCoord_noCopy()
|
||||
{
|
||||
return m_ltsCoord_NoImplicitCopy;
|
||||
}
|
||||
|
||||
LtsCoordinate m_ltsCoord;
|
||||
LtsCoordinateNoImplicitCopy m_ltsCoord_NoImplicitCopy;
|
||||
};
|
||||
|
||||
void UnitTestCoordinate::test_coordinate_avoid_copy()
|
||||
{
|
||||
LtsCoordTrans::LtsCoordinate::resetConversionCounter();
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 0, "getConversionCounter failed");
|
||||
|
||||
ParticpantPositionStore store;
|
||||
|
||||
const UtmCoordinate& utmIn = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U PD 70000 10000"));
|
||||
const LtsCoordinate ltsIn(utmIn.geographic(), 11);
|
||||
|
||||
store.getLtsCoord_noCopy().updateGeoPosition(ltsIn.geoPosition());
|
||||
|
||||
const LtsCoordinateNoImplicitCopy& justReference = store.getLtsCoord_noCopy();
|
||||
NOTICE_LOG(m_logger) << " justReference = " << justReference.mgrs();
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& convertedToUtm = justReference.utmCoordinate();
|
||||
NOTICE_LOG(m_logger) << " convertedToUtm = " << convertedToUtm;
|
||||
QVERIFY2(qFuzzyCompare(convertedToUtm.x, 670000.5), "convert failed");
|
||||
QVERIFY2(qFuzzyCompare(convertedToUtm.y, 5810000.5), "convert failed");
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 1, "getConversionCounter failed");
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& convertedToUtmSecondTry = justReference.utmCoordinate();
|
||||
Q_UNUSED(convertedToUtmSecondTry)
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 1, "getConversionCounter failed");
|
||||
|
||||
std::vector<LtsCoordinateNoImplicitCopy> myVec;
|
||||
myVec.push_back(justReference);
|
||||
|
||||
const LtsCoordTrans::LtsCoordinateNoImplicitCopy& retrievedUtmRef = myVec.front();
|
||||
NOTICE_LOG(m_logger) << " retrievedUtm = " << retrievedUtmRef.mgrs();
|
||||
|
||||
QVERIFY2(justReference.mgrs() == retrievedUtmRef.mgrs(), "getConversionCounter failed");
|
||||
|
||||
QVERIFY2(LtsCoordTrans::LtsCoordinate::getConversionCounter() == 1, "getConversionCounter failed");
|
||||
}
|
||||
|
||||
template <typename T> void removeItem(T& map, int key)
|
||||
{
|
||||
map.erase(key);
|
||||
}
|
||||
|
||||
template <> void removeItem(QMap<int, int>& map, int key)
|
||||
{
|
||||
map.remove(key);
|
||||
}
|
||||
|
||||
template <> void removeItem(QHash<int, int>& map, int key)
|
||||
{
|
||||
map.remove(key);
|
||||
}
|
||||
|
||||
template <typename T> void test_references(T& map)
|
||||
{
|
||||
for (int i = 2; i < 10; ++i)
|
||||
map[i] = i;
|
||||
|
||||
const int& ref2 = map[2];
|
||||
const int& ref3 = map[3];
|
||||
const int& ref4 = map[4];
|
||||
const int& ref5 = map[5];
|
||||
const int& ref6 = map[6];
|
||||
const int& ref7 = map[7];
|
||||
const int& ref8 = map[8];
|
||||
|
||||
QVERIFY2(ref2 == 2, "ref failed");
|
||||
QVERIFY2(ref3 == 3, "ref failed");
|
||||
QVERIFY2(ref4 == 4, "ref failed");
|
||||
QVERIFY2(ref5 == 5, "ref failed");
|
||||
QVERIFY2(ref6 == 6, "ref failed");
|
||||
QVERIFY2(ref7 == 7, "ref failed");
|
||||
QVERIFY2(ref8 == 8, "ref failed");
|
||||
|
||||
removeItem(map, 1);
|
||||
removeItem(map, 3);
|
||||
removeItem(map, 5);
|
||||
|
||||
{
|
||||
QVERIFY2(ref2 == 2, "ref failed");
|
||||
|
||||
QVERIFY2(ref4 == 4, "ref failed");
|
||||
|
||||
QVERIFY2(ref6 == 6, "ref failed");
|
||||
QVERIFY2(ref7 == 7, "ref failed");
|
||||
QVERIFY2(ref8 == 8, "ref failed");
|
||||
}
|
||||
|
||||
map[0] = 0;
|
||||
map[1] = 1;
|
||||
const int& ref0 = map[0];
|
||||
const int& ref1 = map[1];
|
||||
|
||||
{
|
||||
QVERIFY2(ref0 == 0, "ref failed");
|
||||
QVERIFY2(ref1 == 1, "ref failed");
|
||||
|
||||
QVERIFY2(ref2 == 2, "ref failed");
|
||||
|
||||
QVERIFY2(ref4 == 4, "ref failed");
|
||||
|
||||
QVERIFY2(ref6 == 6, "ref failed");
|
||||
QVERIFY2(ref7 == 7, "ref failed");
|
||||
QVERIFY2(ref8 == 8, "ref failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_container_references()
|
||||
{
|
||||
|
||||
{
|
||||
std::unordered_map<int, int> std_unordered_map;
|
||||
test_references(std_unordered_map);
|
||||
}
|
||||
{
|
||||
std::map<int, int> std_map;
|
||||
test_references(std_map);
|
||||
}
|
||||
{
|
||||
QMap<int, int> Qmap;
|
||||
test_references(Qmap);
|
||||
}
|
||||
{
|
||||
QHash<int, int> Qhash;
|
||||
test_references(Qhash);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestCoordinate::test_coordVector()
|
||||
{
|
||||
std::vector<Core::GeoPosition> geoVec;
|
||||
|
||||
{
|
||||
|
||||
QPointF utmPnt = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U LB 00001 50001")).geographic();
|
||||
geoVec.push_back(Core::GeoPosition(utmPnt.x(), utmPnt.y(), 1.1));
|
||||
|
||||
utmPnt = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U LB 00001 50001")).geographic(1, 0);
|
||||
geoVec.push_back(Core::GeoPosition(utmPnt.x(), utmPnt.y(), 2.2));
|
||||
|
||||
utmPnt = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32 U LB 00001 50001")).geographic(2, 0);
|
||||
geoVec.push_back(Core::GeoPosition(utmPnt.x(), utmPnt.y(), 3.3));
|
||||
}
|
||||
|
||||
const LtsCoordVector coordVec(geoVec);
|
||||
QVERIFY2(coordVec.size() == 3, "size failed");
|
||||
|
||||
int cnt = LtsCoordTrans::getConversionCounter_UTMUPS_Forward();
|
||||
|
||||
{
|
||||
const std::vector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toStdUtmCoord(32);
|
||||
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(utmVec.front().mgrs() == QStringLiteral("32U LB 00001 50001"), "mgrs failed");
|
||||
QVERIFY2(utmVec.back().mgrs() == QStringLiteral("32U LB 00003 50001"), "mgrs failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 3,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
{
|
||||
const std::vector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toStdUtmCoord(32);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(utmVec.front().mgrs() == QStringLiteral("32U LB 00001 50001"), "mgrs failed");
|
||||
QVERIFY2(utmVec.back().mgrs() == QStringLiteral("32U LB 00003 50001"), "mgrs failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 3,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
|
||||
{
|
||||
const std::vector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toStdUtmCoord(31);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
{
|
||||
const std::vector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toStdUtmCoord(31);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
|
||||
{
|
||||
const QVector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toQVectorUtmCoord(32);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(utmVec.front().mgrs() == QStringLiteral("32U LB 00001 50001"), "mgrs failed");
|
||||
QVERIFY2(utmVec.back().mgrs() == QStringLiteral("32U LB 00003 50001"), "mgrs failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
{
|
||||
const QVector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toQVectorUtmCoord(32);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(utmVec.front().mgrs() == QStringLiteral("32U LB 00001 50001"), "mgrs failed");
|
||||
QVERIFY2(utmVec.back().mgrs() == QStringLiteral("32U LB 00003 50001"), "mgrs failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
|
||||
{
|
||||
const QVector<QPointF>& utmVec = coordVec.toQVectorQPointF(32);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
{
|
||||
const QVector<LtsCoordTrans::UtmCoordinate>& utmVec = coordVec.toQVectorUtmCoord(32);
|
||||
QVERIFY2(utmVec.size() == 3, "size failed");
|
||||
QVERIFY2(LtsCoordTrans::getConversionCounter_UTMUPS_Forward() - cnt == 6,
|
||||
"getConversionCounterUTMUPS_Forward failed");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTestCoordinate", "log4cxxPositionUnitTest.props");
|
||||
|
||||
UnitTestCoordinate tc;
|
||||
|
||||
int ret = QTest::qExec(&tc, argc, argv);
|
||||
|
||||
if (s_eleMgr)
|
||||
{
|
||||
s_eleMgr->cleanupAll();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <ElevationMap/elevation_map_manager.h>
|
||||
#include <LtsElevation/lts_elevation_manager.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
using LOGGER_T = NGL::INGLLogger&;
|
||||
|
||||
class UnitTestCoordinate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UnitTestCoordinate();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void initTestCase();
|
||||
|
||||
void init();
|
||||
|
||||
void test_NaN();
|
||||
|
||||
void test_coordinate_simple1();
|
||||
void test_coordinate_simple2();
|
||||
void test_coordinate_simple3();
|
||||
void test_coordinate_simple4();
|
||||
|
||||
void test_coordinate_fromUtm();
|
||||
void test_coordinate_fromUtm2();
|
||||
|
||||
void test_coordinate_elevationAt();
|
||||
void test_coordinate_elevationAt_isCovered();
|
||||
|
||||
void test_coordinate_elevation_data();
|
||||
void test_coordinate_elevation();
|
||||
|
||||
void test_coordinate_mgrs();
|
||||
|
||||
void test_coordinate_distance();
|
||||
void test_coordinate_distanceDiffZones();
|
||||
|
||||
void test_squareInDifferentZone();
|
||||
|
||||
void test_coordinate_angle();
|
||||
|
||||
void test_coordinate_cont();
|
||||
|
||||
void test_coordinate_avoid_copy();
|
||||
|
||||
void test_container_references();
|
||||
void test_coordVector();
|
||||
|
||||
private:
|
||||
NGL::INGLLogger& m_logger;
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_coord_vector.h"
|
||||
|
||||
namespace LtsCoordTrans
|
||||
{
|
||||
|
||||
LtsCoordVector::LtsCoordVector(const std::vector<Core::GeoPosition>& geo_coordinates)
|
||||
: m_geo_coordinates(geo_coordinates)
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<UtmCoordinate>& LtsCoordVector::toStdUtmCoord(int zone) const
|
||||
{
|
||||
convertGeoToStdUtm(zone);
|
||||
return m_utmMapStd[zone];
|
||||
}
|
||||
|
||||
const QVector<UtmCoordinate>& LtsCoordVector::toQVectorUtmCoord(int zone) const
|
||||
{
|
||||
convertGeoToQVectorUtm(zone);
|
||||
return m_utmMapQVector[zone];
|
||||
}
|
||||
|
||||
const QVector<QPointF>& LtsCoordVector::toQVectorQPointF(int zone) const
|
||||
{
|
||||
convertGeoToQVectorQPointF(zone);
|
||||
return m_utmMapQVectorQPointF[zone];
|
||||
}
|
||||
|
||||
void LtsCoordVector::convertGeoToStdUtm(int zone) const
|
||||
{
|
||||
const auto it = m_utmMapStd.find(zone);
|
||||
if (it != m_utmMapStd.end())
|
||||
return;
|
||||
convertGeoToUtmInternal(zone, m_utmMapStd[zone]);
|
||||
}
|
||||
|
||||
void LtsCoordVector::convertGeoToQVectorUtm(int zone) const
|
||||
{
|
||||
const auto it = m_utmMapQVector.find(zone);
|
||||
if (it != m_utmMapQVector.end())
|
||||
return;
|
||||
|
||||
convertGeoToStdUtm(zone);
|
||||
QVector<LtsCoordTrans::UtmCoordinate>& utmVectorRef = m_utmMapQVector[zone];
|
||||
utmVectorRef.clear();
|
||||
utmVectorRef.reserve(m_geo_coordinates.size());
|
||||
|
||||
for (const auto& utmCoord : m_utmMapStd[zone])
|
||||
utmVectorRef.push_back(utmCoord);
|
||||
}
|
||||
|
||||
void LtsCoordVector::convertGeoToQVectorQPointF(int zone) const
|
||||
{
|
||||
const auto it = m_utmMapQVectorQPointF.find(zone);
|
||||
if (it != m_utmMapQVectorQPointF.end())
|
||||
return;
|
||||
|
||||
convertGeoToStdUtm(zone);
|
||||
QVector<QPointF>& QVectorQPointFRef = m_utmMapQVectorQPointF[zone];
|
||||
QVectorQPointFRef.clear();
|
||||
QVectorQPointFRef.reserve(m_geo_coordinates.size());
|
||||
|
||||
for (const auto& utmCoord : m_utmMapStd[zone])
|
||||
QVectorQPointFRef.push_back(QPointF(utmCoord.x, utmCoord.y));
|
||||
}
|
||||
|
||||
} // namespace LtsCoordTrans
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsCoordinate/ltscoordinate_export.h>
|
||||
|
||||
#include <Core/core.hpp>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QPointF>
|
||||
#include <QtCore/QVector>
|
||||
#include <iosfwd>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace LtsCoordTrans
|
||||
{
|
||||
|
||||
class LTSCOORDINATE_EXPORT LtsCoordVector
|
||||
{
|
||||
public:
|
||||
explicit LtsCoordVector(const std::vector<Core::GeoPosition>& geo_coordinates);
|
||||
|
||||
int size() const
|
||||
{
|
||||
return m_geo_coordinates.size();
|
||||
}
|
||||
|
||||
const std::vector<Core::GeoPosition>& geoPosition() const
|
||||
{
|
||||
return m_geo_coordinates;
|
||||
}
|
||||
|
||||
const std::vector<LtsCoordTrans::UtmCoordinate>& toStdUtmCoord(int zone) const;
|
||||
const QVector<LtsCoordTrans::UtmCoordinate>& toQVectorUtmCoord(int zone) const;
|
||||
const QVector<QPointF>& toQVectorQPointF(int zone) const;
|
||||
|
||||
protected:
|
||||
void convertGeoToStdUtm(int zone) const;
|
||||
void convertGeoToQVectorUtm(int zone) const;
|
||||
void convertGeoToQVectorQPointF(int zone) const;
|
||||
|
||||
template <typename T> void convertGeoToUtmInternal(int zone, T& utmVectorRef) const
|
||||
{
|
||||
|
||||
utmVectorRef.clear();
|
||||
utmVectorRef.reserve(m_geo_coordinates.size());
|
||||
|
||||
for (const auto& geoCoord : std::as_const(m_geo_coordinates))
|
||||
utmVectorRef.push_back(LtsCoordTrans::UtmCoordinate::fromGeographic(geoCoord.lon, geoCoord.lat, zone));
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<Core::GeoPosition> m_geo_coordinates;
|
||||
|
||||
mutable std::unordered_map<int, std::vector<LtsCoordTrans::UtmCoordinate>> m_utmMapStd;
|
||||
mutable std::unordered_map<int, QVector<LtsCoordTrans::UtmCoordinate>> m_utmMapQVector;
|
||||
mutable std::unordered_map<int, QVector<QPointF>> m_utmMapQVectorQPointF;
|
||||
};
|
||||
|
||||
} // namespace LtsCoordTrans
|
||||
@@ -1,143 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_coordinate.h"
|
||||
|
||||
#include <QtCore/QLineF>
|
||||
#include <iomanip>
|
||||
|
||||
namespace LtsCoordTrans
|
||||
{
|
||||
|
||||
static long s_conversion_counter = 0;
|
||||
|
||||
std::function<double(double, double, double, bool*)> LtsCoordinate::m_getElevationCB;
|
||||
|
||||
void LtsCoordinate::setElevationCallback(const elevationCbFunc& elevationCB)
|
||||
{
|
||||
m_getElevationCB = elevationCB;
|
||||
}
|
||||
|
||||
bool LtsCoordinate::hasElevationCallback()
|
||||
{
|
||||
return m_getElevationCB != nullptr;
|
||||
}
|
||||
|
||||
double LtsCoordinate::elevationAt(double defaultElevation, bool* bIsCovered) const
|
||||
{
|
||||
|
||||
if (!bIsCovered)
|
||||
if (!std::isnan(m_elevation))
|
||||
return m_elevation;
|
||||
if (m_getElevationCB)
|
||||
m_elevation = m_getElevationCB(m_geo.lon, m_geo.lat, defaultElevation, bIsCovered);
|
||||
return m_elevation;
|
||||
}
|
||||
|
||||
void LtsCoordinate::setZValueAccordingElevation(double defaultElevation)
|
||||
{
|
||||
m_geo.z = elevationAt(defaultElevation);
|
||||
}
|
||||
|
||||
double LtsCoordinate::elevationAt(const LtsCoordinate& coordinate, double defaultElevation, bool* bIsCovered)
|
||||
{
|
||||
return coordinate.elevationAt(defaultElevation, bIsCovered);
|
||||
}
|
||||
|
||||
void LtsCoordinate::replaceZValueByElevationIfValue(double zValueToBeReplaced, double defaultElevation)
|
||||
{
|
||||
|
||||
if ((std::isnan(zValueToBeReplaced) && std::isnan(m_geo.z)) || qFuzzyCompare(m_geo.z, zValueToBeReplaced))
|
||||
setZValueAccordingElevation(defaultElevation);
|
||||
}
|
||||
|
||||
double LtsCoordinate::angleDegreeUtm2D(const LtsCoordinate& coord1, const LtsCoordinate& coord2)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate& utm1 = coord1.utmCoordinate();
|
||||
const LtsCoordTrans::UtmCoordinate& utm2 = coord2.utmCoordinateDiffZone(utm1.zone);
|
||||
|
||||
const QPointF& offsetUtm = utm2.toPoint() - utm1.toPoint();
|
||||
QLineF poly(QPointF(), offsetUtm);
|
||||
const double angle = poly.angle();
|
||||
|
||||
return fmod(angle + 90.0, 360);
|
||||
}
|
||||
|
||||
const UtmCoordinate& LtsCoordinate::utmCoordinateInternal(int zone) const
|
||||
{
|
||||
if (zone == -1)
|
||||
{
|
||||
if (!hasUtm())
|
||||
convertGeoToUtm();
|
||||
return m_utm2D;
|
||||
}
|
||||
utmCoordinateDiffZone(zone);
|
||||
return m_utm2D_differentZone;
|
||||
}
|
||||
|
||||
void LtsCoordinate::convertGeoToUtm() const
|
||||
{
|
||||
|
||||
int zone = -1;
|
||||
|
||||
if (std::isnan(m_geo.lon) || std::isnan(m_geo.lat))
|
||||
{
|
||||
fprintf(stderr, "Error while fromGeographic, value is NaN\n");
|
||||
m_utm2D = LtsCoordTrans::UtmCoordinate();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
++s_conversion_counter;
|
||||
#endif
|
||||
|
||||
m_utm2D = LtsCoordTrans::UtmCoordinate::fromGeographic(m_geo.lon, m_geo.lat, zone);
|
||||
Q_ASSERT_X(m_utm2D.zone > 0, "LtsCoordinate", "zone has to be set");
|
||||
}
|
||||
|
||||
QString LtsCoordinate::mgrs(int prec, bool withSpaces) const
|
||||
{
|
||||
utmCoordinateInternal();
|
||||
QString tmp = m_utm2D.mgrs(prec, withSpaces);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QString LtsCoordinate::mgrsWithZ(int prec, bool withSpaces) const
|
||||
{
|
||||
double ele = elevationAt();
|
||||
QString tmp = mgrs(prec, withSpaces) + QStringLiteral(" z=") + QString::number(ele, 'f', 2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QString LtsCoordinate::toString(bool fullAndExpensive) const
|
||||
{
|
||||
if (fullAndExpensive)
|
||||
{
|
||||
utmCoordinateInternal();
|
||||
elevationAt();
|
||||
}
|
||||
std::ostringstream stream;
|
||||
stream << "LtsCoordinate(m_geo=" << m_geo << ", m_utm2D.x " << m_utm2D.x << ", m_utm2D.y " << m_utm2D.y
|
||||
<< ", m_utm2D.zone " << m_utm2D.zone;
|
||||
if (!qFuzzyIsNull(m_utm2D.x) || !qFuzzyIsNull(m_utm2D.y))
|
||||
stream << ", m_utm2D.mgrs '" << m_utm2D.mgrs().toUtf8().constData() << "'";
|
||||
stream << ", elevation " << std::fixed << std::setprecision(3) << m_elevation << ")";
|
||||
return QString::fromStdString(stream.str());
|
||||
}
|
||||
|
||||
void LtsCoordinate::resetConversionCounter()
|
||||
{
|
||||
s_conversion_counter = 0;
|
||||
}
|
||||
|
||||
long LtsCoordinate::getConversionCounter()
|
||||
{
|
||||
return s_conversion_counter;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const LtsCoordinate& value)
|
||||
{
|
||||
stream << value.toString().toStdString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace LtsCoordTrans
|
||||
@@ -1,297 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsCoordinate/ltscoordinate_export.h>
|
||||
|
||||
#include <Core/core.hpp>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtils/LtsUtilsCore/qpoint3d.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QPointF>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace LtsCoordTrans
|
||||
{
|
||||
|
||||
using UtmCoordinate2D = LtsCoordTrans::UtmCoordinate;
|
||||
using QPoint3D = LtsUtils::QPoint3D;
|
||||
|
||||
class LTSCOORDINATE_EXPORT LtsCoordinate
|
||||
{
|
||||
public:
|
||||
explicit LtsCoordinate(double lon = 0, double lat = 0, double z = std::nan(""))
|
||||
: m_geo(Core::GeoPosition(lon, lat, z))
|
||||
{
|
||||
}
|
||||
|
||||
explicit LtsCoordinate(const QPointF& lonLat, double z = std::nan(""))
|
||||
: m_geo(Core::GeoPosition(lonLat.x(), lonLat.y(), z))
|
||||
{
|
||||
}
|
||||
|
||||
explicit LtsCoordinate(const Core::GeoPosition& geoPos) : m_geo(geoPos) {}
|
||||
|
||||
explicit LtsCoordinate(const Core::GeoPosition2D& geoPos2D) : m_geo(geoPos2D.lon, geoPos2D.lat, std::nan("")) {}
|
||||
|
||||
LtsCoordinate(const LtsCoordTrans::UtmCoordinate& utm2D, double zValue) = delete;
|
||||
|
||||
static LtsCoordinate fromGeoPosition(double lon, double lat, double z = std::nan(""))
|
||||
{
|
||||
return LtsCoordinate(lon, lat, z);
|
||||
}
|
||||
|
||||
static LtsCoordinate fromUtmCoordinate(const LtsCoordTrans::UtmCoordinate& utm2D, double zValue)
|
||||
{
|
||||
Q_ASSERT_X(utm2D.zone > 0, "LtsCoordinate", "zone has to be set");
|
||||
|
||||
const QPointF& geoPnt = utm2D.geographic();
|
||||
|
||||
return LtsCoordinate(geoPnt.x(), geoPnt.y(), zValue);
|
||||
}
|
||||
|
||||
static LtsCoordinate fromUtm(const QPointF& utm2d, int zone, double zValue)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate utmCoord(zone, utm2d.x(), utm2d.y());
|
||||
const QPointF& geoPnt = utmCoord.geographic();
|
||||
return LtsCoordinate(geoPnt.x(), geoPnt.y(), zValue);
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return hasGeo() || hasUtm();
|
||||
}
|
||||
|
||||
bool hasGeo() const
|
||||
{
|
||||
return !(valueIsNullOrNan(m_geo.lon) || valueIsNullOrNan(m_geo.lat));
|
||||
}
|
||||
|
||||
bool hasUtm() const
|
||||
{
|
||||
return m_utm2D.isValid();
|
||||
}
|
||||
|
||||
static bool valueIsNullOrNan(double value)
|
||||
{
|
||||
return qFuzzyIsNull(value) || std::isnan(value);
|
||||
}
|
||||
|
||||
QString mgrs(int prec = 5, bool withSpaces = true) const;
|
||||
QString mgrsWithZ(int prec = 5, bool withSpaces = true) const;
|
||||
|
||||
QString toString(bool fullAndExpensive = false) const;
|
||||
|
||||
static void resetConversionCounter();
|
||||
static long getConversionCounter();
|
||||
|
||||
const Core::GeoPosition& geoPosition() const
|
||||
{
|
||||
return m_geo;
|
||||
}
|
||||
|
||||
Core::GeoPosition2D geoPosition2D() const
|
||||
{
|
||||
return Core::GeoPosition2D(m_geo.lon, m_geo.lat);
|
||||
}
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoordinate() const
|
||||
{
|
||||
if (!hasUtm())
|
||||
convertGeoToUtm();
|
||||
return m_utm2D;
|
||||
}
|
||||
|
||||
double& rz()
|
||||
{
|
||||
return m_geo.z;
|
||||
}
|
||||
|
||||
double z() const
|
||||
{
|
||||
return m_geo.z;
|
||||
}
|
||||
|
||||
void setZ(double value)
|
||||
{
|
||||
m_geo.z = value;
|
||||
}
|
||||
|
||||
LtsCoordTrans::UtmCoordinate utmCoordinateDiffZone(int zone) const
|
||||
{
|
||||
|
||||
m_utm2D_differentZone = LtsCoordTrans::UtmCoordinate::fromGeographic(m_geo.lon, m_geo.lat, zone);
|
||||
return m_utm2D_differentZone;
|
||||
}
|
||||
|
||||
template <typename T> T toUtm(int zone = -1) const
|
||||
{
|
||||
T obj;
|
||||
helperToUtm(obj, zone);
|
||||
return obj;
|
||||
}
|
||||
|
||||
QPointF toUtmPointF() const
|
||||
{
|
||||
return toUtm<QPointF>();
|
||||
}
|
||||
|
||||
QPoint3D toUtmPoint3D() const
|
||||
{
|
||||
return toUtm<QPoint3D>();
|
||||
}
|
||||
|
||||
QPointF toGeoPointF() const
|
||||
{
|
||||
return QPointF(m_geo.lon, m_geo.lat);
|
||||
}
|
||||
|
||||
QPoint3D toGeoPoint3D() const
|
||||
{
|
||||
return QPoint3D(m_geo.lon, m_geo.lat, m_geo.z);
|
||||
}
|
||||
|
||||
UtmCoordinate3D toUtmCoordinate3D() const
|
||||
{
|
||||
return UtmCoordinate3D(utmCoordinate(), m_geo.z);
|
||||
}
|
||||
|
||||
using elevationCbFunc = std::function<double(double, double, double, bool*)>;
|
||||
|
||||
static void setElevationCallback(const elevationCbFunc& elevationCB);
|
||||
static bool hasElevationCallback();
|
||||
|
||||
double elevationAt(double defaultElevation = 0.0, bool* bIsCovered = nullptr) const;
|
||||
void setZValueAccordingElevation(double defaultElevation = 0.0);
|
||||
|
||||
static double elevationAt(const LtsCoordinate& coordinate, double defaultElevation = 0.0,
|
||||
bool* bIsCovered = nullptr);
|
||||
|
||||
void replaceZValueByElevationIfValue(double zValueToBeReplaced = std::nan(""), double defaultElevation = 0.0);
|
||||
|
||||
double heightOverElevation() const
|
||||
{
|
||||
return m_geo.z - elevationAt();
|
||||
}
|
||||
|
||||
double distanceUtm2D(const LtsCoordinate& other) const
|
||||
{
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& thisUtm2D = utmCoordinate();
|
||||
const LtsCoordTrans::UtmCoordinate& otherUtm2D = other.utmCoordinateDiffZone(m_utm2D.zone);
|
||||
return LtsCoordTrans::distance(thisUtm2D, otherUtm2D);
|
||||
}
|
||||
|
||||
double distanceUtm3D(const LtsCoordinate& other) const
|
||||
{
|
||||
|
||||
const QPoint3D& thisUtm3D = toUtm<QPoint3D>();
|
||||
const QPoint3D& otherUtm3D = other.toUtm<QPoint3D>(m_utm2D.zone);
|
||||
const double dist3D = (thisUtm3D - otherUtm3D).length();
|
||||
|
||||
Q_ASSERT_X(!std::isnan(dist3D), "LtsCoordinate", "ERROR, distance3D is NaN");
|
||||
|
||||
return dist3D;
|
||||
}
|
||||
|
||||
static double angleDegreeUtm2D(const LtsCoordinate& coord1, const LtsCoordinate& coord2);
|
||||
|
||||
protected:
|
||||
void clearGeo() const
|
||||
{
|
||||
clearGeoLonLat();
|
||||
m_geo.z = std::nan("");
|
||||
}
|
||||
|
||||
void clearGeoLonLat() const
|
||||
{
|
||||
m_geo.lon = 0;
|
||||
m_geo.lat = 0;
|
||||
}
|
||||
|
||||
void clearUtm() const
|
||||
{
|
||||
m_utm2D = m_utm2D_differentZone = UtmCoordinate2D();
|
||||
}
|
||||
|
||||
void clearElevation() const
|
||||
{
|
||||
m_elevation = std::nan("");
|
||||
}
|
||||
|
||||
void clear() const
|
||||
{
|
||||
clearGeo();
|
||||
clearUtm();
|
||||
clearElevation();
|
||||
}
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate& utmCoordinateInternal(int zone = -1) const;
|
||||
void convertGeoToUtm() const;
|
||||
|
||||
protected:
|
||||
void helperToUtm(QPointF& pntRef, int zone = -1) const
|
||||
{
|
||||
const auto& utmTemp = utmCoordinateInternal(zone);
|
||||
pntRef.rx() = utmTemp.x;
|
||||
pntRef.ry() = utmTemp.y;
|
||||
}
|
||||
|
||||
void helperToUtm(QPoint3D& pntRef, int zone = -1) const
|
||||
{
|
||||
const auto& utmTemp = utmCoordinateInternal(zone);
|
||||
pntRef.rx() = utmTemp.x;
|
||||
pntRef.ry() = utmTemp.y;
|
||||
pntRef.rz() = m_geo.z;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable Core::GeoPosition m_geo;
|
||||
mutable UtmCoordinate2D m_utm2D;
|
||||
mutable UtmCoordinate2D m_utm2D_differentZone;
|
||||
mutable double m_elevation{std::nan("")};
|
||||
|
||||
static elevationCbFunc m_getElevationCB;
|
||||
};
|
||||
|
||||
class LTSCOORDINATE_EXPORT LtsCoordinateNoImplicitCopy : public LtsCoordinate
|
||||
{
|
||||
public:
|
||||
using BaseClass = LtsCoordinate;
|
||||
|
||||
LtsCoordinateNoImplicitCopy() = default;
|
||||
explicit LtsCoordinateNoImplicitCopy(const LtsCoordinateNoImplicitCopy&) = default;
|
||||
|
||||
~LtsCoordinateNoImplicitCopy() = default;
|
||||
|
||||
explicit LtsCoordinateNoImplicitCopy(const QPointF& lonLat, double z = std::nan(""))
|
||||
: BaseClass(Core::GeoPosition(lonLat.x(), lonLat.y(), z))
|
||||
{
|
||||
}
|
||||
|
||||
explicit LtsCoordinateNoImplicitCopy(const Core::GeoPosition& geoPos) : BaseClass(geoPos) {}
|
||||
|
||||
explicit LtsCoordinateNoImplicitCopy(const Core::GeoPosition2D& geoPos2D) : BaseClass(geoPos2D) {}
|
||||
|
||||
void updateGeoPosition(const Core::GeoPosition& geoPos) const
|
||||
{
|
||||
clear();
|
||||
m_geo = geoPos;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T_OUT, typename T_IN> T_OUT convert(const T_IN& contIn)
|
||||
{
|
||||
T_OUT out;
|
||||
out.reserve(contIn.size());
|
||||
for (const Core::GeoPosition& posGeo : std::as_const(contIn))
|
||||
out.push_back(LtsCoordinate(posGeo));
|
||||
return out;
|
||||
}
|
||||
|
||||
LTSCOORDINATE_EXPORT std::ostream& operator<<(std::ostream& stream, const LtsCoordinate& value);
|
||||
|
||||
} // namespace LtsCoordTrans
|
||||
@@ -1,52 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# Make ${Qt6_Gui} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Gui)
|
||||
set(Qt6_Gui ${Qt6_Gui})
|
||||
else()
|
||||
set(Qt6_Gui "")
|
||||
endif()
|
||||
|
||||
|
||||
NGL_ADD_LIBRARY2(WS SV HLA LtsElevation SHARED
|
||||
lts_elevation_manager.cpp
|
||||
lts_elevation_manager.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsElevation
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_SOURCE_DIR}/Lts/Common
|
||||
${CMAKE_SOURCE_DIR}/Lts/Common/LtsUtils
|
||||
${CMAKE_SOURCE_DIR}/Lts/Viewer/SituationMap
|
||||
${CMAKE_SOURCE_DIR}/Lts/Viewer/SituationMap/Common
|
||||
)
|
||||
if(QT6_GUI_AVAILABLE)
|
||||
NGL_TARGET_LINK_LIBRARIES(LtsElevation
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
## LtsSessionDataDds
|
||||
PUBLIC
|
||||
LtsUtilsCoreHeaderOnly
|
||||
Qt6::Core
|
||||
${Qt6_Gui}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_RTI)
|
||||
# All ElevationMapManager / resource_path / exm-dtc usages live inside
|
||||
# #ifdef BUILD_RTI in lts_elevation_manager.cpp (Qt5 dependencies restored).
|
||||
target_link_libraries(LtsElevation PRIVATE
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
situationMapCommon
|
||||
situationMapElevationMap
|
||||
)
|
||||
endif()
|
||||
|
||||
ADD_SUBDIRECTORY(UnitTest_Elevation)
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
# Make ${Qt6_Gui} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Gui)
|
||||
set(Qt6_Gui ${Qt6_Gui})
|
||||
else()
|
||||
set(Qt6_Gui "")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# External dependency - missing: situationMapCommon, situationMapElevationMap
|
||||
# Test disabled until external dependencies are available
|
||||
# IF(BUILD_TESTING AND TARGET LtsElevation)
|
||||
# ADD_EXECUTABLE(commenUnitTestElevation ${LinkedSources} ${UnitTestSources} )
|
||||
#
|
||||
# TARGET_LINK_LIBRARIES(commenUnitTestElevation
|
||||
# NGLLogger
|
||||
# nglcoreapplication
|
||||
# LtsElevation
|
||||
# LtsCoordTrans
|
||||
# situationMapCommon
|
||||
# situationMapElevationMap
|
||||
# Qt6::Core
|
||||
# ${Qt6_Gui}
|
||||
# Qt6::Test)
|
||||
#
|
||||
# ADD_TEST(NAME commenUnitTestElevation COMMAND $<TARGET_FILE:commenUnitTestElevation>)
|
||||
# ENDIF()
|
||||
-198
@@ -1,198 +0,0 @@
|
||||
|
||||
|
||||
#include "elevation_unit_test.h"
|
||||
|
||||
#include <ElevationMap/elevation_map_manager.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QtTest/QTest>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
Q_DECLARE_METATYPE(LtsUtils::QPoint3D);
|
||||
Q_DECLARE_METATYPE(LtsElevation::LineOfSight);
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static const int s_id{4711};
|
||||
static LtsElevation::LtsElevationManager* s_eleMgr{nullptr};
|
||||
|
||||
class MyLtsElevationManagerBootstrap : public LtsElevation::LtsElevationManager
|
||||
{
|
||||
using BaseClass = LtsElevation::LtsElevationManager;
|
||||
|
||||
public:
|
||||
static LtsElevationManager* createInstanceUnitTest(int id, const QStringList& filePaths_rough_to_fine)
|
||||
{
|
||||
return BaseClass::createInstanceUnitTest(id, filePaths_rough_to_fine);
|
||||
}
|
||||
};
|
||||
|
||||
UnitTestElevation::UnitTestElevation()
|
||||
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("UnitTestElevation"))
|
||||
{
|
||||
}
|
||||
|
||||
void UnitTestElevation::initTestCase()
|
||||
{
|
||||
|
||||
QString filePath(QStringLiteral("/usr/share/arcgis/resources/elevation/Altmark_dt1.tif"));
|
||||
|
||||
s_eleMgr = MyLtsElevationManagerBootstrap::createInstanceUnitTest(s_id, {filePath});
|
||||
|
||||
const bool bIsValid = s_eleMgr->isValid();
|
||||
std::cerr << "myBootstrapMgr->isValid() 1 = " << bIsValid << std::endl;
|
||||
|
||||
{
|
||||
s_eleMgr->waitForInitialization();
|
||||
const bool bIsValid = s_eleMgr->isValid();
|
||||
std::cerr << "myBootstrapMgr->isValid() 2 = " << bIsValid << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestElevation::init()
|
||||
{
|
||||
QVERIFY2(s_eleMgr, "static LtsElevationManager does not exist");
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_elevation_data()
|
||||
{
|
||||
QTest::addColumn<QPointF>("lonLat");
|
||||
QTest::addColumn<double>("elevationRef");
|
||||
|
||||
QTest::newRow("elevation 1 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 70000 10000")).geographic() << 75.0;
|
||||
QTest::newRow("elevation 2 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 72000 13000")).geographic() << 80.0;
|
||||
|
||||
QTest::newRow("elevation 3 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 76925 18625")).geographic() << 92.0;
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_elevation()
|
||||
{
|
||||
QFETCH(QPointF, lonLat);
|
||||
QFETCH(double, elevationRef);
|
||||
|
||||
double elevation = s_eleMgr->elevation(lonLat.x(), lonLat.y());
|
||||
|
||||
QVERIFY2(qFuzzyCompare(elevationRef, elevation), " got wrong elevation result");
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_elevation_isCovered()
|
||||
{
|
||||
const QPointF& lonLat1 = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 70000 10000")).geographic();
|
||||
const QPointF& lonLat2 = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 60000 10000")).geographic();
|
||||
|
||||
const double defaultElevationValue = -123;
|
||||
{
|
||||
bool bIsCovered = false;
|
||||
s_eleMgr->elevation(lonLat1.x(), lonLat1.y(), defaultElevationValue, &bIsCovered);
|
||||
QVERIFY2(bIsCovered, " error on bIsCovered");
|
||||
}
|
||||
{
|
||||
bool bIsCovered = true;
|
||||
s_eleMgr->elevation(lonLat2.x(), lonLat2.y(), defaultElevationValue, &bIsCovered);
|
||||
QVERIFY2(!bIsCovered, " error on bIsCovered");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_elevation_defaultValue()
|
||||
{
|
||||
const QPointF& lonLat = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 60000 10000")).geographic();
|
||||
|
||||
double elevation = s_eleMgr->elevation(lonLat.x(), lonLat.y());
|
||||
QVERIFY2(qFuzzyCompare(elevation, std::numeric_limits<double>::min()), " error on defaultValue");
|
||||
|
||||
{
|
||||
const double defaultValue = 100;
|
||||
elevation = s_eleMgr->elevation(lonLat.x(), lonLat.y(), defaultValue);
|
||||
QVERIFY2(qFuzzyCompare(elevation, defaultValue), " error on defaultValue");
|
||||
}
|
||||
|
||||
{
|
||||
const double defaultValue = std::numeric_limits<double>::max();
|
||||
elevation = s_eleMgr->elevation(lonLat.x(), lonLat.y(), defaultValue);
|
||||
QVERIFY2(qFuzzyCompare(elevation, defaultValue), " error on defaultValue");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_lineOfSightCalculation_data()
|
||||
{
|
||||
QTest::addColumn<QPointF>("startGeo2D");
|
||||
QTest::addColumn<double>("startObjH");
|
||||
QTest::addColumn<QPointF>("endGeo2D");
|
||||
QTest::addColumn<double>("endObjH");
|
||||
QTest::addColumn<LtsElevation::LineOfSight>("expectedResult");
|
||||
|
||||
QTest::newRow("losDataset 1 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 60000 10000")).geographic() << 1.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 60000 60000")).geographic() << 1.0
|
||||
<< LtsElevation::LineOfSight::LOS_ERROR;
|
||||
|
||||
QTest::newRow("losDataset 2 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77200 17600")).geographic() << 1.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77600 17600")).geographic() << 1.0
|
||||
<< LtsElevation::LineOfSight::LOS_INVISIBLE;
|
||||
|
||||
QTest::newRow("losDataset 3 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77200 17600")).geographic() << 20.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77600 17600")).geographic() << 20.0
|
||||
<< LtsElevation::LineOfSight::LOS_VISIBLE;
|
||||
|
||||
QTest::newRow("losDataset 4 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77200 17600")).geographic() << -1.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77600 17600")).geographic() << 1.0
|
||||
<< LtsElevation::LineOfSight::LOS_ERROR;
|
||||
QTest::newRow("losDataset 5 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77200 17600")).geographic() << 1.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77600 17600")).geographic() << -1.0
|
||||
<< LtsElevation::LineOfSight::LOS_ERROR;
|
||||
QTest::newRow("losDataset 6 ")
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77200 17600")).geographic() << 0.0
|
||||
<< LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77600 17600")).geographic() << 0.0
|
||||
<< LtsElevation::LineOfSight::LOS_INVISIBLE;
|
||||
}
|
||||
|
||||
void UnitTestElevation::test_lineOfSightCalculation()
|
||||
{
|
||||
QFETCH(QPointF, startGeo2D);
|
||||
QFETCH(double, startObjH);
|
||||
QFETCH(QPointF, endGeo2D);
|
||||
QFETCH(double, endObjH);
|
||||
QFETCH(LtsElevation::LineOfSight, expectedResult);
|
||||
|
||||
LtsUtils::QPoint3D start3D = LtsUtils::QPoint3D::fromQPointF(startGeo2D);
|
||||
start3D.rz() = startObjH;
|
||||
start3D.rz() += s_eleMgr->elevation(start3D.x(), start3D.y());
|
||||
|
||||
LtsUtils::QPoint3D end3D = LtsUtils::QPoint3D::fromQPointF(endGeo2D);
|
||||
end3D.rz() = endObjH;
|
||||
end3D.rz() += s_eleMgr->elevation(end3D.x(), end3D.y());
|
||||
|
||||
LtsElevation::LineOfSight los = s_eleMgr->lineOfSightCalculation(start3D, end3D);
|
||||
NOTICE_LOG(m_logger) << "los = " << los;
|
||||
|
||||
{
|
||||
LtsElevation::LineOfSight los2 = s_eleMgr->lineOfSightCalculation(startGeo2D, startObjH, endGeo2D, endObjH);
|
||||
QVERIFY2(los == los2, " got different lineOfSightCalculation result");
|
||||
}
|
||||
|
||||
QVERIFY2(los == expectedResult, " got lineOfSightCalculation result");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTestElevation", "log4cxxElevationUnitTest.props");
|
||||
|
||||
UnitTestElevation tc;
|
||||
|
||||
int ret = QTest::qExec(&tc, argc, argv);
|
||||
|
||||
if (s_eleMgr)
|
||||
{
|
||||
s_eleMgr->cleanupAll();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ElevationMap/elevation_map_manager.h>
|
||||
#include <LtsElevation/lts_elevation_manager.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
using LOGGER_T = NGL::INGLLogger&;
|
||||
|
||||
class UnitTestElevation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UnitTestElevation();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void initTestCase();
|
||||
|
||||
void init();
|
||||
|
||||
void test_elevation_data();
|
||||
void test_elevation();
|
||||
|
||||
void test_elevation_isCovered();
|
||||
void test_elevation_defaultValue();
|
||||
|
||||
void test_lineOfSightCalculation_data();
|
||||
void test_lineOfSightCalculation();
|
||||
|
||||
private:
|
||||
NGL::INGLLogger& m_logger;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace LtsElevation
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char* name)
|
||||
{
|
||||
static const char ns[] = "Lts.Elevation.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LtsElevation
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
namespace LtsElevation
|
||||
{
|
||||
typedef NGL::INGLLogger& LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char* name);
|
||||
|
||||
inline LOGGER_T getLogger(const QString& loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace LtsElevation
|
||||
@@ -1,587 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_elevation_manager.h"
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
#include <AssetManagement/asm_data_plugin_interface.h>
|
||||
#include <ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <Viewer/SituationMap/ElevationMap/elevation_map_manager.h>
|
||||
#include <Viewer/SituationMap/Common/resource_path.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QHash>
|
||||
#include <QSharedPointer>
|
||||
#include <QUrl>
|
||||
|
||||
static_assert((int)SituationMap::ElevationMapManager::LineOfSight::LOS_UNDEFINED ==
|
||||
(int)LtsElevation::LineOfSight::LOS_UNDEFINED,
|
||||
"LineOfSight mismatch");
|
||||
static_assert((int)SituationMap::ElevationMapManager::LineOfSight::LOS_ERROR ==
|
||||
(int)LtsElevation::LineOfSight::LOS_ERROR,
|
||||
"LineOfSight mismatch");
|
||||
static_assert((int)SituationMap::ElevationMapManager::LineOfSight::LOS_VISIBLE ==
|
||||
(int)LtsElevation::LineOfSight::LOS_VISIBLE,
|
||||
"LineOfSight mismatch");
|
||||
static_assert((int)SituationMap::ElevationMapManager::LineOfSight::LOS_INVISIBLE ==
|
||||
(int)LtsElevation::LineOfSight::LOS_INVISIBLE,
|
||||
"LineOfSight mismatch");
|
||||
#endif
|
||||
|
||||
namespace LtsElevation
|
||||
{
|
||||
class LtsElevationManager;
|
||||
|
||||
using LtsElevatioMgrMapTrainingAreaId = QMap<int, LTS_ELEVATION_MANAGER_TYPE>;
|
||||
|
||||
static LtsElevatioMgrMapTrainingAreaId& ltsElevatioMgrMapTrainingAreaId()
|
||||
{
|
||||
static LtsElevatioMgrMapTrainingAreaId s_ltsElevatioMgrMapTrainingAreaId;
|
||||
return s_ltsElevatioMgrMapTrainingAreaId;
|
||||
}
|
||||
|
||||
static void cleanupLtsElevatioMgrMapTrainingAreaId()
|
||||
{
|
||||
qDeleteAll(ltsElevatioMgrMapTrainingAreaId());
|
||||
ltsElevatioMgrMapTrainingAreaId().clear();
|
||||
}
|
||||
|
||||
LtsElevatioMgrMapTrainingAreaId& getLtsElevationMgrMapTrainingAreaId()
|
||||
{
|
||||
if (ltsElevatioMgrMapTrainingAreaId().isEmpty())
|
||||
qAddPostRoutine(cleanupLtsElevatioMgrMapTrainingAreaId);
|
||||
|
||||
return ltsElevatioMgrMapTrainingAreaId();
|
||||
}
|
||||
|
||||
static long s_counter{0};
|
||||
|
||||
class LtsElevationManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
~Private()
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
delete m_elevationManager;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
#ifdef BUILD_RTI
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> m_asmDtc;
|
||||
SituationMap::ElevationMapManager* m_elevationManager{nullptr};
|
||||
#endif
|
||||
|
||||
QStringList m_filePaths_rough_to_fine;
|
||||
};
|
||||
|
||||
LtsElevationManager::LtsElevationManager()
|
||||
: QObject(nullptr)
|
||||
, d(new Private)
|
||||
, m_logger(getLogger("LtsElevationManager"))
|
||||
{
|
||||
++s_counter;
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START, s_counter=" << s_counter << " this=" << this;
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END, s_counter=" << s_counter << " this=" << this;
|
||||
}
|
||||
|
||||
LtsElevationManager::~LtsElevationManager()
|
||||
{
|
||||
--s_counter;
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START, s_counter=" << s_counter << " this=" << this;
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END, s_counter=" << s_counter << " this=" << this;
|
||||
}
|
||||
|
||||
LTS_ELEVATION_MANAGER_TYPE
|
||||
LtsElevationManager::createInstance(int exerciseId, const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc,
|
||||
#ifdef BUILD_RTI
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc
|
||||
#else
|
||||
const std::shared_ptr<void>& asmDtc
|
||||
#endif
|
||||
)
|
||||
{
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " START, exerciseId=" << exerciseId;
|
||||
|
||||
if (exerciseId < 0)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " exerciseId invalid, exerciseId=" << exerciseId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Qt5 logic restored (the qt6 port had dropped the exerciseId->trainingAreaId
|
||||
// caching and always returned nullptr here).
|
||||
#ifdef BUILD_RTI
|
||||
int trainingAreaId = -1;
|
||||
|
||||
// remember for future calls
|
||||
// (so createInstance should work WITHOUT dtcs)
|
||||
// Idea: MainHandler: createInstance with exerciseId and valid dtcs
|
||||
// Plugin or simular: createInstance with exerciseId and no dtcs
|
||||
static QHash<int, int> s_exIdToTaIdStore;
|
||||
|
||||
const auto exTaIt = s_exIdToTaIdStore.find(exerciseId);
|
||||
if (exTaIt != s_exIdToTaIdStore.end())
|
||||
{
|
||||
// CASE 1:
|
||||
// already created:
|
||||
trainingAreaId = *exTaIt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// CASE 2:
|
||||
// ... or create on demand:
|
||||
if (!exmDtc || !asmDtc)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " no dtcs for exerciseId=" << exerciseId
|
||||
<< ", asmDtc=" << asmDtc
|
||||
<< ", exmDtc=" << exmDtc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// exId to taId
|
||||
trainingAreaId = exerciseIdToTrainingAreaId(exerciseId, exmDtc);
|
||||
if (trainingAreaId <= 0)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " Error getting trainingAreaId"
|
||||
<< ", exerciseId=" << exerciseId
|
||||
<< ", trainingAreaId=" << trainingAreaId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// store and remember:
|
||||
s_exIdToTaIdStore[exerciseId] = trainingAreaId;
|
||||
}
|
||||
|
||||
// CASE 1: Following should work even with invalid asmDtc:
|
||||
LTS_ELEVATION_MANAGER_TYPE temp = createInstanceForTrainingAreaId(trainingAreaId, asmDtc);
|
||||
if (!temp)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " Error on createInstanceForTrainingAreaId"
|
||||
<< ", exerciseId=" << exerciseId
|
||||
<< ", trainingAreaId=" << trainingAreaId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// add exmDtc
|
||||
temp->initDDS(exmDtc, asmDtc);
|
||||
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " END, exerciseId=" << exerciseId;
|
||||
return temp;
|
||||
#else
|
||||
Q_UNUSED(exmDtc);
|
||||
Q_UNUSED(asmDtc);
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, cannot create instance";
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
LTS_ELEVATION_MANAGER_TYPE LtsElevationManager::getInstance(int exerciseId)
|
||||
{
|
||||
return LtsElevationManager::createInstance(exerciseId);
|
||||
}
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
LTS_ELEVATION_MANAGER_TYPE
|
||||
LtsElevationManager::createInstanceForTrainingAreaId(int trainingAreaId,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc)
|
||||
{
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " START, trainingAreaId=" << trainingAreaId;
|
||||
|
||||
if (trainingAreaId < 0)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " trainingAreaId invalid, trainingAreaId=" << trainingAreaId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LtsElevatioMgrMapTrainingAreaId& map = getLtsElevationMgrMapTrainingAreaId();
|
||||
QMap<int, LTS_ELEVATION_MANAGER_TYPE>::iterator it = map.find(trainingAreaId);
|
||||
|
||||
if (it != map.end())
|
||||
{
|
||||
DEBUG_LOG(logger) << " LtsElevationMgrMap contains instances: " << map.size();
|
||||
return it.value();
|
||||
}
|
||||
|
||||
if (!asmDtc)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " no dtcs for trainingAreaId=" << trainingAreaId << ", asmDtc=" << asmDtc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LTS_ELEVATION_MANAGER_TYPE temp = new LtsElevationManager();
|
||||
|
||||
temp->initDDS(nullptr, asmDtc);
|
||||
|
||||
const QStringList& filenames = temp->getFilenamesForTrainingArea(trainingAreaId);
|
||||
if (filenames.isEmpty())
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " no filenames for trainingAreaId=" << trainingAreaId;
|
||||
delete temp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool bInitFilenames = temp->init(filenames);
|
||||
if (!bInitFilenames)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " bInitFilenames failed for trainingAreaId=" << trainingAreaId;
|
||||
delete temp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
map.insert(trainingAreaId, temp);
|
||||
|
||||
DEBUG_LOG(logger) << " LtsElevationMgrMap contains instances now: " << map.size();
|
||||
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " END, trainingAreaId=" << trainingAreaId;
|
||||
return map[trainingAreaId];
|
||||
}
|
||||
#endif
|
||||
|
||||
LTS_ELEVATION_MANAGER_TYPE LtsElevationManager::createInstanceUnitTest(int id,
|
||||
const QStringList& filePaths_rough_to_fine)
|
||||
{
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
|
||||
LtsElevatioMgrMapTrainingAreaId& map = getLtsElevationMgrMapTrainingAreaId();
|
||||
QMap<int, LTS_ELEVATION_MANAGER_TYPE>::iterator it = map.find(id);
|
||||
|
||||
if (it != map.end())
|
||||
{
|
||||
DEBUG_LOG(logger) << " LtsElevationMgrMap contains instances: " << map.size();
|
||||
return it.value();
|
||||
}
|
||||
|
||||
LTS_ELEVATION_MANAGER_TYPE temp = new LtsElevationManager();
|
||||
|
||||
bool bInitFilenames = temp->init(filePaths_rough_to_fine);
|
||||
if (!bInitFilenames)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " bInitFilenames failed for id=" << id;
|
||||
delete temp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
map.insert(id, temp);
|
||||
|
||||
DEBUG_LOG(logger) << " LtsElevationMgrMap contains instances now: " << map.size();
|
||||
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " END, trainingAreaId=" << id;
|
||||
return map[id];
|
||||
}
|
||||
|
||||
void LtsElevationManager::cleanupAll()
|
||||
{
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " START";
|
||||
cleanupLtsElevatioMgrMapTrainingAreaId();
|
||||
TRACE_LOG(logger) << Q_FUNC_INFO << " END";
|
||||
}
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
void LtsElevationManager::initDDS(const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc)
|
||||
{
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START";
|
||||
|
||||
d->m_exmDtc = exmDtc;
|
||||
if (d->m_exmDtc)
|
||||
d->m_exmDtc->waitForHistoricalDataExercise(1000);
|
||||
|
||||
d->m_asmDtc = asmDtc;
|
||||
if (d->m_asmDtc)
|
||||
d->m_asmDtc->waitForHistoricalDataTrainingArea(1000);
|
||||
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END";
|
||||
}
|
||||
#else
|
||||
void LtsElevationManager::initDDS(const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc,
|
||||
const std::shared_ptr<void>& asmDtc)
|
||||
{
|
||||
Q_UNUSED(exmDtc);
|
||||
Q_UNUSED(asmDtc);
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START (BUILD_RTI=OFF, no DDS init)";
|
||||
|
||||
// BUILD_RTI=OFF: No DDS initialization
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
QStringList LtsElevationManager::getFilenamesForExercise(int exerciseId)
|
||||
{
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START";
|
||||
|
||||
if (!d->m_exmDtc || !d->m_asmDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " no dtcs"
|
||||
<< ", exerciseId=" << exerciseId;
|
||||
return {};
|
||||
}
|
||||
|
||||
int trainingAreaId = exerciseIdToTrainingAreaId(exerciseId, d->m_exmDtc);
|
||||
if (trainingAreaId <= 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " Error getting trainingAreaId"
|
||||
<< ", exerciseId=" << exerciseId << ", trainingAreaId=" << trainingAreaId;
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList filePaths_rough_to_fine = getFilenamesForTrainingArea(trainingAreaId);
|
||||
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO
|
||||
<< " END, filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(";"));
|
||||
return filePaths_rough_to_fine;
|
||||
}
|
||||
|
||||
QStringList LtsElevationManager::getFilenamesForTrainingArea(int trainingAreaId)
|
||||
{
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START";
|
||||
|
||||
if (!d->m_asmDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " no dtcs"
|
||||
<< ", trainingAreaId=" << trainingAreaId;
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList filePaths_rough_to_fine;
|
||||
{
|
||||
d->m_asmDtc->waitForHistoricalDataTrainingArea(1000);
|
||||
const AssetManagement::TrainingArea& ta = d->m_asmDtc->trainingArea(trainingAreaId);
|
||||
if (ta.id != trainingAreaId)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " Error on s_asmDtc->trainingArea"
|
||||
<< ", trainingAreaId=" << trainingAreaId;
|
||||
return {};
|
||||
}
|
||||
const std::vector<AssetManagement::MapDescription>& mdVec = ta.elevation;
|
||||
filePaths_rough_to_fine.reserve(mdVec.size());
|
||||
|
||||
for (const AssetManagement::MapDescription& md : std::as_const(mdVec))
|
||||
{
|
||||
|
||||
QUrl url(QString::fromStdString(md.url));
|
||||
QString filePathAbs = url.toLocalFile();
|
||||
if (QDir::isRelativePath(filePathAbs))
|
||||
filePathAbs = SituationMap::getResourcePath() + QStringLiteral("/elevation/") + filePathAbs;
|
||||
|
||||
filePaths_rough_to_fine.append(filePathAbs);
|
||||
}
|
||||
}
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO
|
||||
<< " END, filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(";"));
|
||||
return filePaths_rough_to_fine;
|
||||
}
|
||||
#else
|
||||
QStringList LtsElevationManager::getFilenamesForExercise(int /*exerciseId*/)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, getFilenamesForExercise not available";
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList LtsElevationManager::getFilenamesForTrainingArea(int /*trainingAreaId*/)
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, getFilenamesForTrainingArea not available";
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
bool LtsElevationManager::init(const QStringList& filePaths_rough_to_fine)
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
delete d->m_elevationManager;
|
||||
|
||||
d->m_elevationManager = new SituationMap::ElevationMapManager();
|
||||
int cnt = d->m_elevationManager->init(filePaths_rough_to_fine);
|
||||
|
||||
if (cnt != filePaths_rough_to_fine.size())
|
||||
{
|
||||
FATAL_LOG(m_logger) << Q_FUNC_INFO << " ERROR, not all files could be loaded !!!";
|
||||
FATAL_LOG(m_logger) << Q_FUNC_INFO << " ERROR, not all files could be loaded !!!";
|
||||
FATAL_LOG(m_logger) << Q_FUNC_INFO << " ERROR, not all files could be loaded !!!";
|
||||
FATAL_LOG(m_logger) << Q_FUNC_INFO << " ERROR, not all files could be loaded !!!";
|
||||
FATAL_LOG(m_logger) << Q_FUNC_INFO << " ERROR, not all files could be loaded !!!";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(filePaths_rough_to_fine);
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, init not available";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
int LtsElevationManager::exerciseIdToTrainingAreaId(int exerciseId,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc)
|
||||
{
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
|
||||
if (!exmDtc)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " no dtcs"
|
||||
<< ", exerciseId=" << exerciseId;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int trainingAreaId = -1;
|
||||
{
|
||||
exmDtc->waitForHistoricalDataExercise(1000);
|
||||
|
||||
const ExerciseManagement::Exercise& exm = exmDtc->exercise(exerciseId);
|
||||
if (exm.id != exerciseId)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " Error on m_exmDtc->exercise"
|
||||
<< ", exerciseId=" << exerciseId;
|
||||
return -1;
|
||||
}
|
||||
trainingAreaId = exm.trainingAreaId;
|
||||
|
||||
if (trainingAreaId <= 0)
|
||||
{
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " Error getting trainingAreaId"
|
||||
<< ", exerciseId=" << exerciseId << ", trainingAreaId=" << trainingAreaId;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return trainingAreaId;
|
||||
}
|
||||
#else
|
||||
int LtsElevationManager::exerciseIdToTrainingAreaId(int exerciseId,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc)
|
||||
{
|
||||
Q_UNUSED(exerciseId);
|
||||
Q_UNUSED(exmDtc);
|
||||
LOGGER_T logger = getLogger("LtsElevationManager");
|
||||
ERROR_LOG(logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, cannot convert exerciseId to trainingAreaId";
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool LtsElevationManager::waitForInitialization()
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
if (!d->m_elevationManager)
|
||||
return false;
|
||||
return d->m_elevationManager->waitForInitialization();
|
||||
#else
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, waitForInitialization not available";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LtsElevationManager::isValid() const
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
if (!d->m_elevationManager)
|
||||
return false;
|
||||
return d->m_elevationManager->isValid();
|
||||
#else
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, isValid not available";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
double LtsElevationManager::elevation(double lon_rad, double lat_rad, double defaultValue, bool* bIsCovered) const
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
if (!d->m_elevationManager)
|
||||
return defaultValue;
|
||||
return d->m_elevationManager->elevation(lon_rad, lat_rad, defaultValue, bIsCovered);
|
||||
#else
|
||||
Q_UNUSED(lon_rad);
|
||||
Q_UNUSED(lat_rad);
|
||||
Q_UNUSED(bIsCovered);
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, elevation not available";
|
||||
return defaultValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
LineOfSight LtsElevationManager::lineOfSightCalculation(const LtsUtils::QPoint3D& startPointGeo_absZ,
|
||||
const LtsUtils::QPoint3D& endPointGeo_absZ)
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START"
|
||||
<< ", startPointGeo_absZ = " << startPointGeo_absZ
|
||||
<< ", endPointGeo_absZ = " << endPointGeo_absZ;
|
||||
|
||||
if (!isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " Error, LtsElevationManager not valid";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
}
|
||||
|
||||
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult =
|
||||
d->m_elevationManager->lineOfSightCalculation(startPointGeo_absZ, endPointGeo_absZ);
|
||||
|
||||
LtsElevation::LineOfSight result = static_cast<LtsElevation::LineOfSight>(eleMapMgrResult);
|
||||
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END"
|
||||
<< ", startPointGeo = " << startPointGeo_absZ << ", endPointGeo = " << endPointGeo_absZ
|
||||
<< " -> LineOfSight " << result;
|
||||
return result;
|
||||
#else
|
||||
Q_UNUSED(startPointGeo_absZ);
|
||||
Q_UNUSED(endPointGeo_absZ);
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, lineOfSightCalculation not available";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
LineOfSight LtsElevationManager::lineOfSightCalculation(const QPointF& startPointGeo, double startHat,
|
||||
const QPointF& endPointGeo, double endHat)
|
||||
{
|
||||
#ifdef BUILD_RTI
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " START"
|
||||
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
|
||||
<< ", endPointGeo = " << endPointGeo << ", endHat = " << endHat;
|
||||
|
||||
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult =
|
||||
d->m_elevationManager->lineOfSightCalculation(startPointGeo, startHat, endPointGeo, endHat);
|
||||
|
||||
LtsElevation::LineOfSight result = static_cast<LtsElevation::LineOfSight>(eleMapMgrResult);
|
||||
|
||||
TRACE_LOG(m_logger) << Q_FUNC_INFO << " END"
|
||||
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
|
||||
<< ", endPointGeo = " << endPointGeo << ", endHat = " << endHat << " -> LineOfSight "
|
||||
<< static_cast<int>(eleMapMgrResult);
|
||||
return result;
|
||||
#else
|
||||
Q_UNUSED(startPointGeo);
|
||||
Q_UNUSED(startHat);
|
||||
Q_UNUSED(endPointGeo);
|
||||
Q_UNUSED(endHat);
|
||||
ERROR_LOG(m_logger) << Q_FUNC_INFO << " BUILD_RTI=OFF, lineOfSightCalculation not available";
|
||||
return LineOfSight::LOS_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString toString(const LineOfSight& value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case LineOfSight::LOS_UNDEFINED:
|
||||
return QStringLiteral("LOS_UNDEFINED");
|
||||
case LineOfSight::LOS_ERROR:
|
||||
return QStringLiteral("LOS_ERROR");
|
||||
case LineOfSight::LOS_VISIBLE:
|
||||
return QStringLiteral("LOS_VISIBLE");
|
||||
case LineOfSight::LOS_INVISIBLE:
|
||||
return QStringLiteral("LOS_INVISIBLE");
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
return QStringLiteral("LineOfSightERROR");
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const LineOfSight value)
|
||||
{
|
||||
stream << toString(value).toStdString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace LtsElevation
|
||||
@@ -1,113 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#include "ltselevation_export.h"
|
||||
|
||||
#include <LtsUtils/LtsUtilsCore/qpoint3d.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QStringList>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSessionDataDds;
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
} // namespace ExerciseManagement
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
namespace AssetManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
} // namespace AssetManagement
|
||||
#endif
|
||||
|
||||
namespace LtsElevation
|
||||
{
|
||||
|
||||
enum class LineOfSight { LOS_UNDEFINED, LOS_ERROR, LOS_VISIBLE, LOS_INVISIBLE };
|
||||
|
||||
class LtsElevationManager;
|
||||
using LTS_ELEVATION_MANAGER_TYPE = QPointer<LtsElevationManager>;
|
||||
|
||||
class LTSELEVATION_EXPORT LtsElevationManager : public QObject
|
||||
{
|
||||
public:
|
||||
static LTS_ELEVATION_MANAGER_TYPE
|
||||
createInstance(int exerciseId, const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc = {},
|
||||
#ifdef BUILD_RTI
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc = {}
|
||||
#else
|
||||
const std::shared_ptr<void>& asmDtc = {}
|
||||
#endif
|
||||
);
|
||||
|
||||
static LTS_ELEVATION_MANAGER_TYPE getInstance(int exerciseId);
|
||||
|
||||
#ifdef BUILD_RTI
|
||||
static LTS_ELEVATION_MANAGER_TYPE
|
||||
createInstanceForTrainingAreaId(int trainingAreaId,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc = nullptr);
|
||||
#endif
|
||||
|
||||
static void cleanupAll();
|
||||
virtual ~LtsElevationManager();
|
||||
|
||||
bool waitForInitialization();
|
||||
bool isValid() const;
|
||||
|
||||
double elevation(double lon_rad, double lat_rad, double defaultValue = std::numeric_limits<double>::min(),
|
||||
bool* bIsCovered = nullptr) const;
|
||||
|
||||
LineOfSight lineOfSightCalculation(const LtsUtils::QPoint3D& startPointGeo_absZ,
|
||||
const LtsUtils::QPoint3D& endPointGeo_absZ);
|
||||
|
||||
LineOfSight lineOfSightCalculation(const QPointF& startPointGeo, double startHat, const QPointF& endPointGeo,
|
||||
double endHat);
|
||||
|
||||
protected:
|
||||
explicit LtsElevationManager();
|
||||
|
||||
void initDDS(const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc,
|
||||
#ifdef BUILD_RTI
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc>& asmDtc
|
||||
#else
|
||||
const std::shared_ptr<void>& asmDtc
|
||||
#endif
|
||||
);
|
||||
bool init(const QStringList& filePaths_rough_to_fine);
|
||||
static int exerciseIdToTrainingAreaId(int exerciseId,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc>& exmDtc);
|
||||
|
||||
QStringList getFilenamesForExercise(int exerciseId);
|
||||
QStringList getFilenamesForTrainingArea(int trainingAreaId);
|
||||
|
||||
static LTS_ELEVATION_MANAGER_TYPE createInstanceUnitTest(int id, const QStringList& filePaths_rough_to_fine);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
Private* d;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
LTSELEVATION_EXPORT const QString toString(const LtsElevation::LineOfSight& value);
|
||||
|
||||
LTSELEVATION_EXPORT std::ostream& operator<<(std::ostream& stream, const LtsElevation::LineOfSight value);
|
||||
|
||||
} // namespace LtsElevation
|
||||
@@ -1,44 +0,0 @@
|
||||
#
|
||||
# Library which automatically provides Login/Logoff so that user data (rights for apps, etc.) is available before any app is started
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Mike Wille, SLSE, 2016-10-27
|
||||
#
|
||||
|
||||
|
||||
# LtsLogin
|
||||
|
||||
set(LtsLogin_SRCS
|
||||
lts_login.cpp
|
||||
logout_info_dialog.cpp
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(LtsLogin_SRCS
|
||||
logout_info_dialog.ui
|
||||
)
|
||||
|
||||
IF(BUILD_RTI)
|
||||
NGL_ADD_LIBRARY2(WS LtsLogin SHARED ${LtsLogin_SRCS})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsLogin
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(LtsLogin
|
||||
PRIVATE
|
||||
LtsAppDescriptor
|
||||
LtsPluginManager
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
LtsWidgets
|
||||
LtsUtilsSettings
|
||||
LtsUtilsCoreHeaderOnly
|
||||
PUBLIC
|
||||
OpmDataPluginInterface
|
||||
SrmDataPluginInterface
|
||||
AsmDataPluginInterface
|
||||
Qt6::Core
|
||||
)
|
||||
ENDIF(BUILD_RTI)
|
||||
@@ -1,92 +0,0 @@
|
||||
|
||||
|
||||
#include "logout_info_dialog.h"
|
||||
|
||||
#include "ui_logout_info_dialog.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
namespace LtsLogin
|
||||
{
|
||||
|
||||
LogoutInformationDialog::LogoutInformationDialog(int timeOut, AssetManagement::ShutdownAction shutdownAction,
|
||||
QWidget* parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal), m_ui(new Ui::LogoutInformationDialog),
|
||||
m_timer(new QTimer(this)), m_timeOut(timeOut), m_secsLeft(timeOut)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
QString actionText;
|
||||
switch (shutdownAction)
|
||||
{
|
||||
case AssetManagement::ShutdownAction::NoAction:
|
||||
case AssetManagement::ShutdownAction::Logout:
|
||||
actionText = tr("logout");
|
||||
break;
|
||||
case AssetManagement::ShutdownAction::Shutdown:
|
||||
actionText = tr("shutdown");
|
||||
break;
|
||||
case AssetManagement::ShutdownAction::Reboot:
|
||||
actionText = tr("reboot");
|
||||
break;
|
||||
}
|
||||
|
||||
setText(tr("A %1 was triggered by a remote workstation.").arg(actionText));
|
||||
|
||||
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this,
|
||||
&LogoutInformationDialog::acceptClicked);
|
||||
connect(m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this,
|
||||
&LogoutInformationDialog::closeClicked);
|
||||
connect(m_timer, &QTimer::timeout, this, &LogoutInformationDialog::onTimerTimeout);
|
||||
|
||||
m_timer->setInterval(1000);
|
||||
}
|
||||
|
||||
LogoutInformationDialog::~LogoutInformationDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::setText(const QString& text)
|
||||
{
|
||||
m_ui->lblLogoutText->setText(text);
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::onTimerTimeout()
|
||||
{
|
||||
if (m_secsLeft > 0)
|
||||
{
|
||||
m_secsLeft--;
|
||||
setCloseButtonText(m_secsLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
acceptClicked();
|
||||
}
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::acceptClicked()
|
||||
{
|
||||
m_timer->stop();
|
||||
accept();
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::closeClicked()
|
||||
{
|
||||
m_timer->stop();
|
||||
reject();
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::setCloseButtonText(int secsLeft)
|
||||
{
|
||||
m_ui->buttonBox->getButton(LtsWidgets::DialogButton::Close)->setText(tr("Abort [%1]").arg(secsLeft));
|
||||
}
|
||||
|
||||
void LogoutInformationDialog::showEvent(QShowEvent* event)
|
||||
{
|
||||
m_secsLeft = m_timeOut;
|
||||
setCloseButtonText(m_secsLeft);
|
||||
m_timer->start();
|
||||
LtsWidgets::LtsFramelessDialog::showEvent(event);
|
||||
}
|
||||
|
||||
} // namespace LtsLogin
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <AssetManagement/asm.hpp>
|
||||
#include <LtsWidgets/lts_frameless_dialog.h>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class QTimer;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class LogoutInformationDialog;
|
||||
}
|
||||
|
||||
namespace LtsLogin
|
||||
{
|
||||
|
||||
class LogoutInformationDialog : public LtsWidgets::LtsFramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LogoutInformationDialog(int timeOut, AssetManagement::ShutdownAction shutdownAction, QWidget* parent = nullptr);
|
||||
~LogoutInformationDialog();
|
||||
|
||||
private slots:
|
||||
void onTimerTimeout();
|
||||
void acceptClicked();
|
||||
void closeClicked();
|
||||
|
||||
private:
|
||||
void setText(const QString& text);
|
||||
void setCloseButtonText(int secsLeft);
|
||||
|
||||
Ui::LogoutInformationDialog* m_ui;
|
||||
QTimer* m_timer;
|
||||
int m_timeOut;
|
||||
int m_secsLeft;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override final;
|
||||
};
|
||||
|
||||
} // namespace LtsLogin
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LogoutInformationDialog</class>
|
||||
<widget class="QWidget" name="LogoutInformationDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>165</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblLogoutText">
|
||||
<property name="text">
|
||||
<string notr="true"><logout information text></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsDialogButtonBox" name="buttonBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsDialogButtonBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsWidgets/lts_dialog_button_box.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,282 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_login.h"
|
||||
|
||||
#include "logout_info_dialog.h"
|
||||
|
||||
#include <LtsAppDescriptor/lts_app_descriptor.h>
|
||||
#include <LtsPluginManager/lts_plugin_manager.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsUtils/LtsUtilsCore/dds_vector.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <LtsWidgets/lts_wait_dialog.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtCore/QProcess>
|
||||
|
||||
namespace LtsLogin
|
||||
{
|
||||
const int logoutShutdownTimeout = 2 * 60;
|
||||
|
||||
LtsLogin::LtsLogin()
|
||||
: m_loginApp(nullptr), m_shutdownAction(AssetManagement::ShutdownAction::NoAction), m_isInLogoutDialog(false)
|
||||
{
|
||||
}
|
||||
|
||||
LtsLogin::~LtsLogin()
|
||||
{
|
||||
delete m_loginApp;
|
||||
m_loginApp = nullptr;
|
||||
}
|
||||
|
||||
void LtsLogin::login()
|
||||
{
|
||||
LtsAppDescriptor::PluginInfo opmDataPlugin;
|
||||
opmDataPlugin.iid = QStringLiteral("opm");
|
||||
opmDataPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
|
||||
|
||||
LtsAppDescriptor::PluginInfo pdmDataPlugin;
|
||||
pdmDataPlugin.iid = QStringLiteral("pdm");
|
||||
pdmDataPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
|
||||
|
||||
LtsAppDescriptor::PluginInfo asmDataPlugin;
|
||||
asmDataPlugin.iid = QStringLiteral("asm");
|
||||
asmDataPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
|
||||
|
||||
LtsAppDescriptor::PluginInfo srmDataPlugin;
|
||||
srmDataPlugin.iid = QStringLiteral("srm");
|
||||
srmDataPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::DATA;
|
||||
|
||||
LtsAppDescriptor::PluginInfo guiPlugin;
|
||||
guiPlugin.iid = m_loginPluginIid;
|
||||
guiPlugin.type = LtsAppDescriptor::PluginInfo::PluginType::GUI;
|
||||
guiPlugin.flags |= LtsAppDescriptor::PluginInfo::Flag::PAYLOAD;
|
||||
|
||||
QVector<LtsAppDescriptor::PluginInfo> plugins;
|
||||
plugins.append(opmDataPlugin);
|
||||
plugins.append(pdmDataPlugin);
|
||||
plugins.append(asmDataPlugin);
|
||||
plugins.append(srmDataPlugin);
|
||||
plugins.append(guiPlugin);
|
||||
|
||||
LtsAppDescriptor::AppDescription app;
|
||||
app.active = true;
|
||||
app.appName = QStringLiteral("Login");
|
||||
app.pluginInfos = plugins;
|
||||
|
||||
LtsSession::DdsConnectionParams connParams;
|
||||
connParams.domainId = LtsSessionData::LtsSessionData::getInstance()->getDomainIdPreset();
|
||||
connParams.tcpConnectionUrl = LtsSessionData::LtsSessionData::getInstance()->getTcpConnectionUrl();
|
||||
connParams.partitionType = IDL::PartitionType::Global;
|
||||
connParams.partitionId = 0;
|
||||
|
||||
m_loginApp = new LtsPluginManager::LtsPluginManager();
|
||||
bool result = m_loginApp->startApp(app, true, connParams);
|
||||
if (!result)
|
||||
{
|
||||
qWarning() << "no login plugin - probably an offline project";
|
||||
emit signalLoginDone();
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_loginApp, &LtsPluginManager::LtsPluginManager::signalInitializationFinished, this, [this]() {
|
||||
disconnect(m_loginApp, &LtsPluginManager::LtsPluginManager::signalInitializationFinished, this, nullptr);
|
||||
|
||||
LtsSession::LtsSession* session = getAdminSession();
|
||||
|
||||
if (!session)
|
||||
{
|
||||
qCritical() << "I cannot find the Admin Session :( - abort!";
|
||||
QMessageBox::critical(nullptr, tr("Error loading login app"), tr("Could not load login app - abort."));
|
||||
abort();
|
||||
}
|
||||
|
||||
if (session->isInitializationDone())
|
||||
QMetaObject::invokeMethod(this, &LtsLogin::slotLoginDone);
|
||||
else
|
||||
connect(session, &LtsSession::LtsSession::signalDoneInitializingSession, this, &LtsLogin::slotLoginDone,
|
||||
Qt::UniqueConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void LtsLogin::slotLoginDone()
|
||||
{
|
||||
LtsSession::LtsSession* session = getAdminSession();
|
||||
|
||||
if (session != nullptr)
|
||||
{
|
||||
disconnect(session, &LtsSession::LtsSession::signalDoneInitializingSession, this, &LtsLogin::slotLoginDone);
|
||||
|
||||
if (session->getDtc<AssetManagement::DataInterface>(m_asmDtc))
|
||||
{
|
||||
m_asmDtc->enableWorkstationLogout();
|
||||
connect(m_asmDtc.get(), &AssetManagement::Interface::Dtc::workstationLogoutChanged, this,
|
||||
&LtsLogin::slotLogoutShutdown);
|
||||
}
|
||||
else
|
||||
qWarning() << "LtsLogin: no asm dtc, no remote logout/shutdown!";
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "LtsLogin: no admin session for login!!";
|
||||
QMessageBox::critical(nullptr, tr("Login error"), tr("Could not finalize login - abort."));
|
||||
abort();
|
||||
}
|
||||
|
||||
emit signalLoginDone();
|
||||
}
|
||||
|
||||
void LtsLogin::showLogoutInformationDialog(AssetManagement::ShutdownAction action)
|
||||
{
|
||||
LogoutInformationDialog* lid = new LogoutInformationDialog(logoutShutdownTimeout, action, nullptr);
|
||||
connect(lid, &LogoutInformationDialog::accepted, this, [this, action]() {
|
||||
m_shutdownAction = action;
|
||||
m_isInLogoutDialog = false;
|
||||
emit signalLogout();
|
||||
});
|
||||
|
||||
connect(lid, &LogoutInformationDialog::rejected, this, [this]() { m_isInLogoutDialog = false; });
|
||||
|
||||
lid->show();
|
||||
}
|
||||
|
||||
void LtsLogin::slotLogoutShutdown(const AssetManagement::WorkstationLogout& data, DataModification modType)
|
||||
{
|
||||
if (m_isInLogoutDialog)
|
||||
return;
|
||||
|
||||
if (m_asmDtc == nullptr || modType != DataModification::eAdded)
|
||||
return;
|
||||
|
||||
if (!m_asmDtc->isAssetEnabled())
|
||||
m_asmDtc->enableAsset();
|
||||
for (int id : data.ids)
|
||||
{
|
||||
if (QString::fromStdString(m_asmDtc->asset(id).name)
|
||||
.compare(LtsSession::LtsSession::workstationName(), Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
m_isInLogoutDialog = true;
|
||||
showLogoutInformationDialog(data.shutdownAction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LtsSession::LtsSession* LtsLogin::getAdminSession()
|
||||
{
|
||||
return m_loginApp->m_sessionManager->getSession(IDL::PartitionType::Global, 0);
|
||||
}
|
||||
|
||||
void LtsLogin::logoff()
|
||||
{
|
||||
if (m_loginApp == nullptr)
|
||||
{
|
||||
qCritical() << "LtsLogin::logoff: missing login app!";
|
||||
return;
|
||||
}
|
||||
|
||||
LtsSession::LtsSession* datSession = getAdminSession();
|
||||
|
||||
if (!datSession)
|
||||
{
|
||||
qCritical() << "LtsLogin::logoff: no admin session for logout!";
|
||||
abort();
|
||||
}
|
||||
|
||||
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
|
||||
int workstationId = LtsSessionData::LtsSessionData::getInstance()->getWorkstationId();
|
||||
|
||||
LtsSessionData::LtsSessionData::getInstance()->clear();
|
||||
|
||||
std::shared_ptr<OperatorManagement::Interface::Ftc> opmFtc;
|
||||
if (operatorId == -1 || !datSession->getFtc<OperatorManagement::DataInterface>(opmFtc))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
LtsUtils::OperatorSettings* os = LtsUtils::OperatorSettings::getInstance();
|
||||
|
||||
const QByteArray settings = os->exportSettings();
|
||||
|
||||
const auto vec(LtsUtils::convert<std::vector<uint8_t>>(settings));
|
||||
os->clear();
|
||||
opmFtc->operatorGetSetSettingsRequest(OperatorManagement::OperatorGetSetSettingsRequest(operatorId, vec));
|
||||
}
|
||||
catch (const std::runtime_error& err)
|
||||
{
|
||||
qCritical() << "Saving operator settings failed!" << err.what();
|
||||
}
|
||||
|
||||
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> srmIfc;
|
||||
if (datSession->getForeignDataInterface<SituationReplayManagement::DataInterface>(srmIfc))
|
||||
{
|
||||
try
|
||||
{
|
||||
srmIfc->removeReplayPartitionsWorkstation(workstationId);
|
||||
}
|
||||
catch (const std::runtime_error& err)
|
||||
{
|
||||
qCritical() << "Removing reply partitions from this workstation failed!" << err.what();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
srmIfc->removeReplayPartitionsOperator(operatorId);
|
||||
}
|
||||
catch (const std::runtime_error& err)
|
||||
{
|
||||
qCritical() << "Removing reply partitions from this operator failed!" << err.what();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
opmFtc->operatorLogoutRequest(OperatorManagement::OperatorLogoutRequest(operatorId));
|
||||
}
|
||||
catch (const std::runtime_error& err)
|
||||
{
|
||||
qCritical() << "Logout failed!" << err.what();
|
||||
}
|
||||
}
|
||||
|
||||
m_loginApp->deleteLater();
|
||||
m_loginApp = nullptr;
|
||||
|
||||
QString cmd;
|
||||
switch (m_shutdownAction)
|
||||
{
|
||||
case AssetManagement::ShutdownAction::Shutdown:
|
||||
#ifdef LTS_DEBUG
|
||||
cmd = QStringLiteral("xeyes");
|
||||
#else
|
||||
cmd = QStringLiteral("systemctl poweroff");
|
||||
#endif
|
||||
break;
|
||||
case AssetManagement::ShutdownAction::Reboot:
|
||||
#ifdef LTS_DEBUG
|
||||
cmd = QStringLiteral("kcalc");
|
||||
#else
|
||||
cmd = QStringLiteral("systemctl reboot");
|
||||
#endif
|
||||
break;
|
||||
case AssetManagement::ShutdownAction::Logout:
|
||||
case AssetManagement::ShutdownAction::NoAction:
|
||||
emit signalLogoffDone();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cmd.isEmpty())
|
||||
{
|
||||
QProcess::startDetached(cmd);
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace LtsLogin
|
||||
@@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <AssetManagement/asm_data_plugin_interface.h>
|
||||
#include <OperatorManagement/opm_data_plugin_interface.h>
|
||||
#include <SituationReplayManagement/srm_data_plugin_interface.h>
|
||||
#include <QtCore/QObject>
|
||||
#include <ltslogin_export.h>
|
||||
|
||||
namespace LtsPluginManager
|
||||
{
|
||||
class LtsPluginManager;
|
||||
}
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class RequestHelper;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace DeveloperTools
|
||||
{
|
||||
class DevDialog;
|
||||
}
|
||||
|
||||
namespace LtsLogin
|
||||
{
|
||||
|
||||
class LTSLOGIN_EXPORT LtsLogin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LtsLogin();
|
||||
~LtsLogin();
|
||||
|
||||
void login();
|
||||
void logoff();
|
||||
|
||||
void setLoginPlugin(const QString& loginPluginIid)
|
||||
{
|
||||
m_loginPluginIid = loginPluginIid;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class DeveloperTools::DevDialog;
|
||||
|
||||
LtsSession::LtsSession* getAdminSession();
|
||||
void showLogoutInformationDialog(AssetManagement::ShutdownAction action);
|
||||
|
||||
LtsPluginManager::LtsPluginManager* m_loginApp;
|
||||
AssetManagement::ShutdownAction m_shutdownAction;
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> m_asmDtc;
|
||||
QString m_loginPluginIid;
|
||||
bool m_isInLogoutDialog;
|
||||
|
||||
private slots:
|
||||
void slotLoginDone();
|
||||
void slotLogoutShutdown(const AssetManagement::WorkstationLogout& data, DataModification modType);
|
||||
|
||||
signals:
|
||||
void signalLogout();
|
||||
void signalStopBlock();
|
||||
void signalLoginDone();
|
||||
void signalLogoffDone();
|
||||
};
|
||||
|
||||
} // namespace LtsLogin
|
||||
@@ -1,68 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
# Created by Mike Wille, SLSE, 2016-11-01
|
||||
#
|
||||
|
||||
|
||||
# LtsMultiMonitor
|
||||
# Make ${Qt6_Gui} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Gui)
|
||||
set(Qt6_Gui ${Qt6_Gui})
|
||||
else()
|
||||
set(Qt6_Gui "")
|
||||
endif()
|
||||
|
||||
# Make ${Qt6_Widgets} optional
|
||||
if(QT6_GUI_AVAILABLE AND TARGET Qt6::Widgets)
|
||||
set(Qt6_Widgets ${Qt6_Widgets})
|
||||
else()
|
||||
set(Qt6_Widgets "")
|
||||
endif()
|
||||
|
||||
|
||||
SET(LtsMultiMonitor_SRCS
|
||||
lts_multi_monitor_export.h
|
||||
lts_multi_monitor.cpp
|
||||
lts_dummy_widget.cpp
|
||||
lts_screen_container.cpp
|
||||
lts_multi_monitor_selector_base.cpp
|
||||
lts_screen_base.cpp
|
||||
lts_magic_corner.h
|
||||
lts_magic_corner.cpp
|
||||
|
||||
# normal screen
|
||||
lts_multi_monitor_selector_normal.cpp
|
||||
lts_screen_normal.cpp
|
||||
|
||||
# ultra wide screen
|
||||
lts_multi_monitor_selector_wide.cpp
|
||||
lts_screen_wide.cpp
|
||||
)
|
||||
|
||||
# LtsMultiMonitor is needed by AvmShared regardless of BUILD_RTI
|
||||
NGL_ADD_LIBRARY2(WS LtsMultiMonitor SHARED ${LtsMultiMonitor_SRCS})
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(LtsMultiMonitor
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_SOURCE_DIR}/Lts/Common/LtsUtils
|
||||
)
|
||||
|
||||
if(QT6_GUI_AVAILABLE)
|
||||
NGL_TARGET_LINK_LIBRARIES(LtsMultiMonitor
|
||||
PUBLIC
|
||||
Qt6::Core
|
||||
${Qt6_Widgets}
|
||||
PRIVATE
|
||||
${Qt6_Gui}
|
||||
LtsWidgets
|
||||
LtsSessionData
|
||||
LtsUtilsCore
|
||||
LtsUtilsGuiDds
|
||||
)
|
||||
endif()
|
||||
|
||||
NGL_INSTALL_TARGET(LtsMultiMonitor)
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "lts_dummy_widget.h"
|
||||
|
||||
#include <LtsUtilsGui/LtsUtilsGuiDds/dds_vector_to_pixmap.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
|
||||
FullscreenVideoDummyWidget::FullscreenVideoDummyWidget()
|
||||
{
|
||||
setWindowIcon(LtsUtils::iconFromSvg(QStringLiteral(":/style/mobile_video.svg")));
|
||||
setWindowTitle(tr("Fullscreen Video Helper"));
|
||||
}
|
||||
|
||||
void FullscreenVideoDummyWidget::hideVideo()
|
||||
{
|
||||
qWarning() << "FullscreenVideoDummyWidget::hideVideo()";
|
||||
emit signalHideVideo();
|
||||
}
|
||||
|
||||
void FullscreenVideoDummyWidget::showVideo()
|
||||
{
|
||||
emit signalShowVideo();
|
||||
}
|
||||
|
||||
bool FullscreenVideoDummyWidget::event(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::Type::Show)
|
||||
assert(false);
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
} // namespace LtsMultiMonitor
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
#include "ltsmultimonitor_export.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
class QEvent;
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
|
||||
class LTSMULTIMONITOR_EXPORT SecondaryWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SecondaryWidget() = default;
|
||||
virtual ~SecondaryWidget() = default;
|
||||
};
|
||||
|
||||
class LTSMULTIMONITOR_EXPORT FullscreenVideoDummyWidget : public SecondaryWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FullscreenVideoDummyWidget();
|
||||
|
||||
void hideVideo();
|
||||
void showVideo();
|
||||
|
||||
protected:
|
||||
bool event(QEvent*);
|
||||
|
||||
signals:
|
||||
void signalWidgetPlaced(const QRect& globalGeometry);
|
||||
void signalHideVideo();
|
||||
void signalShowVideo();
|
||||
};
|
||||
|
||||
} // namespace LtsMultiMonitor
|
||||
@@ -1,130 +0,0 @@
|
||||
#include "lts_magic_corner.h"
|
||||
|
||||
#include <LtsUtilsGui/LtsUtilsGuiDds/dds_vector_to_pixmap.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtGui/QIcon>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtCore/QTimer>
|
||||
#include <chrono>
|
||||
|
||||
#define SMOL 48
|
||||
#define SWOLE 100
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
LtsMagicCorner::LtsMagicCorner(const QRect& neogeo)
|
||||
: m_neogeo(neogeo), m_shrinkTimer(new QTimer(this)), m_label(new QLabel(this))
|
||||
{
|
||||
|
||||
m_shrinkTimer->setInterval(1500ms);
|
||||
m_shrinkTimer->setSingleShot(true);
|
||||
|
||||
connect(m_shrinkTimer, &QTimer::timeout, this, &LtsMagicCorner::makeSmol);
|
||||
|
||||
makeSmol();
|
||||
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
setMouseTracking(true);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
setWindowFlag(Qt::WindowType::WindowStaysOnTopHint);
|
||||
setWindowFlag(Qt::WindowType::X11BypassWindowManagerHint);
|
||||
activateWindow();
|
||||
|
||||
auto* t = new QTimer(this);
|
||||
connect(t, &QTimer::timeout, this, [this]() {
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
raise();
|
||||
});
|
||||
t->setInterval(750ms);
|
||||
t->start();
|
||||
|
||||
m_label->setMinimumSize(SWOLE, SWOLE);
|
||||
m_label->setMaximumSize(SWOLE, SWOLE);
|
||||
m_label->setGeometry(0, 0, SWOLE, SWOLE);
|
||||
m_label->setText(QStringLiteral("<unknown>"));
|
||||
m_label->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
}
|
||||
|
||||
void LtsMagicCorner::setActiveWidgetType(LtsScreenBase::WidgetType widgetType)
|
||||
{
|
||||
m_activeWidgetType = widgetType;
|
||||
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
|
||||
m_label->setPixmap(m_mainPixmap);
|
||||
else
|
||||
m_label->setPixmap(m_secondaryPixmap);
|
||||
}
|
||||
|
||||
void LtsMagicCorner::setFreezed(bool freezed)
|
||||
{
|
||||
setVisible(!freezed);
|
||||
}
|
||||
|
||||
void LtsMagicCorner::setIcon(const QIcon& icon, LtsScreenBase::WidgetType widgetType)
|
||||
{
|
||||
QPixmap p(LtsUtils::pixmapFromIcon(icon));
|
||||
|
||||
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
|
||||
m_mainPixmap = p;
|
||||
else
|
||||
m_secondaryPixmap = p;
|
||||
|
||||
if (widgetType != m_activeWidgetType)
|
||||
m_label->setPixmap(p);
|
||||
}
|
||||
|
||||
void LtsMagicCorner::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
m_mousePressed = (event->button() == Qt::MouseButton::LeftButton);
|
||||
}
|
||||
|
||||
void LtsMagicCorner::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (!m_mousePressed)
|
||||
return;
|
||||
|
||||
m_mousePressed = false;
|
||||
|
||||
if (event->button() != Qt::MouseButton::LeftButton)
|
||||
return;
|
||||
|
||||
m_shrinkTimer->start();
|
||||
emit toggle();
|
||||
}
|
||||
|
||||
void LtsMagicCorner::makeSmol()
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setGeometry(m_neogeo.x(), m_neogeo.y(), SMOL, SMOL);
|
||||
setMinimumSize(SMOL, SMOL);
|
||||
setMaximumSize(SMOL, SMOL);
|
||||
m_label->hide();
|
||||
}
|
||||
|
||||
void LtsMagicCorner::makeSwole()
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground, false);
|
||||
setAttribute(Qt::WA_NoSystemBackground, false);
|
||||
setGeometry(m_neogeo.x(), m_neogeo.y(), SWOLE, SWOLE);
|
||||
setMinimumSize(SWOLE, SWOLE);
|
||||
setMaximumSize(SWOLE, SWOLE);
|
||||
m_label->show();
|
||||
m_shrinkTimer->start();
|
||||
update();
|
||||
}
|
||||
|
||||
void LtsMagicCorner::mouseMoveEvent(QMouseEvent*)
|
||||
{
|
||||
|
||||
emit signalMakeAllSwole();
|
||||
}
|
||||
|
||||
} // namespace LtsMultiMonitor
|
||||
@@ -1,52 +0,0 @@
|
||||
#pragma once
|
||||
#include "lts_screen_base.h"
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
class QMouseEvent;
|
||||
class QPaintEvent;
|
||||
class QLabel;
|
||||
class QTimer;
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
class LtsMagicCorner : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LtsMagicCorner(const QRect& neogeo);
|
||||
|
||||
void setIcon(const QIcon& icon, LtsScreenBase::WidgetType widgetType);
|
||||
void setActiveWidgetType(LtsScreenBase::WidgetType widgetType);
|
||||
|
||||
void setFreezed(bool freezed);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
|
||||
signals:
|
||||
void toggle();
|
||||
void signalMakeAllSwole();
|
||||
|
||||
private slots:
|
||||
void makeSmol();
|
||||
|
||||
public slots:
|
||||
void makeSwole();
|
||||
|
||||
private:
|
||||
QRect m_neogeo;
|
||||
QTimer* m_shrinkTimer;
|
||||
bool m_mousePressed{false};
|
||||
bool m_freezed = false;
|
||||
QLabel* m_label;
|
||||
QPixmap m_mainPixmap;
|
||||
QPixmap m_secondaryPixmap;
|
||||
LtsScreenBase::WidgetType m_activeWidgetType;
|
||||
};
|
||||
} // namespace LtsMultiMonitor
|
||||
@@ -1,602 +0,0 @@
|
||||
|
||||
|
||||
#include "lts_multi_monitor.h"
|
||||
|
||||
#include "lts_dummy_widget.h"
|
||||
#include "lts_multi_monitor_selector_normal.h"
|
||||
#include "lts_multi_monitor_selector_wide.h"
|
||||
#include "lts_screen_container.h"
|
||||
#include "lts_screen_normal.h"
|
||||
#include "lts_screen_wide.h"
|
||||
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QRect>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <utility>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
|
||||
#endif
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
static LtsMultiMonitor* s_ltsMultiMonitor = nullptr;
|
||||
|
||||
LtsMultiMonitor* LtsMultiMonitor::getInstance()
|
||||
{
|
||||
if (!s_ltsMultiMonitor)
|
||||
{
|
||||
s_ltsMultiMonitor = new LtsMultiMonitor;
|
||||
qAddPostRoutine(&cleanupLtsMultiMonitor);
|
||||
}
|
||||
return s_ltsMultiMonitor;
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::cleanupLtsMultiMonitor()
|
||||
{
|
||||
delete s_ltsMultiMonitor;
|
||||
s_ltsMultiMonitor = nullptr;
|
||||
}
|
||||
|
||||
LtsMultiMonitor::LtsMultiMonitor()
|
||||
: QObject(nullptr), m_mainScreen(nullptr), m_active(false), m_initialized(false), m_skipScreenId(-1),
|
||||
m_subSkipScreenId(-1)
|
||||
|
||||
,
|
||||
m_overlapBaseLayouts(false), m_debugMargins(false)
|
||||
{
|
||||
}
|
||||
|
||||
LtsMultiMonitor::~LtsMultiMonitor()
|
||||
{
|
||||
|
||||
for (auto i = m_screens.begin(); i != m_screens.end(); ++i)
|
||||
{
|
||||
LtsScreenBase* screen = *i;
|
||||
disconnect(screen, &QObject::destroyed, this, &LtsMultiMonitor::screenDied);
|
||||
screen->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::screenDied()
|
||||
{
|
||||
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::init()
|
||||
{
|
||||
|
||||
if (LtsSessionData::LtsSessionData::getInstance()->isTablet())
|
||||
{
|
||||
m_overlapBaseLayouts = true;
|
||||
m_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_initialized || !m_active)
|
||||
return;
|
||||
|
||||
QList<QScreen*> screenList = QGuiApplication::screens();
|
||||
const QScreen& mainScreen = *QGuiApplication::primaryScreen();
|
||||
|
||||
for (auto i = screenList.constBegin(); i != screenList.constEnd(); ++i)
|
||||
{
|
||||
const QScreen& screen = **i;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (LtsScreenBase* ltsScreen : std::as_const(m_screens))
|
||||
{
|
||||
if (ltsScreen->serialNumber() == screen.name())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
int screenId = m_nextScreenId++;
|
||||
|
||||
QRect screenGeo(screen.geometry());
|
||||
|
||||
if (screenId == m_skipScreenId)
|
||||
{
|
||||
if (m_subSkipScreenId == 0)
|
||||
{
|
||||
|
||||
QRect newScreenGeo(screenGeo);
|
||||
|
||||
newScreenGeo.moveLeft(screenGeo.x() + (screenGeo.width() / 2));
|
||||
newScreenGeo.setWidth(screenGeo.width() / 2);
|
||||
|
||||
screenGeo = newScreenGeo;
|
||||
}
|
||||
else if (m_subSkipScreenId == 1)
|
||||
{
|
||||
|
||||
QRect newScreenGeo(screenGeo);
|
||||
|
||||
newScreenGeo.setWidth(screenGeo.width() / 2);
|
||||
|
||||
screenGeo = newScreenGeo;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool isUltraWideView = (screenGeo.width() > 3000);
|
||||
|
||||
LtsScreenBase* newScreen;
|
||||
if (isUltraWideView)
|
||||
{
|
||||
newScreen = new LtsScreenWide(screenGeo, screenId, m_debugMargins, screen.name());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* newScreenNormal = new LtsScreenNormal(std::move(screenGeo), screenId, m_debugMargins, screen.name());
|
||||
newScreen = newScreenNormal;
|
||||
|
||||
connect(newScreenNormal, &LtsScreenNormal::signalMakeAllSwole, this, &LtsMultiMonitor::signalMakeAllSwole);
|
||||
connect(this, &LtsMultiMonitor::signalMakeAllSwole, newScreenNormal, &LtsScreenNormal::signalMakeSwole);
|
||||
}
|
||||
|
||||
connect(newScreen, &QObject::destroyed, this, &LtsMultiMonitor::screenDied);
|
||||
|
||||
if ((&mainScreen) == (&screen))
|
||||
m_mainScreen = newScreen;
|
||||
|
||||
m_screens.append(newScreen);
|
||||
}
|
||||
if (m_screens.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(nullptr, QString(), tr("No screens found - cannot start application."));
|
||||
abort();
|
||||
}
|
||||
|
||||
if (m_mainScreen == nullptr)
|
||||
m_mainScreen = m_screens.first();
|
||||
|
||||
m_initialized = true;
|
||||
emit signalScreenCountChanged(screenCount());
|
||||
}
|
||||
|
||||
int LtsMultiMonitor::screenCount() const
|
||||
{
|
||||
return m_screens.count();
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::cancelAndProcessIfInactive(QWidget* widget) const
|
||||
{
|
||||
if (m_active)
|
||||
return false;
|
||||
|
||||
widget->activateWindow();
|
||||
widget->show();
|
||||
|
||||
place(widget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::place(QWidget* widget)
|
||||
{
|
||||
|
||||
auto* blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget*>(widget);
|
||||
if (blw != nullptr)
|
||||
emit blw->signalSuccessfullyPlaced();
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::putScreen(QWidget* widget, int screenId, int screenPart)
|
||||
{
|
||||
Q_ASSERT(widget != nullptr);
|
||||
if (widget == nullptr)
|
||||
return false;
|
||||
|
||||
if (cancelAndProcessIfInactive(widget))
|
||||
return true;
|
||||
|
||||
init();
|
||||
|
||||
if (overlapBaseLayouts(widget))
|
||||
return true;
|
||||
|
||||
bool isSecondary = isWidgetSecondary(widget);
|
||||
qWarning() << "putScreen: isSecondary" << isSecondary;
|
||||
|
||||
for (LtsScreenBase* screen : std::as_const(m_screens))
|
||||
{
|
||||
if (screen->screenId() != screenId)
|
||||
continue;
|
||||
|
||||
screen->switchToTemp(isSecondary ? LtsScreenBase::WidgetType::SecondaryWidget
|
||||
: LtsScreenBase::WidgetType::MainWidget);
|
||||
|
||||
try
|
||||
{
|
||||
screen->putWidget(widget, screenPart);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
screen->revertSwitch();
|
||||
|
||||
return selectScreen(widget);
|
||||
}
|
||||
|
||||
screen->check();
|
||||
|
||||
place(widget);
|
||||
screen->finalizeSwitch();
|
||||
return true;
|
||||
}
|
||||
|
||||
return selectScreen(widget);
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::putScreenAutomatically(QWidget* widget)
|
||||
{
|
||||
if (widget == nullptr)
|
||||
return false;
|
||||
|
||||
if (cancelAndProcessIfInactive(widget))
|
||||
return true;
|
||||
|
||||
init();
|
||||
|
||||
if (overlapBaseLayouts(widget))
|
||||
return true;
|
||||
|
||||
for (LtsScreenBase* screen : std::as_const(m_screens))
|
||||
{
|
||||
if (screen->screenId() == m_skipScreenId || !screen->isEmpty())
|
||||
continue;
|
||||
|
||||
screen->switchToTemp(LtsScreenBase::WidgetType::SecondaryWidget);
|
||||
|
||||
try
|
||||
{
|
||||
screen->putWidget(widget, 1);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
try
|
||||
{
|
||||
screen->putWidget(widget, 2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
screen->revertSwitch();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
screen->check();
|
||||
place(widget);
|
||||
screen->finalizeSwitch();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::isOverlapBaseLayouts() const
|
||||
{
|
||||
return (m_overlapBaseLayouts);
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::freezeMagicCorner(int screenId)
|
||||
{
|
||||
|
||||
for (auto* screen : std::as_const(m_screens))
|
||||
{
|
||||
|
||||
if (screen->screenId() == screenId)
|
||||
{
|
||||
LtsScreenNormal* normalScreen = qobject_cast<LtsScreenNormal*>(screen);
|
||||
if (normalScreen->child()->hasMainWidget() && normalScreen->child()->hasSecondaryWidget())
|
||||
{
|
||||
normalScreen->hideMagicCorner(true);
|
||||
if (normalScreen->child()->activeWidgetType() == LtsScreenBase::WidgetType::MainWidget)
|
||||
normalScreen->child()->toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LtsMultiMonitor::unfreezeMagicCorner(int screenId)
|
||||
{
|
||||
|
||||
for (auto* screen : std::as_const(m_screens))
|
||||
{
|
||||
|
||||
if (screen->screenId() == screenId)
|
||||
{
|
||||
LtsScreenNormal* normalScreen = qobject_cast<LtsScreenNormal*>(screen);
|
||||
if (normalScreen->child()->hasMainWidget() && normalScreen->child()->hasSecondaryWidget())
|
||||
normalScreen->hideMagicCorner(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::overlapBaseLayouts(QWidget* widget)
|
||||
{
|
||||
if (!isOverlapBaseLayouts())
|
||||
return false;
|
||||
|
||||
Q_ASSERT(qobject_cast<FullscreenVideoDummyWidget*>(widget) == nullptr);
|
||||
if (qobject_cast<FullscreenVideoDummyWidget*>(widget) != nullptr)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
widget->winId();
|
||||
QWindowsWindowFunctions::setHasBorderInFullScreen(widget->windowHandle(), true);
|
||||
#endif
|
||||
|
||||
widget->activateWindow();
|
||||
widget->showFullScreen();
|
||||
|
||||
place(widget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::selectAndSwap(QWidget* widget)
|
||||
{
|
||||
if (!m_active)
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!isOverlapBaseLayouts());
|
||||
if (isOverlapBaseLayouts())
|
||||
return false;
|
||||
|
||||
LtsScreenContainer* oldContainer = nullptr;
|
||||
for (LtsScreenBase* _screen : std::as_const(m_screens))
|
||||
{
|
||||
try
|
||||
{
|
||||
oldContainer = _screen->containerOfWidget(widget);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (oldContainer == nullptr)
|
||||
{
|
||||
|
||||
LtsWidgets::LtsMessageDialog::showMessage(
|
||||
widget,
|
||||
tr("Could not determine screen id for this swap!<br>Swapping not possible, please try again later."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return selectScreen(widget, oldContainer);
|
||||
}
|
||||
|
||||
LtsScreenBase* LtsMultiMonitor::widgetsScreen(QWidget* widget)
|
||||
{
|
||||
for (LtsScreenBase* screen : std::as_const(m_screens))
|
||||
if (screen->hasWidget(widget))
|
||||
return screen;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LtsMultiMonitor::isWidgetSecondary(QWidget* widget)
|
||||
{
|
||||
#ifndef GUEZ_MODE
|
||||
return false;
|
||||
#endif
|
||||
|
||||
auto* blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget*>(widget);
|
||||
auto* secondaryWidget = qobject_cast<SecondaryWidget*>(widget);
|
||||
|
||||
bool isSecondaryWidget = ((blw != nullptr && blw->isSecondaryWidget()) || secondaryWidget != nullptr);
|
||||
|
||||
return isSecondaryWidget;
|
||||
}
|
||||
|
||||
class StupidDeleter
|
||||
{
|
||||
public:
|
||||
explicit StupidDeleter(LtsScreenBase* screen) : m_screen(screen) {}
|
||||
|
||||
~StupidDeleter()
|
||||
{
|
||||
|
||||
if (m_screen != nullptr)
|
||||
{
|
||||
|
||||
m_screen->revertSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
|
||||
m_screen = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
LtsScreenBase* m_screen;
|
||||
};
|
||||
|
||||
bool LtsMultiMonitor::selectScreen(QWidget* widget, LtsScreenContainer* swap, bool putOnMainIfFree,
|
||||
bool ltsScreenNormalOnly, const QVector<QWidget*>& irreplacableWidgets)
|
||||
{
|
||||
Q_ASSERT(widget != nullptr);
|
||||
if (widget == nullptr)
|
||||
return false;
|
||||
|
||||
if (cancelAndProcessIfInactive(widget))
|
||||
return true;
|
||||
|
||||
init();
|
||||
|
||||
if (overlapBaseLayouts(widget))
|
||||
return true;
|
||||
|
||||
bool isSecondary = isWidgetSecondary(widget);
|
||||
|
||||
if (!isSecondary)
|
||||
{
|
||||
bool allEmpty = putOnMainIfFree;
|
||||
for (LtsScreenBase* screen : std::as_const(m_screens))
|
||||
{
|
||||
screen->switchToTemp(LtsScreenBase::WidgetType::MainWidget);
|
||||
bool isEmpty = screen->isEmpty();
|
||||
screen->revertSwitch();
|
||||
|
||||
if (isEmpty)
|
||||
continue;
|
||||
|
||||
allEmpty = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (allEmpty)
|
||||
{
|
||||
|
||||
m_mainScreen->switchToTemp(LtsScreenBase::WidgetType::MainWidget);
|
||||
|
||||
try
|
||||
{
|
||||
m_mainScreen->putWidget(widget);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qWarning() << "failed - reverting";
|
||||
m_mainScreen->revertSwitch();
|
||||
|
||||
Q_ASSERT_X(false, __FUNCTION__,
|
||||
"screen promised to be empty but 'putWidgetSomewhere' method failed regardless");
|
||||
|
||||
auto* blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget*>(widget);
|
||||
if (blw != nullptr)
|
||||
emit blw->signalClose();
|
||||
else
|
||||
widget->deleteLater();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mainScreen->check();
|
||||
place(widget);
|
||||
m_mainScreen->finalizeSwitch();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
auto* selectionProcessWatcher = new QObject;
|
||||
|
||||
bool minOnce = false;
|
||||
|
||||
for (auto i = m_screens.begin(); i != m_screens.end(); ++i)
|
||||
{
|
||||
LtsScreenBase* screen = *i;
|
||||
|
||||
screen->switchToTemp(isSecondary ? LtsScreenBase::WidgetType::SecondaryWidget
|
||||
: LtsScreenBase::WidgetType::MainWidget);
|
||||
|
||||
StupidDeleter _(screen);
|
||||
|
||||
if (screen->isIrreplaceable())
|
||||
{
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
for (QWidget* widget : std::as_const(irreplacableWidgets))
|
||||
{
|
||||
|
||||
if (screen->hasWidget(widget))
|
||||
{
|
||||
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
MultiMonitorSelectorBase* mms;
|
||||
if (qobject_cast<LtsScreenNormal*>(screen) != nullptr)
|
||||
{
|
||||
auto* screenNormal = static_cast<LtsScreenNormal*>(screen);
|
||||
mms = new MultiMonitorSelectorNormal(screenNormal, isSecondary, irreplacableWidgets);
|
||||
}
|
||||
else if (qobject_cast<LtsScreenWide*>(screen) != nullptr && !ltsScreenNormalOnly)
|
||||
{
|
||||
auto* screenWide = static_cast<LtsScreenWide*>(screen);
|
||||
mms = new MultiMonitorSelectorWide(screenWide, nullptr, irreplacableWidgets);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
QPointer<QWidget> widgetPtr(widget);
|
||||
|
||||
connect(widget, &QWidget::destroyed, mms, &MultiMonitorSelectorBase::close);
|
||||
connect(mms, &MultiMonitorSelectorBase::rejected, this, [widgetPtr, swap]() {
|
||||
if (!widgetPtr || swap != nullptr)
|
||||
return;
|
||||
|
||||
auto* blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget*>(widgetPtr.data());
|
||||
if (blw != nullptr)
|
||||
emit blw->signalClose();
|
||||
else
|
||||
widgetPtr->deleteLater();
|
||||
});
|
||||
connect(mms, &MultiMonitorSelectorBase::signalSelected, this, [this, mms, widgetPtr]() {
|
||||
for (LtsScreenBase* screen : std::as_const(m_screens))
|
||||
screen->check();
|
||||
|
||||
if (widgetPtr)
|
||||
place(widgetPtr.data());
|
||||
|
||||
mms->deleteLater();
|
||||
emit signalSelected();
|
||||
});
|
||||
connect(mms, &MultiMonitorSelectorBase::destroyed, selectionProcessWatcher, &QObject::deleteLater);
|
||||
connect(selectionProcessWatcher, &QObject::destroyed, mms, &MultiMonitorSelectorBase::close);
|
||||
|
||||
mms->setSwap(swap);
|
||||
mms->setWidget(widget);
|
||||
mms->show();
|
||||
_.reset();
|
||||
minOnce = true;
|
||||
}
|
||||
|
||||
if (!minOnce)
|
||||
{
|
||||
selectionProcessWatcher->deleteLater();
|
||||
auto* blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget*>(widget);
|
||||
if (blw != nullptr)
|
||||
emit blw->signalClose();
|
||||
else
|
||||
widget->deleteLater();
|
||||
|
||||
LtsWidgets::LtsMessageDialog::showMessage(m_mainScreen->screenDialog(),
|
||||
tr("There are no free screens available to select from."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace LtsMultiMonitor
|
||||
@@ -1,95 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ltsmultimonitor_export.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
#include <memory>
|
||||
|
||||
namespace LtsMultiMonitor
|
||||
{
|
||||
class LtsScreenBase;
|
||||
class MultiMonitorSelectorBase;
|
||||
class LtsScreenContainer;
|
||||
|
||||
class LTSMULTIMONITOR_EXPORT LtsMultiMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static LtsMultiMonitor* getInstance();
|
||||
|
||||
bool selectScreen(QWidget* widget, LtsScreenContainer* swap = nullptr, bool putOnMainIfFree = true,
|
||||
bool ltsScreenNormalOnly = false, const QVector<QWidget*>& irreplacableWidgets = {});
|
||||
bool selectAndSwap(QWidget* widget);
|
||||
|
||||
void setEnableMultiMonitorMode()
|
||||
{
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
void setDebugMultiMonitorMode()
|
||||
{
|
||||
m_debugMargins = true;
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
LtsScreenBase* widgetsScreen(QWidget* widget);
|
||||
|
||||
void freezeMagicCorner(int screenId);
|
||||
void unfreezeMagicCorner(int screenId);
|
||||
|
||||
bool putScreen(QWidget* widget, int screenId, int screenPart);
|
||||
bool putScreenAutomatically(QWidget* widget);
|
||||
static void place(QWidget* widget);
|
||||
|
||||
void setSkipScreen(int screenId, int subScreenId = -1)
|
||||
{
|
||||
m_skipScreenId = screenId;
|
||||
m_subSkipScreenId = subScreenId;
|
||||
}
|
||||
|
||||
LtsScreenBase* mainScreen() const
|
||||
{
|
||||
return m_mainScreen;
|
||||
}
|
||||
|
||||
int screenCount() const;
|
||||
|
||||
private slots:
|
||||
void screenDied();
|
||||
|
||||
private:
|
||||
LtsMultiMonitor();
|
||||
~LtsMultiMonitor();
|
||||
static void cleanupLtsMultiMonitor();
|
||||
void init();
|
||||
bool cancelAndProcessIfInactive(QWidget* widget) const;
|
||||
static bool isWidgetSecondary(QWidget* widget);
|
||||
|
||||
bool overlapBaseLayouts(QWidget* widget);
|
||||
bool isOverlapBaseLayouts() const;
|
||||
|
||||
QVector<LtsScreenBase*> m_screens;
|
||||
int m_nextScreenId{0};
|
||||
LtsScreenBase* m_mainScreen;
|
||||
bool m_active;
|
||||
bool m_initialized;
|
||||
int m_skipScreenId;
|
||||
int m_subSkipScreenId;
|
||||
|
||||
bool m_overlapBaseLayouts;
|
||||
bool m_debugMargins;
|
||||
|
||||
signals:
|
||||
void signalQuitLoop();
|
||||
void signalSelected();
|
||||
void signalScreenCountChanged(int);
|
||||
void signalMakeAllSwole();
|
||||
};
|
||||
|
||||
} // namespace LtsMultiMonitor
|
||||
Loaded 100 of 765 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user