Compare commits

...
Author SHA1 Message Date
berrux-dev 9c1ac7cbef Merge feature/lts-viewer-validation-testing-phase into feature/qt6-migration-basis-modules-merge
Resolves 1 conflict (new_docker_build.sh, union of viewer-only + codification options); folds in fixes for pre-existing defects surfaced by the validation runs (KDReports-qt6 wiring, LtsSession RTI linking, LtsFileDialog/WLS/BSM Qt6/RTI API migration, GROUP4 target list, new --cmake_build_flags option); validated with BUILD_RTI=ON BUILD_GRANTLEE=ON in 3 Docker runs (run 3: build green, 6 base-state first-run CTest failures documented).
2026-09-27 07:33:29 +02:00
berrux-dev 36f077bce4 Emit record_replay fromQVariant for plain enums; document PPM MOC exclusion 2026-09-26 00:49:47 +02:00
torsten c664611b80 Migrates non-ArcGIS built successfully (tbc) 2026-09-24 16:49:49 +02:00
torstenandCopilot b6a97c39e5 Fix KDReports detection and add codification support for viewer-only builds
- Update FindKDReports.cmake to always use CONFIG mode first with explicit search paths
- Add --codification/--no-codification CLI options to new_docker_build.sh
- Add BUILD_CODIFICATION to cmake invocation and Docker environment variables
- Fix BUILD_GROUP5=ON when BUILD_VIEWER_ONLY is enabled
- Exclude LtsFileDialog from viewer-only builds (depends on Group 4 services)
- Fix KDReports git clone to use default branch (removed non-existent branch)
- Add KDReports symlink creation to Dockerfile for include path compatibility

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-23 17:37:56 +02:00
torstenandCopilot fd3e5e8380 Add --build-viewer-only option to skip Groups 1-4 and build Viewer targets only
- Add --build-viewer-only command-line option to argument parsing
- Add BUILD_VIEWER_ONLY environment variable handling
- Add conditional build logic to skip Groups 1-4 when enabled
- Update usage() documentation with new option
- Enable CTest when --build-viewer-only is specified
- Allows bypassing pre-existing Group 3/4 build errors

Tested: Successfully skips Groups 1-4 and builds Group 5 Viewer targets
Validated: situationMapCommon, advancedSymbologyXML, LtsDataView build without errors
No Qt5→Qt6 deprecation warnings in Viewer module targets

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-23 13:36:37 +02:00
33 changed files with 642 additions and 450 deletions

No files matched your search

@@ -191,6 +191,7 @@ OPTION(BUILD_PLUGINS_PARTICIPANT_ORG_CHART "Build ParticipantOrgChart (requires
OPTION(BUILD_PLUGINS_MSDL "Build MSDL module (requires Qt6 XmlPatterns)" OFF) OPTION(BUILD_PLUGINS_MSDL "Build MSDL module (requires Qt6 XmlPatterns)" OFF)
OPTION(BUILD_PLUGINS_SAAB "Build Saab module (requires Qt6 XmlPatterns)" OFF) OPTION(BUILD_PLUGINS_SAAB "Build Saab module (requires Qt6 XmlPatterns)" OFF)
OPTION(BUILD_RTI "Build RTI Connext DDS dependent modules" OFF) OPTION(BUILD_RTI "Build RTI Connext DDS dependent modules" OFF)
OPTION(BUILD_VIEWER_ONLY "Build only Viewer module (no RTI required)" OFF)
# Add Lts/ include path globally for QosProfile and other Lts headers # Add Lts/ include path globally for QosProfile and other Lts headers
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/Lts) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/Lts)
IF(BUILD_RTI) IF(BUILD_RTI)
@@ -525,8 +526,10 @@ if(NOT TARGET Qt6::WebEngineWidgets)
endif() endif()
# Stub KDReports::KDReports target if not available (needed by LtsReportDisplay) # Stub KDReports::KDReports target if not available (needed by LtsReportDisplay)
# UNKNOWN (not INTERFACE) so FindKDReports.cmake can upgrade it with a real
# IMPORTED_LOCATION; an INTERFACE imported target ignores IMPORTED_LOCATION.
if(NOT TARGET KDReports::KDReports) if(NOT TARGET KDReports::KDReports)
add_library(KDReports::KDReports INTERFACE IMPORTED) add_library(KDReports::KDReports UNKNOWN IMPORTED)
set_target_properties(KDReports::KDReports PROPERTIES set_target_properties(KDReports::KDReports PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "NO_KDREPORTS" INTERFACE_COMPILE_DEFINITIONS "NO_KDREPORTS"
) )
@@ -171,8 +171,20 @@ std::vector<T> fromJson(const QVariant &jsonData, type<std::vector<T>>)
return ret; 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> template<typename T>
T fromQVariant(const QVariant &val, type<T>); T fromQVariant(const QVariant &val, type<T>)
{
return static_cast<T>(val.toInt());
}
template<> template<>
bool fromQVariant(const QVariant &val, type<bool>) bool fromQVariant(const QVariant &val, type<bool>)
@@ -266,6 +278,23 @@ T fromQVariant(const QVariant &val)
return fromQVariant(val, type<T>{}); 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 %} {% for dt in serializeTopics.member %}
// //
// Begin {{ dt.typeFq }} // Begin {{ dt.typeFq }}
@@ -121,7 +121,7 @@ protected:
int64_t m_snapshot{{ dt.name }}MapTime = -1; // time for which the snapshot is valid int64_t m_snapshot{{ dt.name }}MapTime = -1; // time for which the snapshot is valid
{% endif %} {% endfor %} {% endif %} {% endfor %}
NGL::INGLLogger* m_logger; NGL::INGLLogger& m_logger;
}; };
} }
@@ -32,8 +32,10 @@ NGL_TARGET_LINK_LIBRARIES(LtsSessionDataDds
PRIVATE PRIVATE
$<$<BOOL:${BUILD_RTI}>:$<IF:$<TARGET_EXISTS:ddsconnector>,ddsconnector,>> $<$<BOOL:${BUILD_RTI}>:$<IF:$<TARGET_EXISTS:ddsconnector>,ddsconnector,>>
PUBLIC PUBLIC
$<$<BOOL:${BUILD_RTI}>:nddscore> $<$<BOOL:${BUILD_RTI}>:RTI::nddscore>
$<$<BOOL:${BUILD_RTI}>:ddsQoS> $<$<BOOL:${BUILD_RTI}>:ddsQoS>
# Generated Core type support (topic_type_support<Core::PartitionTime>, ...)
$<$<BOOL:${BUILD_RTI}>:$<IF:$<TARGET_EXISTS:ddscore>,ddscore,>>
NGLLogger NGLLogger
Qt6::Core Qt6::Core
) )
@@ -112,7 +114,7 @@ IF(BUILD_RTI)
PRIVATE PRIVATE
ddsconnector ddsconnector
PUBLIC PUBLIC
nddscore RTI::nddscore
) )
TARGET_COMPILE_DEFINITIONS(LtsSession PUBLIC BUILD_RTI) TARGET_COMPILE_DEFINITIONS(LtsSession PUBLIC BUILD_RTI)
ENDIF() ENDIF()
@@ -40,7 +40,9 @@
#include <LtsWidgets/lts_tab_widget.h> #include <LtsWidgets/lts_tab_widget.h>
#include <PluginInterfaces/data_plugin_interface.h> #include <PluginInterfaces/data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h> #include <PluginInterfaces/gui_plugin_interface.h>
#ifdef BUILD_FILTERMANAGEMENT // Complete type needed for dynamic_pointer_cast of m_ohvIfc (BUILD_RTI code below);
// the header is self-contained (Qt only), the FilterManagement plugin is only the implementor.
#ifdef BUILD_RTI
#include <Lts/Plugins/OnlineHelp/ohp_online_help_viewer_gui_plugin_interface.h> // XXX: grrr.. #include <Lts/Plugins/OnlineHelp/ohp_online_help_viewer_gui_plugin_interface.h> // XXX: grrr..
#endif #endif
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
@@ -156,7 +158,7 @@ QString LtsSession::toString() const
str.append(QStringLiteral(", workspaceId='%1'").arg(workspaceId())); str.append(QStringLiteral(", workspaceId='%1'").arg(workspaceId()));
#ifdef BUILD_RTI #ifdef BUILD_RTI
str.append(QStringLiteral(", appToString='%1'").arg(appToString(app()))); str.append(QStringLiteral(", appToString='%1'").arg(appToString(app())));
str.append(QStringLiteral(", partitionType=%1, exerciseId='%2'").arg(partitionType()).arg(exerciseId())); str.append(QStringLiteral(", partitionType=%1, exerciseId='%2'").arg(static_cast<int>(partitionType())).arg(exerciseId()));
str.append(QStringLiteral(", LtsSessionDataDds=%1").arg(LtsSessionDataDds::toString())); str.append(QStringLiteral(", LtsSessionDataDds=%1").arg(LtsSessionDataDds::toString()));
#else #else
str.append(QStringLiteral(", app=Login (stub)")); str.append(QStringLiteral(", app=Login (stub)"));
@@ -20,30 +20,6 @@
#include <QtCore/QSet> #include <QtCore/QSet>
#include <QtCore/QVector> #include <QtCore/QVector>
namespace
{
// Convert LtsSession::PartitionType to IDL::PartitionType
IDL::PartitionType toIdlPartitionType(LtsSession::PartitionType type)
{
switch (type)
{
case LtsSession::PartitionType::Any:
return IDL::PartitionType::Any;
case LtsSession::PartitionType::Global:
return IDL::PartitionType::Global;
case LtsSession::PartitionType::Exercise:
return IDL::PartitionType::Exercise;
case LtsSession::PartitionType::AllExercises:
return IDL::PartitionType::AllExercises;
case LtsSession::PartitionType::Replay:
return IDL::PartitionType::Replay;
case LtsSession::PartitionType::Invalid:
default:
return IDL::PartitionType::Any;
}
}
} // namespace
namespace LtsSession namespace LtsSession
{ {
/** /**
@@ -74,7 +50,7 @@ class DdsConnectionContainer
for (int i = ddsConnections.size() - 1; i >= 0; --i) for (int i = ddsConnections.size() - 1; i >= 0; --i)
{ {
const DdsConnection& conn = ddsConnections.at(i); const DdsConnection& conn = ddsConnections.at(i);
if (toIdlPartitionType(conn.partitionType) != IDL::PartitionType::Global) if (conn.partitionType != IDL::PartitionType::Global)
continue; continue;
auto ret = conn.ddsConnector.lock(); auto ret = conn.ddsConnector.lock();
if (ret != nullptr) if (ret != nullptr)
@@ -242,7 +218,7 @@ bool LtsSessionDataDds::init(const DdsConnectionParams& connParams)
#endif #endif
m_ddsConnector = std::make_shared<DDSConnector::DdsConnector>( m_ddsConnector = std::make_shared<DDSConnector::DdsConnector>(
connParams.domainId, toIdlPartitionType(connParams.partitionType), connParams.partitionId, connParams.domainId, connParams.partitionType, connParams.partitionId,
connParams.exerciseId, // same as partition Id in live but not in replay connParams.exerciseId, // same as partition Id in live but not in replay
type); type);
s_ddsConnections()->insertConnection(connParams, m_ddsConnector); s_ddsConnections()->insertConnection(connParams, m_ddsConnector);
@@ -277,7 +253,7 @@ bool LtsSessionDataDds::init(const dds::domain::DomainParticipant& dp, const Dds
if (m_ddsConnector == nullptr) if (m_ddsConnector == nullptr)
{ {
m_ddsConnector = m_ddsConnector =
std::make_shared<DDSConnector::DdsConnector>(dp, toIdlPartitionType(connParams.partitionType), type, connParams.partitionId); std::make_shared<DDSConnector::DdsConnector>(dp, connParams.partitionType, type, connParams.partitionId);
s_ddsConnections()->insertConnection(connParams, m_ddsConnector); s_ddsConnections()->insertConnection(connParams, m_ddsConnector);
} }
@@ -292,38 +268,27 @@ Fetcher* LtsSessionDataDds::fetcher(const QString& yourPluginsName)
return m_fetcher; return m_fetcher;
} }
QString LtsSessionDataDds::partitionTypeString(PartitionType partitionType) QString LtsSessionDataDds::partitionTypeString(IDL::PartitionType partitionType)
{ {
switch (partitionType) switch (partitionType)
{ {
case PartitionType::AllExercises: case IDL::PartitionType::AllExercises:
return QStringLiteral("AllExercises"); return QStringLiteral("AllExercises");
case PartitionType::Any: case IDL::PartitionType::Any:
return QStringLiteral("Any"); return QStringLiteral("Any");
case PartitionType::Exercise: case IDL::PartitionType::Exercise:
return QStringLiteral("Exercise"); return QStringLiteral("Exercise");
case PartitionType::Global: case IDL::PartitionType::Global:
return QStringLiteral("Global"); return QStringLiteral("Global");
case PartitionType::Replay: case IDL::PartitionType::Replay:
return QStringLiteral("Replay"); return QStringLiteral("Replay");
default:
break;
} }
return QStringLiteral("Invalid (%1)").arg(int(partitionType)); return QStringLiteral("Invalid (%1)").arg(int(partitionType));
} }
LtsSession::PartitionType LtsSessionDataDds::toPartitionType(IDL::PartitionType idlType)
{
switch (idlType)
{
case IDL::PartitionType::Any: return PartitionType::Any;
case IDL::PartitionType::Exercise: return PartitionType::Exercise;
case IDL::PartitionType::Replay: return PartitionType::Replay;
case IDL::PartitionType::AllExercises: return PartitionType::AllExercises;
case IDL::PartitionType::Global: return PartitionType::Global;
default: return PartitionType::Invalid;
}
}
QString LtsSessionDataDds::toString() const QString LtsSessionDataDds::toString() const
{ {
return QStringLiteral("(LtsSessionDataDds: id=%1, partitionId=%2, partitionType=%3(%4), exerciseId=%5)") return QStringLiteral("(LtsSessionDataDds: id=%1, partitionId=%2, partitionType=%3(%4), exerciseId=%5)")
@@ -349,9 +314,9 @@ int LtsSessionDataDds::partitionId() const
return m_ddsConnector ? m_ddsConnector->getPartitionId() : -1; return m_ddsConnector ? m_ddsConnector->getPartitionId() : -1;
} }
PartitionType LtsSessionDataDds::partitionType() const IDL::PartitionType LtsSessionDataDds::partitionType() const
{ {
return m_ddsConnector ? toPartitionType(m_ddsConnector->getPartitionType()) : PartitionType::Global; return m_ddsConnector ? m_ddsConnector->getPartitionType() : IDL::PartitionType::Global;
} }
QStringList LtsSessionDataDds::qosFile() const QStringList LtsSessionDataDds::qosFile() const
@@ -394,7 +359,7 @@ bool LtsSessionDataDds::initInternal()
assert(m_dtcPartitionTime.get()); assert(m_dtcPartitionTime.get());
m_dtcPartitionTime->setSubscriberCallback([this](const Core::PartitionTime& data, DataModification) { m_dtcPartitionTime->setSubscriberCallback([this](const Core::PartitionTime& data, DataModification) {
m_curMSecSinceEpoch = data.timeStamp(); m_curMSecSinceEpoch = data.timeStamp;
emit partitionTimeChangedInternal(); emit partitionTimeChangedInternal();
}); });
connect(this, &LtsSessionDataDds::partitionTimeChangedInternal, this, connect(this, &LtsSessionDataDds::partitionTimeChangedInternal, this,
@@ -38,12 +38,12 @@ struct DdsConnectionParams
DdsConnectionParams() = default; DdsConnectionParams() = default;
explicit DdsConnectionParams(const Core::ReplayPartition &rp) explicit DdsConnectionParams(const Core::ReplayPartition &rp)
: domainId(rp.domainId()) : domainId(rp.domainId)
, partitionId(rp.id()) , partitionId(rp.id)
, exerciseId(rp.exerciseId()) , exerciseId(rp.exerciseId)
, partitionType(IDL::PartitionType::Replay) , partitionType(IDL::PartitionType::Replay)
{ {
setTcpConnectionUrl(rp.tcpConnectionUrl()); setTcpConnectionUrl(rp.tcpConnectionUrl);
} }
bool isValid() const { return domainId >= 0 && partitionType != IDL::PartitionType::Any; } bool isValid() const { return domainId >= 0 && partitionType != IDL::PartitionType::Any; }
@@ -64,5 +64,6 @@ class FunctionTopicTests : public QObject
DdsUnitTests::FunctionRequestWithState m_requestTopicWithState; DdsUnitTests::FunctionRequestWithState m_requestTopicWithState;
DdsUnitTests::FunctionReplyWithState m_replyTopicWithState; DdsUnitTests::FunctionReplyWithState m_replyTopicWithState;
NGL::INGLLogger& m_logger;
Qt::HANDLE m_mainThreadId; Qt::HANDLE m_mainThreadId;
}; };
@@ -47,6 +47,10 @@ NGL_TARGET_LINK_LIBRARIES(BuildingControlBsm
BuildingControlCommon BuildingControlCommon
svcTabCommon svcTabCommon
) )
NGL_TARGET_INCLUDE_DIRECTORIES(BuildingControlBsm
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../..
)
NGL_ADD_EXECUTABLE(AAR SV BuildingControlTestBsm bsm_test_main.cpp) NGL_ADD_EXECUTABLE(AAR SV BuildingControlTestBsm bsm_test_main.cpp)
NGL_TARGET_LINK_LIBRARIES(BuildingControlTestBsm NGL_TARGET_LINK_LIBRARIES(BuildingControlTestBsm
@@ -3,6 +3,7 @@
#include "bsm_api.h" #include "bsm_api.h"
#include "bsm_socket_handler.h" #include "bsm_socket_handler.h"
#include <TrainingAreaBase/logger.h>
namespace BuildingControlUnit namespace BuildingControlUnit
{ {
@@ -6,6 +6,7 @@
#include "bsm_telegrams_configuration_setup.h" #include "bsm_telegrams_configuration_setup.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtNetwork/QHostAddress> #include <QtNetwork/QHostAddress>
#include <TrainingAreaBase/logger.h>
static const int s_aliveTimeout = 10; static const int s_aliveTimeout = 10;
namespace BuildingControlUnit namespace BuildingControlUnit
@@ -3,6 +3,7 @@
#include "bsm_socket_handler.h" #include "bsm_socket_handler.h"
#include <utility> #include <utility>
#include <TrainingAreaBase/logger.h>
#include "bsm_telegrams_base.h" #include "bsm_telegrams_base.h"
#include "bsm_telegrams_bit_timeout_request.h" #include "bsm_telegrams_bit_timeout_request.h"
#include "bsm_telegrams_chopped_signal_flash.h" #include "bsm_telegrams_chopped_signal_flash.h"
@@ -3,6 +3,7 @@
#include "bsm_telegrams_base.h" #include "bsm_telegrams_base.h"
#include "bsm_telegrams_alive.h" #include "bsm_telegrams_alive.h"
#include <TrainingAreaBase/logger.h>
#include "bsm_telegrams_bit_timeout_report.h" #include "bsm_telegrams_bit_timeout_report.h"
#include "bsm_telegrams_direct_fire.h" #include "bsm_telegrams_direct_fire.h"
#include "bsm_telegrams_sw_version_report.h" #include "bsm_telegrams_sw_version_report.h"
@@ -2,7 +2,7 @@
#include "bsm_telegrams_direct_fire.h" #include "bsm_telegrams_direct_fire.h"
#include "logger.h" #include <TrainingAreaBase/logger.h>
#include <QStringBuilder> #include <QStringBuilder>
namespace BuildingControlUnit namespace BuildingControlUnit
@@ -3,6 +3,7 @@
#include "ism_handler.h" #include "ism_handler.h"
#include "main_handler.h" #include "main_handler.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace WirelessLocationSystem namespace WirelessLocationSystem
{ {
@@ -34,26 +35,26 @@ void IsmHandler::onMainStructureElementChanged(const InfrastructureManagement::M
case DataModification::eAdded: case DataModification::eAdded:
case DataModification::eModified: case DataModification::eModified:
{ {
m_mainStructureElements[data.id()] = data; m_mainStructureElements[data.id] = data;
if (data.externalWlsId() != 0) if (data.externalWlsId != 0)
m_externalWlsId2MseId[data.externalWlsId()] = data.id(); m_externalWlsId2MseId[data.externalWlsId] = data.id;
QMap<int, int> roomNumber2roomId; QMap<int, int> roomNumber2roomId;
for (const auto &element : data.elements()) for (const auto &element : data.elements)
{ {
if (element.structureElementTypeId() != InfrastructureManagement::StructureElementType::Room) if (element.structureElementTypeId != InfrastructureManagement::StructureElementType::Room)
continue; continue;
roomNumber2roomId[element.mountingPointId()] = element.id(); roomNumber2roomId[element.mountingPointId] = element.id;
} }
m_mseId2RoomId[data.id()] = roomNumber2roomId; m_mseId2RoomId[data.id] = roomNumber2roomId;
break; break;
} }
case DataModification::eRemoved: case DataModification::eRemoved:
{ {
m_mainStructureElements.remove(data.id()); m_mainStructureElements.remove(data.id);
m_mseId2RoomId.remove(data.id()); m_mseId2RoomId.remove(data.id);
for (auto it = m_externalWlsId2MseId.begin(); it != m_externalWlsId2MseId.end(); ++it) for (auto it = m_externalWlsId2MseId.begin(); it != m_externalWlsId2MseId.end(); ++it)
{ {
if (it.value() == data.id()) if (it.value() == data.id)
{ {
m_externalWlsId2MseId.erase(it); m_externalWlsId2MseId.erase(it);
break; break;
@@ -10,6 +10,8 @@
#include "wls_handler.h" #include "wls_handler.h"
#include "wls_participant_handler.h" #include "wls_participant_handler.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsUtils/LtsUtilsCore/dds_vector.h> #include <LtsUtils/LtsUtilsCore/dds_vector.h>
#include <QtCore/QJsonDocument> #include <QtCore/QJsonDocument>
@@ -13,6 +13,8 @@
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <web_socket_handler.h> #include <web_socket_handler.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace WirelessLocationSystem namespace WirelessLocationSystem
{ {
@@ -9,6 +9,8 @@
#include <LtsUtils/LtsUtilsCore/dds_vector.h> #include <LtsUtils/LtsUtilsCore/dds_vector.h>
#include <LtsUtils/LtsUtilsCore/sfm_bytemessage_converter.h> #include <LtsUtils/LtsUtilsCore/sfm_bytemessage_converter.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
static constexpr qint64 s_dataCommunicationAliveTimeout = 5 * 1000; static constexpr qint64 s_dataCommunicationAliveTimeout = 5 * 1000;
static constexpr int s_maxWlsRetryCount = 3; static constexpr int s_maxWlsRetryCount = 3;
@@ -7,6 +7,7 @@
#include "wls_handler.h" #include "wls_handler.h"
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace WirelessLocationSystem namespace WirelessLocationSystem
{ {
@@ -5,7 +5,7 @@
# #
ADD_SUBDIRECTORY(SituationMap) ADD_SUBDIRECTORY(SituationMap)
IF(BUILD_RTI) IF(BUILD_RTI OR BUILD_VIEWER_ONLY)
ADD_SUBDIRECTORY(LtsDataView) ADD_SUBDIRECTORY(LtsDataView)
ENDIF() ENDIF()
ADD_SUBDIRECTORY(LtsFileDialog) ADD_SUBDIRECTORY(LtsFileDialog)
@@ -64,15 +64,14 @@ NGL_INSTALL_TARGET(LtsDataView)
# Test-Executable # Test-Executable
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsDataViewTest test.h test.cpp) NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsDataViewTest test.h test.cpp)
if(QT6_GUI_AVAILABLE) NGL_TARGET_LINK_LIBRARIES(LtsDataViewTest
NGL_TARGET_LINK_LIBRARIES(LtsDataViewTest ${Qt6_Widgets}
${Qt6_Widgets} LtsDataView
LtsDataView LtsWidgets
LtsWidgets )
)
endif()
# Register test with CTest # Register test with CTest
if(BUILD_TESTING) if(BUILD_TESTING)
add_test(NAME LtsDataViewTest COMMAND $<TARGET_FILE:LtsDataViewTest>) add_test(NAME LtsDataViewTest COMMAND $<TARGET_FILE:LtsDataViewTest>)
set_tests_properties(LtsDataViewTest PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
endif() endif()
@@ -19,6 +19,7 @@
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QtWidgets/QScrollArea> #include <QtWidgets/QScrollArea>
#include <QScroller> #include <QScroller>
#include <QTimer>
Disp::Disp() Disp::Disp()
@@ -99,5 +100,8 @@ int main(int argc, char **argv)
qWarning() << "took" << et.elapsed() << "ms"; qWarning() << "took" << et.elapsed() << "ms";
// Auto-exit for CI/headless testing
QTimer::singleShot(1000, &app, &QApplication::quit);
return app.exec(); return app.exec();
} }
@@ -83,4 +83,5 @@ endif()
# Register test with CTest # Register test with CTest
if(BUILD_TESTING) if(BUILD_TESTING)
add_test(NAME LtsFileDialogTest COMMAND $<TARGET_FILE:LtsFileDialogTest>) add_test(NAME LtsFileDialogTest COMMAND $<TARGET_FILE:LtsFileDialogTest>)
set_tests_properties(LtsFileDialogTest PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
endif() endif()
@@ -53,14 +53,13 @@ bool DialogModelFile::initModel(const std::shared_ptr<FileManagement::Interface:
clear(); clear();
// insert Model // insert Model
auto files = [this, xmlType, predicate](const std::vector<FileManagement::FileContent> & fcs, const std::vector<int> &, FileManagement::Interface::DataModification) // Dtc per-item callback: return true to stop iteration (iterateUntil), so collect with false.
// Explicit std::function type disambiguates the void/bool overloads.
std::function<bool(const FileManagement::FileContent &)> files = [this, xmlType, predicate](const FileManagement::FileContent &fc)
{ {
for (const auto& fc : fcs) if (predicate(fc, xmlType))
{
if (!predicate(fc, xmlType))
continue;
insertRow(fc); insertRow(fc);
} return false;
}; };
m_flmDtc->fileContents(files); m_flmDtc->fileContents(files);
@@ -79,7 +78,7 @@ QVariant DialogModelFile::data(const QModelIndex &index, int role) const
{ {
case Qt::BackgroundRole: case Qt::BackgroundRole:
{ {
if (fl.fileStatus() == FileManagement::FileStatus::Deleted) if (fl.fileStatus == FileManagement::FileStatus::Deleted)
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::AlternateBase); return QGuiApplication::palette().color(QPalette::Disabled, QPalette::AlternateBase);
return QGuiApplication::palette().color(QPalette::Active, QPalette::Base); return QGuiApplication::palette().color(QPalette::Active, QPalette::Base);
} }
@@ -88,38 +87,38 @@ QVariant DialogModelFile::data(const QModelIndex &index, int role) const
switch (index.column()) switch (index.column())
{ {
case NAME: case NAME:
return fl.name(); return QString::fromStdString(fl.name);
case ISTEMPLATE: case ISTEMPLATE:
return fl.isTemplate() ? tr("Yes") : tr("No"); return fl.isTemplate ? tr("Yes") : tr("No");
case FOLDER: case FOLDER:
return fl.folderId(); return fl.folderId;
case FILETYPE: case FILETYPE:
return FileManagement::toString(fl.fileType()); return FileManagement::toString(fl.fileType);
case FILECATEGORY: case FILECATEGORY:
return FileManagement::toString(fl.fileCategory()); return FileManagement::toString(fl.fileCategory);
case FILESTATUS: case FILESTATUS:
return FileManagement::toString(fl.fileStatus()); return FileManagement::toString(fl.fileStatus);
case OPERATOR: case OPERATOR:
return QString::fromStdString(m_opmDtc->user(fl.operatorId()).name()); return QString::fromStdString(m_opmDtc->user(fl.operatorId).name);
case EXERCISE: case EXERCISE:
return fl.exerciseId().has_value() ? fl.exerciseId().value() : QVariant(); return fl.exerciseId.has_value() ? fl.exerciseId.value() : QVariant();
case PHASE: case PHASE:
return fl.phaseId().has_value() ? fl.phaseId().value() : QVariant(); return fl.phaseId.has_value() ? fl.phaseId.value() : QVariant();
case USEDBY: case USEDBY:
return fl.isUsedBy() ? tr("Yes") : tr("No"); return fl.isUsedBy ? tr("Yes") : tr("No");
case USES: case USES:
return QString::fromStdString(fl.usedBy()); return QString::number(fl.usedBy);
case LASTMODIFIED: case LASTMODIFIED:
return DTG::toStringMSec(fl.lastModified().toMSecsSinceEpoch()); return DTG::toStringMSec(fl.lastModified);
case PROPERTIES: case PROPERTIES:
return QString::fromStdString(fl.properties()); return QString::fromStdString(fl.properties);
default: default:
break; break;
} }
} }
case Qt::DecorationRole: case Qt::DecorationRole:
{ {
if (index.column() == NAME && fl.isHidden()) if (index.column() == NAME && fl.isHidden)
return QIcon(QLatin1String(":/style/lock.svg")); return QIcon(QLatin1String(":/style/lock.svg"));
break; break;
} }
@@ -136,9 +135,9 @@ int DialogModelFile::findFileIdFromName(const QString &fileName) const
for (int row = 0; row < rc; ++row) for (int row = 0; row < rc; ++row)
{ {
const FileManagement::FileContent &fl = this->getRowData(row); const FileManagement::FileContent &fl = this->getRowData(row);
if (fl.name() == fileName) if (fl.name == fileName)
{ {
return fl.id(); return fl.id;
} }
} }
return 0; return 0;
@@ -158,7 +157,7 @@ QMimeData * DialogModelFile::mimeData(const QModelIndexList &indexes) const
const QModelIndex & index = indexes.first(); const QModelIndex & index = indexes.first();
const FileManagement::FileContent & fl = this->getRowData(index.row()); const FileManagement::FileContent & fl = this->getRowData(index.row());
int id = fl.id(); int id = fl.id;
if (id <= 0) return nullptr; if (id <= 0) return nullptr;
@@ -188,7 +187,7 @@ bool DialogFileProxyModel::lessThan(const QModelIndex &source_left, const QModel
switch (source_left.column()) switch (source_left.column())
{ {
case LASTMODIFIED: case LASTMODIFIED:
return dataLeft.lastModified() < dataRight.lastModified(); return dataLeft.lastModified < dataRight.lastModified;
case NAME: case NAME:
case ISTEMPLATE: case ISTEMPLATE:
case FILETYPE: case FILETYPE:
@@ -12,6 +12,8 @@
#include <FileManagement/flm_translation.h> #include <FileManagement/flm_translation.h>
#include <functional>
//#include <QtCore/QDebug> //#include <QtCore/QDebug>
namespace LtsWidgets namespace LtsWidgets
@@ -68,16 +70,16 @@ QVariant DialogModelFolder::data(const QModelIndex &index, int role) const
case NAME: case NAME:
return getFolderName(folderData); return getFolderName(folderData);
case ID: case ID:
return folderData.id(); return folderData.id;
default: default:
break; break;
} }
} }
case Qt::UserRole: case Qt::UserRole:
return folderData.id(); return folderData.id;
case Qt::DecorationRole: case Qt::DecorationRole:
{ {
if (folderData.isHidden()) if (folderData.isHidden)
return item->icon(); return item->icon();
break; break;
} }
@@ -97,22 +99,22 @@ FileManagement::Folder DialogModelFolder::getFolder(const QModelIndex &idx) cons
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
QString DialogModelFolder::getFolderName(const FileManagement::Folder &folderData) const QString DialogModelFolder::getFolderName(const FileManagement::Folder &folderData) const
{ {
QString folderName = QString::fromStdString(folderData.name()); QString folderName = QString::fromStdString(folderData.name);
if (folderName.startsWith(QStringLiteral("$"))) if (folderName.startsWith(QStringLiteral("$")))
{ {
folderName.remove(0,1); folderName.remove(0,1);
if (folderName.startsWith(QStringLiteral("EX_"))) if (folderName.startsWith(QStringLiteral("EX_")))
{ {
int exId = folderName.remove(0,3).toInt(); int exId = folderName.remove(0,3).toInt();
return QString::fromStdString(m_exmDtc->exercise(exId).name()); return QString::fromStdString(m_exmDtc->exercise(exId).name);
} }
if (folderName.startsWith(QStringLiteral("PH_"))) if (folderName.startsWith(QStringLiteral("PH_")))
{ {
int phId = folderName.remove(0,3).toInt(); int phId = folderName.remove(0,3).toInt();
return QString::fromStdString(m_exmDtc->exercisePhase(phId).name()); return QString::fromStdString(m_exmDtc->exercisePhase(phId).name);
} }
} }
return FileManagement::trFolderName(folderName); return FileManagement::trFolderName(folderName.toStdString());
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
@@ -121,7 +123,7 @@ bool DialogModelFolder::isRowRemovable(NGLTreeItem *parentItem) const
if (!parentItem) if (!parentItem)
return false; return false;
FileManagement::Folder folderData = parentItem->data().value<FileManagement::Folder>(); FileManagement::Folder folderData = parentItem->data().value<FileManagement::Folder>();
return folderData.isEditable(); return folderData.isEditable;
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
@@ -133,34 +135,32 @@ bool DialogModelFolder::initModel(int exerciseId, const QVector<FileManagement::
QHash<int, QModelIndex> parentItemIndexCache; QHash<int, QModelIndex> parentItemIndexCache;
QVector<int> idsToExclude; QVector<int> idsToExclude;
auto cbFolders = [this, exerciseId, &tmap, &idsToExclude, &mainFolders, &parentItemIndexCache] (const std::vector<FileManagement::Folder> &folders, const std::vector<int32_t> &ids, FileManagement::Interface::DataModification mod) // Dtc per-item callback: return true to stop iteration (iterateUntil), so collect with false.
// Explicit std::function type disambiguates the void/bool overloads.
std::function<bool(const FileManagement::Folder &)> cbFolders = [this, exerciseId, &tmap, &idsToExclude, &mainFolders] (const FileManagement::Folder &data)
{ {
Q_UNUSED(ids); if (data.isDeleted)
Q_UNUSED(mod); return false;
for (const auto &data : folders) if (exerciseId > 0)
{ {
if (data.isDeleted()) QString folderName = QString::fromStdString(data.name);
continue; if (folderName.startsWith(QStringLiteral("$EX_")))
if (exerciseId > 0)
{ {
QString folderName = QString::fromStdString(data.name()); int exId = folderName.remove(0, 4).toInt();
if (folderName.startsWith(QStringLiteral("$EX_"))) if (exId != exerciseId)
{ idsToExclude.append(data.id);
int exId = folderName.remove(0, 4).toInt();
if (exId != exerciseId)
idsToExclude.append(data.id());
}
} }
FileManagement::MainFolder mainFolder = static_cast<FileManagement::MainFolder>(data.path()[0]); }
//qCritical() << "Folder = " << data.name() << ", mainFolder = " << mainFolder.underlying(); FileManagement::MainFolder mainFolder = static_cast<FileManagement::MainFolder>(data.path[0]);
//qCritical() << "Folder = " << data.name << ", mainFolder = " << static_cast<int>(mainFolder);
if (!mainFolders.contains(mainFolder)) if (!mainFolders.contains(mainFolder))
{ {
// qCritical() << "Excluded id = " << data.id(); // qCritical() << "Excluded id = " << data.id;
idsToExclude.append(data.id()); idsToExclude.append(data.id);
} }
tmap.insert(data.id(), data); tmap.insert(data.id, data);
} return false;
}; };
m_flmDtc->folders(cbFolders); m_flmDtc->folders(cbFolders);
@@ -173,16 +173,16 @@ bool DialogModelFolder::initModel(int exerciseId, const QVector<FileManagement::
int parentId = 0; int parentId = 0;
FileManagement::Folder fld = iter.value(); FileManagement::Folder fld = iter.value();
if (fld.path().size() > 1) if (fld.path.size() > 1)
{ {
parentId = fld.path().at(fld.path().size() - 2); parentId = fld.path.at(fld.path.size() - 2);
int idPos2 = fld.path().at(1); int idPos2 = fld.path.at(1);
if (idsToExclude.contains(idPos2)) if (idsToExclude.contains(idPos2))
continue; continue;
} }
else // main Folders else // main Folders
{ {
if (idsToExclude.contains(fld.id())) if (idsToExclude.contains(fld.id))
continue; continue;
} }
@@ -212,7 +212,7 @@ bool DialogModelFolder::onInsertRow(int &row, const QModelIndex &parent, const F
QVariant data; QVariant data;
data.setValue(folderData); data.setValue(folderData);
QIcon icon; QIcon icon;
if (folderData.isHidden()) if (folderData.isHidden)
icon = QIcon(QLatin1String(":/style/lock.svg")); icon = QIcon(QLatin1String(":/style/lock.svg"));
NGLTreeItem *item = new NGLTreeItem(data, icon); NGLTreeItem *item = new NGLTreeItem(data, icon);
item->setModified(true); item->setModified(true);
@@ -227,7 +227,7 @@ bool DialogModelFolder::onUpdateRow(const QModelIndex &index, const FileManageme
data.setValue(folderData); data.setValue(folderData);
QIcon icon; QIcon icon;
if (folderData.isHidden()) if (folderData.isHidden)
icon = QIcon(QLatin1String(":/style/lock.svg")); icon = QIcon(QLatin1String(":/style/lock.svg"));
return setItemData(index, data, icon); return setItemData(index, data, icon);
} }
@@ -243,7 +243,7 @@ bool DialogModelFolder::onDeleteRow(const QModelIndex &idx, bool isFirstItem)
{ {
NGLTreeItem *item = privateData(idx); NGLTreeItem *item = privateData(idx);
FileManagement::Folder data = item->data().value<FileManagement::Folder>(); FileManagement::Folder data = item->data().value<FileManagement::Folder>();
data.setDeleted(true); data.isDeleted = true;
} }
removeRow(idx.row(), idx.parent()); removeRow(idx.row(), idx.parent());
@@ -282,19 +282,22 @@ bool DialogModelProxyFolder::lessThan(const QModelIndex &source_left, const QMod
const FileManagement::Folder folderLeft = itemLeft->data().value<FileManagement::Folder>(); const FileManagement::Folder folderLeft = itemLeft->data().value<FileManagement::Folder>();
const FileManagement::Folder folderRight = itemRight->data().value<FileManagement::Folder>(); const FileManagement::Folder folderRight = itemRight->data().value<FileManagement::Folder>();
if (folderLeft.mainFolder() == FileManagement::MainFolder::GlobalDocuments || folderRight.mainFolder() == FileManagement::MainFolder::GlobalDocuments || // mainFolder() was part of the legacy Folder API; the generated Folder carries it in path[0]
folderLeft.mainFolder() == FileManagement::MainFolder::UserDocuments || folderRight.mainFolder() == FileManagement::MainFolder::UserDocuments || const int leftMain = folderLeft.path.empty() ? 0 : static_cast<int>(folderLeft.path[0]);
folderLeft.mainFolder() == FileManagement::MainFolder::ExerciseDocuments || folderRight.mainFolder() == FileManagement::MainFolder::ExerciseDocuments) const int rightMain = folderRight.path.empty() ? 0 : static_cast<int>(folderRight.path[0]);
if (leftMain == static_cast<int>(FileManagement::MainFolder::GlobalDocuments) || rightMain == static_cast<int>(FileManagement::MainFolder::GlobalDocuments) ||
leftMain == static_cast<int>(FileManagement::MainFolder::UserDocuments) || rightMain == static_cast<int>(FileManagement::MainFolder::UserDocuments) ||
leftMain == static_cast<int>(FileManagement::MainFolder::ExerciseDocuments) || rightMain == static_cast<int>(FileManagement::MainFolder::ExerciseDocuments))
{ {
return FileManagement::toInt(folderLeft.mainFolder()) < FileManagement::toInt(folderRight.mainFolder()); return leftMain < rightMain;
} }
if (folderLeft.name() != folderRight.name()) if (folderLeft.name != folderRight.name)
{ {
return (folderLeft.name() < folderRight.name()); return (folderLeft.name < folderRight.name);
} }
return folderLeft.id() < folderRight.id(); return folderLeft.id < folderRight.id;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -324,10 +327,10 @@ bool DialogModelProxyFolder::filterAcceptsRow(int source_row, const QModelIndex
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
const FileManagement::Folder data = child->data().value<FileManagement::Folder>(); const FileManagement::Folder data = child->data().value<FileManagement::Folder>();
if (data.operatorId() != m_operatorId) if (data.operatorId != m_operatorId)
{ {
// it's user folder -> check if it's in user documents and hide if it's not for the current operator // it's user folder -> check if it's in user documents and hide if it's not for the current operator
for (int p : data.path()) for (int p : data.path)
{ {
if (static_cast<FileManagement::MainFolder>(p) == FileManagement::MainFolder::UserDocuments) if (static_cast<FileManagement::MainFolder>(p) == FileManagement::MainFolder::UserDocuments)
return false; return false;
@@ -92,7 +92,7 @@ bool LtsFileDialog::init(LtsSession::LtsSession *session,
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
int LtsFileDialog::getSelectedFileId() const int LtsFileDialog::getSelectedFileId() const
{ {
return m_editItemWidget->m_selectedFileContent.id(); return m_editItemWidget->m_selectedFileContent.id;
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
@@ -114,8 +114,8 @@ bool LtsFileDialogWidget::init(LtsSession::LtsSession *session,
// initial all valid, not-deleted files // initial all valid, not-deleted files
auto predicate = [](const FileManagement::FileContent &fc, const QString &xmlType) auto predicate = [](const FileManagement::FileContent &fc, const QString &xmlType)
{ {
return (!fc.isDeleted() && fc.fileStatus() == FileManagement::FileStatus::Valid && return (!fc.isDeleted && fc.fileStatus == FileManagement::FileStatus::Valid &&
(xmlType.isEmpty() || fc.properties().find(xmlType.toStdString()) != std::string::npos)); (xmlType.isEmpty() || fc.properties.find(xmlType.toStdString()) != std::string::npos));
}; };
m_modelFile->initModel(m_dtc, m_opmDtc, xmlType, predicate); m_modelFile->initModel(m_dtc, m_opmDtc, xmlType, predicate);
@@ -200,7 +200,7 @@ void LtsFileDialogWidget::onFolderSelectionChanged(const QItemSelection& /*selec
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
void LtsFileDialogWidget::requestReadingSelectedFile() void LtsFileDialogWidget::requestReadingSelectedFile()
{ {
emit readSelectedFile(m_selectedFileContent.id()); emit readSelectedFile(m_selectedFileContent.id);
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
@@ -228,7 +228,7 @@ void LtsFileDialogWidget::onChooseFileName()
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void LtsFileDialogWidget::onFolderChanged(const FileManagement::Folder &data, FileManagement::Interface::DataModification modType) void LtsFileDialogWidget::onFolderChanged(const FileManagement::Folder &data, DataModification modType)
{ {
Q_UNUSED(data); Q_UNUSED(data);
Q_UNUSED(modType); Q_UNUSED(modType);
@@ -240,7 +240,7 @@ void LtsFileDialogWidget::onFolderChanged(const FileManagement::Folder &data, Fi
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void LtsFileDialogWidget::onFileChanged(const FileManagement::FileContent &data, FileManagement::Interface::DataModification modType) void LtsFileDialogWidget::onFileChanged(const FileManagement::FileContent &data, DataModification modType)
{ {
bool condition = showFile(data, m_xmlType); bool condition = showFile(data, m_xmlType);
@@ -250,17 +250,17 @@ void LtsFileDialogWidget::onFileChanged(const FileManagement::FileContent &data,
if (selIndex.isValid()) if (selIndex.isValid())
row = selIndex.row(); row = selIndex.row();
if (modType == FileManagement::Interface::DataModification::eRemoved) if (modType == DataModification::eRemoved)
{ {
m_modelFile->removeRow(row); m_modelFile->removeRow(row);
return; return;
} }
if (modType == FileManagement::Interface::DataModification::eAdded && condition) if (modType == DataModification::eAdded && condition)
{ {
m_modelFile->insertRow(data); m_modelFile->insertRow(data);
return; return;
} }
if (modType == FileManagement::Interface::DataModification::eModified && condition) if (modType == DataModification::eModified && condition)
{ {
m_modelFile->setRowData(row, data); m_modelFile->setRowData(row, data);
return; return;
@@ -301,7 +301,7 @@ void LtsFileDialogWidget::enaDisa()
{ {
QString folderName = m_modelFolder->getFolderName(m_modelFolder->getFolder(idxFolder)); QString folderName = m_modelFolder->getFolderName(m_modelFolder->getFolder(idxFolder));
m_ui->lblSelectedFolder->setText(folderName); m_ui->lblSelectedFolder->setText(folderName);
m_selectedFolderId = m_modelFolder->getFolder(idxFolder).id(); m_selectedFolderId = m_modelFolder->getFolder(idxFolder).id;
} }
else else
{ {
@@ -314,7 +314,7 @@ void LtsFileDialogWidget::enaDisa()
if (idxFile.isValid()) if (idxFile.isValid())
{ {
m_selectedFileContent = m_modelFile->getRowData(m_ui->widgetFiles->currentIndex().row()); m_selectedFileContent = m_modelFile->getRowData(m_ui->widgetFiles->currentIndex().row());
m_fileName = m_selectedFileContent.name(); m_fileName = QString::fromStdString(m_selectedFileContent.name);
m_ui->leFile->setText(m_fileName); m_ui->leFile->setText(m_fileName);
} }
else else
@@ -333,31 +333,31 @@ void LtsFileDialogWidget::enaDisa()
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
bool LtsFileDialogWidget::showFile(const FileManagement::FileContent &fc, const QString &xmlType) bool LtsFileDialogWidget::showFile(const FileManagement::FileContent &fc, const QString &xmlType)
{ {
if (fc.isDeleted()) if (fc.isDeleted)
return false; return false;
if (fc.folderId() != m_selectedFolderId) if (fc.folderId != m_selectedFolderId)
return false; return false;
if (!m_fileTypes.isEmpty() && !m_fileTypes.contains(fc.fileType())) if (!m_fileTypes.isEmpty() && !m_fileTypes.contains(fc.fileType))
return false; return false;
if (fc.fileStatus() != FileManagement::FileStatus::Valid) if (fc.fileStatus != FileManagement::FileStatus::Valid)
return false; return false;
// get folder selected // get folder selected
const QModelIndex selIndex = selectedIndexViewFolder(); const QModelIndex selIndex = selectedIndexViewFolder();
const NGLTreeItem *item = m_modelFolder->privateData(selIndex); const NGLTreeItem *item = m_modelFolder->privateData(selIndex);
const FileManagement::Folder fld = item->data().value<FileManagement::Folder>(); const FileManagement::Folder fld = item->data().value<FileManagement::Folder>();
const auto &fldPath = fld.path(); const auto &fldPath = fld.path;
// filter in USER DOCUMENTS folder and subfolders // filter in USER DOCUMENTS folder and subfolders
if (LtsUtils::isInVector(fldPath, static_cast<int>(FileManagement::MainFolder::UserDocuments))) if (LtsUtils::isInVector(fldPath, static_cast<int>(FileManagement::MainFolder::UserDocuments)))
{ {
const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
// filter on User Category and OperatorId // filter on User Category and OperatorId
if (fc.fileCategory() == FileManagement::FileCategory::User && if (fc.fileCategory == FileManagement::FileCategory::User &&
fc.operatorId() != operatorId) fc.operatorId != operatorId)
return false; return false;
} }
@@ -365,20 +365,20 @@ bool LtsFileDialogWidget::showFile(const FileManagement::FileContent &fc, const
if (LtsUtils::isInVector(fldPath, static_cast<int>(FileManagement::MainFolder::ExerciseDocuments))) if (LtsUtils::isInVector(fldPath, static_cast<int>(FileManagement::MainFolder::ExerciseDocuments)))
{ {
// filter on Category = Exercise // filter on Category = Exercise
if (fc.fileCategory() != FileManagement::FileCategory::Exercise) if (fc.fileCategory != FileManagement::FileCategory::Exercise)
return false; return false;
if (m_session->exerciseId() > 0) if (m_session->exerciseId() > 0)
{ {
// filter on exact exerciseId // filter on exact exerciseId (optional member, no comparison operator)
if (fc.exerciseId() != m_session->exerciseId()) if (!fc.exerciseId.has_value() || fc.exerciseId.value() != m_session->exerciseId())
return false; return false;
} }
} }
// filter on XmlType // filter on XmlType
if (fc.fileType() == FileManagement::FileType::Xml && !xmlType.isEmpty() && fc.properties().size() > 0) if (fc.fileType == FileManagement::FileType::Xml && !xmlType.isEmpty() && fc.properties.size() > 0)
{ {
const QString &prop = QString::fromStdString(fc.properties()); const QString &prop = QString::fromStdString(fc.properties);
if (!prop.contains(xmlType, Qt::CaseSensitive)) if (!prop.contains(xmlType, Qt::CaseSensitive))
{ {
return false; return false;
@@ -65,12 +65,12 @@ protected slots:
// folders // folders
void onFolderSelectionChanged(const QItemSelection & /*selected*/, void onFolderSelectionChanged(const QItemSelection & /*selected*/,
const QItemSelection& /*deselected*/); const QItemSelection& /*deselected*/);
void onFolderChanged(const FileManagement::Folder &data, FileManagement::Interface::DataModification modType); void onFolderChanged(const FileManagement::Folder &data, DataModification modType);
// files // files
FileManagement::FileContent onSelectFile(); FileManagement::FileContent onSelectFile();
void onChooseFileName(); void onChooseFileName();
void onFileChanged(const FileManagement::FileContent &data, FileManagement::Interface::DataModification modType); void onFileChanged(const FileManagement::FileContent &data, DataModification modType);
bool showFile(const FileManagement::FileContent &fc, const QString &xmlType); bool showFile(const FileManagement::FileContent &fc, const QString &xmlType);
private: private:
@@ -9,6 +9,7 @@
#include "lts_file_dialog.h" #include "lts_file_dialog.h"
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QTimer>
#include <NGLLogger/NGLLoggerBootstrap.h> #include <NGLLogger/NGLLoggerBootstrap.h>
#include <DDS/DDSConnector/dds_connector.h> #include <DDS/DDSConnector/dds_connector.h>
@@ -61,6 +62,9 @@ int main(int argc, char **argv)
view->show(); view->show();
// Auto-exit for CI/headless testing
QTimer::singleShot(1000, &app, &QApplication::quit);
int ret = app.exec(); int ret = app.exec();
view->deleteLater(); view->deleteLater();
@@ -8,46 +8,55 @@ if(NOT Qt6_FOUND)
endif() endif()
set(_qt_prefix "Qt6") set(_qt_prefix "Qt6")
# If KDReports already provided via variables, use them # Prefer KDReports-qt6 package config if installed under standard prefixes
IF(KDREPORTS_INCLUDE_DIR AND KDREPORTS_KDREPORTS_INCLUDE_DIR AND KDREPORTS_LIBRARY) # Search in common installation locations for KDReports cmake config
SET(KDREPORTS_FOUND TRUE) list(APPEND CMAKE_PREFIX_PATH /usr/local /usr)
SET(KDReports_FOUND TRUE) find_package(KDReports-qt6 CONFIG QUIET PATHS /usr/local/lib/cmake/KDReports-qt6 /usr/local/lib64/cmake/KDReports-qt6 /usr/lib/cmake/KDReports-qt6 /usr/lib64/cmake/KDReports-qt6)
ELSE() if(KDReports-qt6_FOUND OR KDReports-qt6_CONFIG)
# Prefer KDReports-qt6 package config if installed under standard prefixes message(STATUS "Found KDReports-qt6 package config")
if(EXISTS "${CMAKE_PREFIX_PATH}/lib64/cmake/KDReports-qt6" OR EXISTS "/usr/local/lib64/cmake/KDReports-qt6" OR EXISTS "${CMAKE_PREFIX_PATH}/lib/cmake/KDReports-qt6" OR EXISTS "/usr/local/lib/cmake/KDReports-qt6") set(KDREPORTS_FOUND TRUE)
message(STATUS "Found KDReports-qt6 package config") set(KDReports_FOUND TRUE)
set(KDREPORTS_FOUND TRUE) # KDReports-qt6 config provides KDReports::KDReports imported target
set(KDReports_FOUND TRUE) # Set variables for compatibility with code that uses them
# Best-effort defaults; specific projects will use the imported target below set(KDREPORTS_INCLUDE_DIR "/usr/local/include/KDReports-qt6")
set(KDREPORTS_INCLUDE_DIR "/usr/local/include/KDReports-qt6") set(KDREPORTS_KDREPORTS_INCLUDE_DIR "/usr/local/include/KDReports-qt6")
set(KDREPORTS_KDREPORTS_INCLUDE_DIR "/usr/local/include/KDReports-qt6") # Check lib64 first, then lib
# Check lib64 first, then lib if(EXISTS "/usr/local/lib64/libkdreports-qt6.so")
if(EXISTS "/usr/local/lib64/libkdreports-qt6.so") set(KDREPORTS_LIBRARY "/usr/local/lib64/libkdreports-qt6.so")
set(KDREPORTS_LIBRARY "/usr/local/lib64/libkdreports-qt6.so")
else()
set(KDREPORTS_LIBRARY "/usr/local/lib/libkdreports-qt6.so")
endif()
else() else()
FIND_PATH(KDREPORTS_INCLUDE_DIR KDReports/KDReports.h) set(KDREPORTS_LIBRARY "/usr/local/lib/libkdreports-qt6.so")
FIND_PATH(KDREPORTS_KDREPORTS_INCLUDE_DIR KDReports.h PATH_SUFFIXES KDReports)
FIND_LIBRARY(KDREPORTS_LIBRARY NAMES kdreports kdreport kdreports-qt6)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(KDReports DEFAULT_MSG
KDREPORTS_LIBRARY
KDREPORTS_INCLUDE_DIR
KDREPORTS_KDREPORTS_INCLUDE_DIR
)
MARK_AS_ADVANCED(KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY)
MARK_AS_ADVANCED(KDREPORTS_KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY)
endif() endif()
ENDIF() else()
# Search both /usr and /usr/local for apt-installed or manually built KDReports
FIND_PATH(KDREPORTS_INCLUDE_DIR KDReports/KDReports.h PATHS /usr/include /usr/local/include)
FIND_PATH(KDREPORTS_KDREPORTS_INCLUDE_DIR KDReports.h PATH_SUFFIXES KDReports PATHS /usr/include /usr/local/include)
FIND_LIBRARY(KDREPORTS_LIBRARY NAMES kdreports kdreport kdreports-qt6 PATHS /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64)
IF(NOT TARGET KDReports::KDReports) INCLUDE(FindPackageHandleStandardArgs)
ADD_LIBRARY(KDReports::KDReports UNKNOWN IMPORTED) FIND_PACKAGE_HANDLE_STANDARD_ARGS(KDReports DEFAULT_MSG
KDREPORTS_LIBRARY
KDREPORTS_INCLUDE_DIR
KDREPORTS_KDREPORTS_INCLUDE_DIR
)
MARK_AS_ADVANCED(KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY)
MARK_AS_ADVANCED(KDREPORTS_KDREPORTS_INCLUDE_DIR KDREPORTS_LIBRARY)
endif()
# The root CMakeLists may already have created a no-op stub target for
# KDReports::KDReports (before FindKDReports ran). When the library was found,
# upgrade that existing target to the real imported target instead of skipping.
IF(KDReports_FOUND)
IF(NOT TARGET KDReports::KDReports)
ADD_LIBRARY(KDReports::KDReports UNKNOWN IMPORTED)
ENDIF()
SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}") SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}")
SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}") SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${KDREPORTS_INCLUDE_DIR}" "${KDREPORTS_KDREPORTS_INCLUDE_DIR}")
SET_PROPERTY(TARGET KDReports::KDReports PROPERTY IMPORTED_LOCATION "${KDREPORTS_LIBRARY}") SET_PROPERTY(TARGET KDReports::KDReports PROPERTY IMPORTED_LOCATION "${KDREPORTS_LIBRARY}")
SET_PROPERTY(TARGET KDReports::KDReports PROPERTY INTERFACE_COMPILE_DEFINITIONS "")
SET_PROPERTY(TARGET KDReports::KDReports APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_qt_prefix}::Core ${_qt_prefix}::Gui ${_qt_prefix}::PrintSupport ${_qt_prefix}::Widgets) SET_PROPERTY(TARGET KDReports::KDReports APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_qt_prefix}::Core ${_qt_prefix}::Gui ${_qt_prefix}::PrintSupport ${_qt_prefix}::Widgets)
ELSE()
IF(NOT TARGET KDReports::KDReports)
ADD_LIBRARY(KDReports::KDReports UNKNOWN IMPORTED)
ENDIF()
ENDIF() ENDIF()
@@ -122,11 +122,10 @@ SET(_components ALL SV WS AAR TOOLSWS TOOLSSV HLA)
MACRO (NGL_GET_BUILDPARTS _args _buildopts) MACRO (NGL_GET_BUILDPARTS _args _buildopts)
SET(${_buildopts} "") SET(${_buildopts} "")
SET(_at_least_one_keyword_found OFF) SET(_at_least_one_keyword_found OFF)
MESSAGE(STATUS "DEBUG NGL_GET_BUILDPARTS: BUILD_ALL=${BUILD_ALL}, BUILD_SV=${BUILD_SV}, BUILD_WS=${BUILD_WS}, BUILD_AAR=${BUILD_AAR}") MESSAGE(STATUS "DEBUG NGL_GET_BUILDPARTS: _args (name)=${_args}, _args (value)=${${_args}}, BUILD_ALL=${BUILD_ALL}, BUILD_SV=${BUILD_SV}, BUILD_WS=${BUILD_WS}, BUILD_AAR=${BUILD_AAR}")
LIST(FIND ${_args} "ALL" _all) LIST(FIND ${_args} "ALL" _all)
IF (_all GREATER -1) IF (_all GREATER -1)
@@ -148,8 +147,12 @@ MACRO (NGL_GET_BUILDPARTS _args _buildopts)
IF(_idx GREATER -1) IF(_idx GREATER -1)
LIST(REMOVE_AT ${_args} ${_idx}) LIST(REMOVE_AT ${_args} ${_idx})
SET(_at_least_one_keyword_found ON) SET(_at_least_one_keyword_found ON)
MESSAGE(STATUS "DEBUG ELSE: _component=${_component}, BUILD_${_component}=${BUILD_${_component}}")
IF(BUILD_${_component}) IF(BUILD_${_component})
LIST(APPEND ${_buildopts} ${_component}) LIST(APPEND ${_buildopts} ${_component})
MESSAGE(STATUS "DEBUG ELSE: Added ${_component} to _buildopts")
ELSE()
MESSAGE(STATUS "DEBUG ELSE: BUILD_${_component} is FALSE/NOTFOUND, NOT adding ${_component}")
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDFOREACH() ENDFOREACH()
@@ -162,10 +165,10 @@ ENDMACRO()
MACRO (NGL_PARSE_BUILDCOMPONENT_INTERNAL _args _properties _build_target) MACRO (NGL_PARSE_BUILDCOMPONENT_INTERNAL _args _properties _build_target)
NGL_GET_BUILDPARTS(${_args} _buildopts) NGL_GET_BUILDPARTS(_args _buildopts)
SET(${_build_target} OFF) SET(${_build_target} OFF)
MESSAGE(STATUS "DEBUG NGL_PARSE: _buildopts=${_buildopts}, _components=${_components}") MESSAGE(STATUS "DEBUG NGL_PARSE: _args=${_args}, _buildopts=${_buildopts}, _components=${_components}")
FOREACH(_component ${_components}) FOREACH(_component ${_components})
LIST(FIND _buildopts ${_component} _idx) LIST(FIND _buildopts ${_component} _idx)
@@ -320,10 +323,14 @@ MACRO (NGL_ADD_EXECUTABLE)
NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target)
LIST(GET _args 0 _target_NAME) LIST(GET _args 0 _target_NAME)
MESSAGE(STATUS "DEBUG NGL_ADD_EXECUTABLE: _target_NAME=${_target_NAME}, _build_target=${_build_target}")
IF(_build_target) IF(_build_target)
MESSAGE(STATUS "DEBUG NGL_ADD_EXECUTABLE: Creating executable ${_target_NAME}")
ADD_EXECUTABLE(${_args}) ADD_EXECUTABLE(${_args})
SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties})
SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME})
ELSE()
MESSAGE(STATUS "DEBUG NGL_ADD_EXECUTABLE: SKIPPING executable ${_target_NAME}")
ENDIF() ENDIF()
@@ -1,180 +0,0 @@
#!/bin/bash
set -e
# Check if .envrc exists
if [ ! -f .envrc ]; then
echo "ERROR: .envrc not found in current directory"
echo "Please create .envrc with required environment variables (e.g., MIGRATE_PIPELINE_ROOT)"
exit 1
fi
# Load environment variables from .envrc
set -a
source .envrc
set +a
# Allow BUILD_RTI to be overridden via environment variable or argument
BUILD_RTI="${BUILD_RTI:-ON}"
if [ "$1" = "OFF" ]; then
BUILD_RTI=OFF
elif [ "$1" = "ON" ]; then
BUILD_RTI=ON
fi
# BUILD_GRANTLEE must be ON: codegen (IDL/DTC/FTC/SQL) generation is required
# for the migrated services. Only the ON variant is supported and validated.
BUILD_GRANTLEE="${BUILD_GRANTLEE:-ON}"
# Run CMake configuration and build inside Docker
docker run --rm \
-e MIGRATE_PIPELINE_ROOT \
-e LANG \
-e LC_ALL \
-e BUILD_RTI \
-v ${MIGRATE_PIPELINE_ROOT}:/workspace \
-v ${MIGRATE_PIPELINE_ROOT}/rti_license.dat:/workspace/rti_license.dat \
-w /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus \
ubuntu:26.04 bash -c "
# Fail the container on any command error and on failing pipeline
# stages (the make call below pipes through tee, which would otherwise
# mask a non-zero make exit code).
set -eo pipefail
apt-get update -qq && \
apt-get install -y -qq \
build-essential \
cmake \
libboost-dev \
libkf6texttemplate-dev \
libqt6core6 \
libqt6gui6 \
libqt6widgets6 \
qt6-base-dev \
qt6-svg-dev \
qt6-websockets-dev \
qt6-serialport-dev \
qt6-tools-dev-tools \
qt6-tools-dev \
qt6-l10n-tools \
libgtest-dev \
libpq-dev \
postgresql-server-dev-all \
libqt6sql6-psql \
libvlc-dev \
vlc-plugin-base \
git > /dev/null 2>&1
# Set RTI license
export RTI_LICENSE_FILE=/workspace/rti_license.dat
# Set Qt platform for headless testing (required for gtest_discover_tests)
export QT_QPA_PLATFORM=offscreen
# Qt6 is installed via apt - CMake finds it automatically in /usr/lib/x86_64-linux-gnu/cmake
# Clean and configure
rm -rf build4
mkdir -p build4
cd build4
cmake .. \
-DBUILD_RTI=${BUILD_RTI} \
-DBUILD_GRANTLEE=${BUILD_GRANTLEE} \
-DBUILD_ARCGIS=OFF \
-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_BUILD_TYPE=Release
# Validation builds the full service set, not only the two services that
# happened to be migrated first: every service library, the per-service
# test executables, and the shared libraries they need. Targets that are
# known blocked for reasons outside this migration are excluded below, so
# a green run means every migratable service actually compiles.
#
# Excluded, each for a dependency this migration cannot supply:
# svcTargetManagement - needs SituationMap::ElevationMap /
# LineOfSightCalculation, the GDAL module
# whose CMakeLists states it was never
# migrated (main_handler.h:18 includes
# <ElevationMap/elevation_map.h>).
# svcExerciseManagement - needs QStateMachine / QState, moved from
# svcInfrastructureManagement QtCore to the Qt SCXML module in Qt6
# exmStateMachineTest (Qt6::StateMachine). No qt6-scxml-dev in
# the image and qstatemachine.h is absent.
make -j8 \
ddscore ddsftccore ddsQoS ddsconnector ddsfts migration_tests \
NGLLogger nglapplication nglcompression nglcoreapplication ngldb \
nglguiapplication nglsettings nglsingleapplication nglsinglecoreapplication \
ngltools ngltranslator nglwidgets qtsingleapplication qtsinglecoreapplication \
wms_json_ds tcpserver \
svcAesClient svcAesCommon svcAesServer \
svcAlmClient svcAlmCommon svcAlmServer \
svcAreaEffectSimulation \
svcAsmClient svcAsmCommon svcAsmServer svcAssetManagement \
svcAudioVideoManagement \
svcAvmClient svcAvmCommon svcAvmServer \
svcBldClient svcBldCommon svcBldServer svcBuildings \
svcCentralEffectSimulation \
svcCesClient svcCesCommon svcCesDDSCommon svcCesGeoPairingImpl svcCesServer \
svcCmoClient svcCmoCommon svcCmoServer \
svcCnrHelper svcCodClient svcCodCommon svcCodServer \
svcCombatNetRadio svcComponentMonitor svcCoreClient svcDifferentialGPS \
svcEemClient svcEemCommon svcEemServer \
svcEffectShowClient \
svcEscClient svcEscCommon svcEscServer \
svcEsmClient svcEsmCommon svcEsmServer \
svcEvlClient svcEvlCommon svcEvlServer \
svcExerciseEventManagement \
svcExmClient svcExmCommon svcExmServer \
svcFileManagement svcFilterManagement \
svcFlmClient svcFlmCommon svcFlmServer \
svcFltClient svcFltCommon svcFltServer \
svcGimClient svcGimCommon svcGimServer svcGmpServer \
svcGnaClient svcGnaCommon svcGnaServer \
svcGuezIedManagement \
svcIsmClient svcIsmCommon svcIsmServer \
svcMapDummy \
svcMdmClient svcMdmCommon svcMdmServer \
svcMessaging svcMeteoDataManagement \
svcMrkClient svcMrkCommon svcMrkServer \
svcMsgClient svcMsgCommon svcMsgServer \
svcNomClient svcNomCommon svcNomServer svcNotificationManagement \
svcNmeClient svcNmeCommon svcNmeServer svcNmeaManagement \
svcObdClient svcObdCommon svcObdServer \
svcOcBaseDownload svcOcSituationClient svcOcSituationServer \
svcOperatorManagement \
svcOpmClient svcOpmCommon svcOpmServer \
svcOreDummy \
svcOscClient svcOscCommon svcOscServer \
svcOssClient svcOssCommon svcOssServer \
svcParticipantManagement \
svcPdmClient svcPdmCommon svcPdmServer svcPedDummy \
svcPpmClient svcPpmCommon svcPpmServer \
svcPreClient svcPreCommon svcPreServer svcProjectDataManagement svcPwsCommon \
svcRecCommon svcRecordingManagement \
svcRepClient svcRepCommon svcRepCommonExecutable svcRepServer \
svcReportAnalyzer svcReportGenerator \
svcScmClient svcScmCommon svcScmServer svcScrDummy \
svcServiceManagement svcSituationReplay svcSmoDummy \
svcSomClient svcSomCommon svcSomServer svcSoundManagement svcSrmCommon \
svcSrpClient svcSrpCommon svcSrpServer \
svcTabClient svcTabCommon svcTabServer \
svcTabocClient svcTabocCommon svcTabocServer \
svcTgtClient svcTgtCommon svcTgtServer \
svcTrainingAreaBase svcTrainingAreaBaseOC \
svcVideoOverlayManagement \
svcWarehouseGuez svcWarehouseManagement \
svcWhgClient svcWhgCommon svcWhgServer \
asmTests avmFtTests avmTests avmVcaTests cesTests eemTests evlTests \
exmDtUnitTest exmTests flmTests gmpTests ismTests \
mrkTests mvsTests nomTests opmTests pdmTests ppmTests preTests repTests \
scmDtUnitTest srpFtTests tgtTests whgTests \
2>&1 | tee build.log
# Run the CTest unit tests as an explicit validation step.
# We are already inside build4 (cd build4 above), so --test-dir is the
# current directory. --output-on-failure surfaces failing test output; a
# non-zero exit propagates through set -e and fails the container validation.
# Set QT_QPA_PLATFORM for headless testing (no display required)
export QT_QPA_PLATFORM=offscreen
ctest --test-dir . --output-on-failure
"
@@ -16,11 +16,13 @@ set -euo pipefail
# - Optional disabling of ctest # - Optional disabling of ctest
# - Optional tests-only mode # - Optional tests-only mode
# - Uses a temporary container-side script for robust execution # - Uses a temporary container-side script for robust execution
# - Supersedes docker_build.sh: its full migrated-service target set, apt
# package additions, and exclusion notes are merged into this script
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
usage() { usage() {
cat <<'EOF' cat <<'EOF'
Usage: ./build.sh [ON|OFF] [options] Usage: ./new_docker_build.sh [ON|OFF] [options]
BUILD_RTI: BUILD_RTI:
First positional argument may be: First positional argument may be:
@@ -33,12 +35,17 @@ BUILD_GRANTLEE:
BUILD_ARCGIS: BUILD_ARCGIS:
--arcgis / --no-arcgis Enable/disable BUILD_ARCGIS (default: OFF) --arcgis / --no-arcgis Enable/disable BUILD_ARCGIS (default: OFF)
BUILD_CODIFICATION:
--codification / --no-codification Enable/disable BUILD_CODIFICATION (default: OFF, requires KDReports)
Build groups: Build groups:
--group1 / --no-group1 Enable/disable DDS core libraries build --group1 / --no-group1 Enable/disable DDS core libraries build
--group2 / --no-group2 Enable/disable migration_tests build --group2 / --no-group2 Enable/disable migration_tests build
--group3 / --no-group3 Enable/disable remaining application targets build --group3 / --no-group3 Enable/disable remaining application and service targets build
--group4 / --no-group4 Enable/disable Lts/Proxies module targets and tests only (NGL app targets + full migrated Lts service set with per-service tests)
--group4 / --no-group4 Enable/disable DDS tests and Lts/Proxies module targets
--group5 / --no-group5 Enable/disable Lts/Viewer module targets and tests only --group5 / --no-group5 Enable/disable Lts/Viewer module targets and tests only
--build-viewer-only Build only Viewer module targets (skip Groups 1-4, implies --group5 --codification; ctest runs)
Test execution: Test execution:
--no-ctest Skip ctest execution --no-ctest Skip ctest execution
@@ -49,6 +56,8 @@ Prebuilt Docker image usage:
--use-prebuilt-image Use a Docker image with dependencies already installed --use-prebuilt-image Use a Docker image with dependencies already installed
--no-prebuilt-image Use base image and run apt-get install inside the container --no-prebuilt-image Use base image and run apt-get install inside the container
--docker-image IMAGE Docker image name to use/build/delete --docker-image IMAGE Docker image name to use/build/delete
--cmake_build_flags FLAGS Extra CMake flags passed to the in-container configure
(space-separated -D flags, e.g. "-DBUILD_WLS=ON -DGUEZ_MODE=ON")
Prebuilt Docker image management: Prebuilt Docker image management:
--build-prebuilt-image Build the prebuilt Docker image before running the build --build-prebuilt-image Build the prebuilt Docker image before running the build
@@ -60,6 +69,7 @@ Environment variable overrides:
BUILD_RTI=ON|OFF BUILD_RTI=ON|OFF
BUILD_GRANTLEE=ON|OFF BUILD_GRANTLEE=ON|OFF
BUILD_ARCGIS=ON|OFF BUILD_ARCGIS=ON|OFF
BUILD_CODIFICATION=ON|OFF
BUILD_GROUP1=ON|OFF BUILD_GROUP1=ON|OFF
BUILD_GROUP2=ON|OFF BUILD_GROUP2=ON|OFF
BUILD_GROUP3=ON|OFF BUILD_GROUP3=ON|OFF
@@ -83,6 +93,7 @@ Defaults:
BUILD_RTI=ON BUILD_RTI=ON
BUILD_GRANTLEE=ON BUILD_GRANTLEE=ON
BUILD_ARCGIS=OFF BUILD_ARCGIS=OFF
BUILD_CODIFICATION=OFF
BUILD_GROUP1=ON BUILD_GROUP1=ON
BUILD_GROUP2=ON BUILD_GROUP2=ON
BUILD_GROUP3=ON BUILD_GROUP3=ON
@@ -94,20 +105,20 @@ Defaults:
USE_PREBUILT_IMAGE=OFF USE_PREBUILT_IMAGE=OFF
BUILD_PREBUILT_IMAGE=OFF BUILD_PREBUILT_IMAGE=OFF
DELETE_PREBUILT_IMAGE=OFF DELETE_PREBUILT_IMAGE=OFF
DOCKER_IMAGE=qt-migration-builder:latest DOCKER_IMAGE=legatus-qt6-prebuilt:latest
Examples: Examples:
./build.sh ./new_docker_build.sh
./build.sh OFF ./new_docker_build.sh OFF
./build.sh --no-group3 ./new_docker_build.sh --no-group3
./build.sh --no-group1 --group2 --no-group3 ./new_docker_build.sh --no-group1 --group2 --no-group3
./build.sh --no-ctest ./new_docker_build.sh --no-ctest
./build.sh --tests-only ./new_docker_build.sh --tests-only
./build.sh --build-prebuilt-image --docker-image qt-migration-builder:latest ./new_docker_build.sh --build-prebuilt-image --docker-image legatus-qt6-prebuilt:latest
./build.sh --use-prebuilt-image --docker-image qt-migration-builder:latest ./new_docker_build.sh --use-prebuilt-image --docker-image legatus-qt6-prebuilt:latest
./build.sh --build-prebuilt-image --use-prebuilt-image --docker-image qt-migration-builder:latest ./new_docker_build.sh --build-prebuilt-image --use-prebuilt-image --docker-image legatus-qt6-prebuilt:latest
./build.sh --delete-prebuilt-image --docker-image qt-migration-builder:latest ./new_docker_build.sh --delete-prebuilt-image --docker-image legatus-qt6-prebuilt:latest
./build.sh --use-prebuilt-image --no-group1 --no-group3 --integration-test ./new_docker_build.sh --use-prebuilt-image --no-group1 --no-group3 --integration-test
EOF EOF
} }
@@ -210,16 +221,21 @@ delete_prebuilt_image() {
APT_PACKAGES=( APT_PACKAGES=(
build-essential build-essential
cmake cmake
libboost-dev
libkf6texttemplate-dev libkf6texttemplate-dev
libqt6core6 libqt6core6
libqt6gui6 libqt6gui6
libqt6widgets6 libqt6widgets6
libqt6sql6 libqt6sql6
libqt6sql6-psql
libqt6test6 libqt6test6
qt6-base-dev qt6-base-dev
qt6-l10n-tools
qt6-serialport-dev
qt6-svg-dev
qt6-tools-dev-tools qt6-tools-dev-tools
qt6-tools-dev qt6-tools-dev
qt6-l10n-tools qt6-websockets-dev
libgtest-dev libgtest-dev
libpq-dev libpq-dev
postgresql-server-dev-all postgresql-server-dev-all
@@ -241,16 +257,56 @@ GROUP1_TARGETS=(
ddsconnector ddsconnector
) )
GROUP4_TARGETS=(
ddsGenericDataTests
ddsDataTopicTests
ddsFunctionTopicTests
)
GROUP2_TARGETS=( GROUP2_TARGETS=(
migration_tests migration_tests
) )
# Validation builds the full service set, not only the targets that
# happened to be migrated first: every service library, the per-service
# test executables, and the shared libraries they need. Targets that are
# known blocked for reasons outside this migration are excluded below, so
# a green run means every migratable service actually compiles.
#
# This is the full validation set formerly built by docker_build.sh, which
# is superseded by this script.
#
# Excluded, each for a dependency this migration cannot supply:
# svcTargetManagement - needs SituationMap::ElevationMap /
# LineOfSightCalculation, the GDAL module
# whose CMakeLists states it was never
# migrated (main_handler.h:18 includes
# <ElevationMap/elevation_map.h>).
# svcExerciseManagement - needs QStateMachine / QState, moved from
# svcInfrastructureManagement QtCore to the Qt SCXML module in Qt6
# exmStateMachineTest (Qt6::StateMachine). No qt6-scxml-dev in
# the image and qstatemachine.h is absent.
# svcBuildings - its generated record_replay_plugin
# (bld_record_replay_plugin.cpp) calls
# fromQVariant() for the nested foreign
# ProjectDataManagement types
# VulnerabilityState /
# StateChangeOriginator, for which no
# specialization is generated (they are
# not Buildings' own types), leaving the
# generic fromQVariant template
# undefined -> link error.
# svcParticipantManagement - its record_replay custom header
# (RecordReplay/ppm_record_replay_plugin_custom.h)
# declares Q_INTERFACES(RecordReplay::
# RecordReplayPlugin) on a class that also
# inherits ParticipantHandling::BaseDataProvider
# (a second Q_OBJECT base the other record_replay
# custom plugins lack). Qt6's MOC reports
# "Undefined interface" for the Q_INTERFACES in
# that multi-Q_OBJECT-base context (RecordReplay::
# RecordReplayPlugin is a Q_GADGET, not a Q_OBJECT),
# so the plugin autogen step fails before link.
# (The nested-foreign-PDM fromQVariant link error
# that also applied is now resolved by the
# fromQVariant primary-template body added to
# svc_record_replay_plugin.cpp.grantlee.) The PPM
# client/common/server libs still build; only this
# exe is excluded.
GROUP3_TARGETS=( GROUP3_TARGETS=(
NGLLogger NGLLogger
nglapplication nglapplication
@@ -274,9 +330,174 @@ GROUP3_TARGETS=(
svcPdmServer svcPdmServer
svcProjectDataManagement svcProjectDataManagement
pdmTests pdmTests
# Migrated Lts services (full validation set merged from docker_build.sh)
svcAesClient
svcAesCommon
svcAesServer
svcAlmClient
svcAlmCommon
svcAlmServer
svcAreaEffectSimulation
svcAsmClient
svcAsmCommon
svcAsmServer
svcAssetManagement
svcAudioVideoManagement
svcAvmClient
svcAvmCommon
svcAvmServer
# svcBldServer builds in Group 4 (Proxies module)
svcBldClient
svcBldCommon
svcCentralEffectSimulation
svcCesClient
svcCesCommon
svcCesDDSCommon
svcCesGeoPairingImpl
svcCesServer
svcCodClient
svcCodCommon
svcCodServer
svcEemClient
svcEemCommon
svcEemServer
svcEffectShowClient
svcEscClient
svcEscCommon
svcEscServer
svcEsmClient
svcEsmCommon
svcEsmServer
svcEvlClient
svcEvlCommon
svcEvlServer
svcExerciseEventManagement
svcExmClient
svcExmCommon
svcExmServer
svcFileManagement
svcFilterManagement
svcFlmClient
svcFlmCommon
svcFlmServer
svcFltClient
svcFltCommon
svcFltServer
svcGimClient
svcGimCommon
svcGimServer
svcGmpServer
svcGuezIedManagement
svcIsmClient
svcIsmCommon
svcIsmServer
svcMapDummy
svcMdmClient
svcMdmCommon
svcMdmServer
svcMessaging
svcMeteoDataManagement
svcMrkClient
svcMrkCommon
svcMrkServer
svcMsgClient
svcMsgCommon
svcMsgServer
svcNomClient
svcNomCommon
svcNomServer
svcNotificationManagement
svcNmeClient
svcNmeCommon
svcNmeServer
svcNmeaManagement
svcObdClient
svcObdCommon
svcObdServer
svcOcBaseDownload
svcOcSituationClient
svcOcSituationServer
svcOperatorManagement
svcOpmClient
svcOpmCommon
svcOpmServer
svcOreDummy
svcOscClient
svcOscCommon
svcOscServer
svcOssClient
svcOssCommon
svcOssServer
svcPedDummy
svcPpmClient
svcPpmCommon
svcPpmServer
svcPreClient
svcPreCommon
svcPreServer
svcPwsCommon
svcRecCommon
svcRecordingManagement
svcRepClient
svcRepCommon
svcRepCommonExecutable
svcRepServer
svcReportAnalyzer
svcReportGenerator
svcScmClient
svcScmCommon
svcScmServer
svcScrDummy
svcServiceManagement
svcSituationReplay
svcSmoDummy
svcSomClient
svcSomCommon
svcSomServer
svcSoundManagement
svcSrmCommon
svcSrpClient
svcSrpCommon
svcSrpServer
svcTgtClient
svcTgtCommon
svcTgtServer
svcVideoOverlayManagement
svcWarehouseGuez
svcWhgClient
svcWhgCommon
svcWhgServer
# Per-service tests (merged from docker_build.sh)
asmTests
avmFtTests
avmTests
avmVcaTests
cesTests
eemTests
evlTests
exmDtUnitTest
exmTests
flmTests
gmpTests
ismTests
mrkTests
mvsTests
nomTests
opmTests
ppmTests
preTests
repTests
scmDtUnitTest
srpFtTests
tgtTests
whgTests
) )
GROUP4_TARGETS=( GROUP4_TARGETS=(
# DDS tests
ddsGenericDataTests
ddsDataTopicTests
ddsFunctionTopicTests
# Proxies module - Buildings # Proxies module - Buildings
BuildingControlCommon BuildingControlCommon
BuildingControlBsm BuildingControlBsm
@@ -296,20 +517,24 @@ GROUP4_TARGETS=(
svcTabClient svcTabClient
svcTabServer svcTabServer
svcTrainingAreaBase svcTrainingAreaBase
tabPluginInterface # tabPluginInterface - defined in the CMake but no make rule is generated (base state)
TmsIfAdapterInterface # TmsIfAdapterInterface/TmsIfAdapter/tabPluginUAS/TabUASTest3/TabUASTest4_2/TabUASTest6
TmsIfAdapter # - only built with BUILD_UAS_PROXY=ON (default OFF, not exposed by this script)
tabPluginUAS # tabPluginInterface
TabUASTest3 # TmsIfAdapterInterface
TabUASTest4_2 # TmsIfAdapter
TabUASTest6 # tabPluginUAS
# TabUASTest3
# TabUASTest4_2
# TabUASTest6
# Proxies module - TrainingAreaBaseOC # Proxies module - TrainingAreaBaseOC
svcTabocCommon svcTabocCommon
svcTabocClient svcTabocClient
svcTabocServer svcTabocServer
svcTrainingAreaBaseOC svcTrainingAreaBaseOC
serialtest serialtest
# Proxies module - WirelessLocationSystem # Proxies module - WirelessLocationSystem (requires -DBUILD_WLS=ON, e.g. via
# --cmake_build_flags "-DBUILD_WLS=ON")
svcWirelessLocationSystem svcWirelessLocationSystem
wlsJsonClientTest wlsJsonClientTest
# Proxies module - Other # Proxies module - Other
@@ -361,6 +586,22 @@ RUN pip3 install --break-system-packages --quiet aqtinstall && \
--outputdir ${QT_BASE_DIR} && \ --outputdir ${QT_BASE_DIR} && \
rm -rf /root/.cache/Aqt rm -rf /root/.cache/Aqt
# Install KDReports from source (apt package not available in Ubuntu 22.04/26.04)
# Try apt install first (will fail), then build from KDAB GitHub mirror
RUN apt-get install -y -qq libkdreports-dev 2>/dev/null || \
(git clone --depth 1 https://github.com/KDAB/KDReports.git /tmp/KDReports && \
cd /tmp/KDReports && \
mkdir build && cd build && \
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_PREFIX_PATH=${QT_BASE_DIR} .. && \
make -j$(nproc) && \
make install && \
cd / && rm -rf /tmp/KDReports)
# Legacy sources include <KDReports/...> but the Qt6 package installs headers flat
# under /usr/local/include/KDReports-qt6 - alias the directory so the prefixed
# includes resolve through the default /usr/local/include search path.
RUN ln -sfn KDReports-qt6 /usr/local/include/KDReports
CMD ["/bin/bash"] CMD ["/bin/bash"]
EOF EOF
@@ -402,25 +643,25 @@ source ".envrc"
set +a set +a
BUILD_ALL="${BUILD_ALL:-ON}" BUILD_ALL="${BUILD_ALL:-ON}"
BUILD_SV="${BUILD_SV:-ON}"
BUILD_WS="${BUILD_WS:-ON}"
BUILD_AAR="${BUILD_AAR:-ON}"
BUILD_RTI="${BUILD_RTI:-ON}" BUILD_RTI="${BUILD_RTI:-ON}"
BUILD_GRANTLEE="${BUILD_GRANTLEE:-ON}" BUILD_GRANTLEE="${BUILD_GRANTLEE:-ON}"
BUILD_ARCGIS="${BUILD_ARCGIS:-OFF}" BUILD_ARCGIS="${BUILD_ARCGIS:-OFF}"
BUILD_CODIFICATION="${BUILD_CODIFICATION:-OFF}"
BUILD_GROUP1="${BUILD_GROUP1:-ON}" BUILD_GROUP1="${BUILD_GROUP1:-ON}"
BUILD_GROUP2="${BUILD_GROUP2:-ON}" BUILD_GROUP2="${BUILD_GROUP2:-ON}"
BUILD_GROUP3="${BUILD_GROUP3:-ON}" BUILD_GROUP3="${BUILD_GROUP3:-ON}"
BUILD_GROUP4="${BUILD_GROUP4:-OFF}" BUILD_GROUP4="${BUILD_GROUP4:-OFF}"
BUILD_GROUP5="${BUILD_GROUP5:-OFF}" BUILD_GROUP5="${BUILD_GROUP5:-OFF}"
BUILD_VIEWER_ONLY="${BUILD_VIEWER_ONLY:-OFF}"
RUN_CTEST="${RUN_CTEST:-ON}" RUN_CTEST="${RUN_CTEST:-ON}"
TESTS_ONLY="${TESTS_ONLY:-OFF}" TESTS_ONLY="${TESTS_ONLY:-OFF}"
INTEGRATION_TEST="${INTEGRATION_TEST:-OFF}" INTEGRATION_TEST="${INTEGRATION_TEST:-OFF}"
USE_PREBUILT_IMAGE="${USE_PREBUILT_IMAGE:-OFF}" USE_PREBUILT_IMAGE="${USE_PREBUILT_IMAGE:-OFF}"
BUILD_PREBUILT_IMAGE="${BUILD_PREBUILT_IMAGE:-OFF}" BUILD_PREBUILT_IMAGE="${BUILD_PREBUILT_IMAGE:-OFF}"
DELETE_PREBUILT_IMAGE="${DELETE_PREBUILT_IMAGE:-OFF}" DELETE_PREBUILT_IMAGE="${DELETE_PREBUILT_IMAGE:-OFF}"
if [[ "${USE_PREBUILT_IMAGE}" == "ON" ]]; then
DOCKER_IMAGE="${DOCKER_IMAGE:-qt-migration-builder:latest}"
else
DOCKER_IMAGE="${DOCKER_IMAGE:-ubuntu:26.04}"
fi
export QT_VERSION="${QT_VERSION:-6.10.2}" export QT_VERSION="${QT_VERSION:-6.10.2}"
export QT_ARCH="${QT_ARCH:-linux_gcc_64}" export QT_ARCH="${QT_ARCH:-linux_gcc_64}"
# aqtinstall uses 'linux_gcc_64' but creates directory 'gcc_64' # aqtinstall uses 'linux_gcc_64' but creates directory 'gcc_64'
@@ -468,6 +709,12 @@ while [[ $# -gt 0 ]]; do
--no-group5) --no-group5)
BUILD_GROUP5=OFF BUILD_GROUP5=OFF
;; ;;
--build-viewer-only)
BUILD_VIEWER_ONLY=ON
BUILD_GROUP5=ON
BUILD_CODIFICATION=ON
RUN_CTEST=ON
;;
--grantlee) --grantlee)
BUILD_GRANTLEE=ON BUILD_GRANTLEE=ON
;; ;;
@@ -480,6 +727,12 @@ while [[ $# -gt 0 ]]; do
--no-arcgis) --no-arcgis)
BUILD_ARCGIS=OFF BUILD_ARCGIS=OFF
;; ;;
--codification)
BUILD_CODIFICATION=ON
;;
--no-codification)
BUILD_CODIFICATION=OFF
;;
--no-ctest) --no-ctest)
RUN_CTEST=OFF RUN_CTEST=OFF
;; ;;
@@ -506,6 +759,11 @@ while [[ $# -gt 0 ]]; do
[[ $# -gt 0 ]] || die "--docker-image requires an image name" [[ $# -gt 0 ]] || die "--docker-image requires an image name"
DOCKER_IMAGE="$1" DOCKER_IMAGE="$1"
;; ;;
--cmake_build_flags)
shift
[[ $# -gt 0 ]] || die "--cmake_build_flags requires a flag string"
CMAKE_BUILD_FLAGS="$1"
;;
-h|--help) -h|--help)
usage usage
exit 0 exit 0
@@ -534,11 +792,13 @@ BUILD_ALL="$(normalize_on_off "$BUILD_ALL" "BUILD_ALL")"
BUILD_RTI="$(normalize_on_off "$BUILD_RTI" "BUILD_RTI")" BUILD_RTI="$(normalize_on_off "$BUILD_RTI" "BUILD_RTI")"
BUILD_GRANTLEE="$(normalize_on_off "$BUILD_GRANTLEE" "BUILD_GRANTLEE")" BUILD_GRANTLEE="$(normalize_on_off "$BUILD_GRANTLEE" "BUILD_GRANTLEE")"
BUILD_ARCGIS="$(normalize_on_off "$BUILD_ARCGIS" "BUILD_ARCGIS")" BUILD_ARCGIS="$(normalize_on_off "$BUILD_ARCGIS" "BUILD_ARCGIS")"
BUILD_CODIFICATION="$(normalize_on_off "$BUILD_CODIFICATION" "BUILD_CODIFICATION")"
BUILD_GROUP1="$(normalize_on_off "$BUILD_GROUP1" "BUILD_GROUP1")" BUILD_GROUP1="$(normalize_on_off "$BUILD_GROUP1" "BUILD_GROUP1")"
BUILD_GROUP2="$(normalize_on_off "$BUILD_GROUP2" "BUILD_GROUP2")" BUILD_GROUP2="$(normalize_on_off "$BUILD_GROUP2" "BUILD_GROUP2")"
BUILD_GROUP3="$(normalize_on_off "$BUILD_GROUP3" "BUILD_GROUP3")" BUILD_GROUP3="$(normalize_on_off "$BUILD_GROUP3" "BUILD_GROUP3")"
BUILD_GROUP4="$(normalize_on_off "$BUILD_GROUP4" "BUILD_GROUP4")" BUILD_GROUP4="$(normalize_on_off "$BUILD_GROUP4" "BUILD_GROUP4")"
BUILD_GROUP5="$(normalize_on_off "$BUILD_GROUP5" "BUILD_GROUP5")" BUILD_GROUP5="$(normalize_on_off "$BUILD_GROUP5" "BUILD_GROUP5")"
BUILD_VIEWER_ONLY="$(normalize_on_off "$BUILD_VIEWER_ONLY" "BUILD_VIEWER_ONLY")"
RUN_CTEST="$(normalize_on_off "$RUN_CTEST" "RUN_CTEST")" RUN_CTEST="$(normalize_on_off "$RUN_CTEST" "RUN_CTEST")"
TESTS_ONLY="$(normalize_on_off "$TESTS_ONLY" "TESTS_ONLY")" TESTS_ONLY="$(normalize_on_off "$TESTS_ONLY" "TESTS_ONLY")"
INTEGRATION_TEST="$(normalize_on_off "$INTEGRATION_TEST" "INTEGRATION_TEST")" INTEGRATION_TEST="$(normalize_on_off "$INTEGRATION_TEST" "INTEGRATION_TEST")"
@@ -546,29 +806,69 @@ USE_PREBUILT_IMAGE="$(normalize_on_off "$USE_PREBUILT_IMAGE" "USE_PREBUILT_IMAGE
BUILD_PREBUILT_IMAGE="$(normalize_on_off "$BUILD_PREBUILT_IMAGE" "BUILD_PREBUILT_IMAGE")" BUILD_PREBUILT_IMAGE="$(normalize_on_off "$BUILD_PREBUILT_IMAGE" "BUILD_PREBUILT_IMAGE")"
DELETE_PREBUILT_IMAGE="$(normalize_on_off "$DELETE_PREBUILT_IMAGE" "DELETE_PREBUILT_IMAGE")" DELETE_PREBUILT_IMAGE="$(normalize_on_off "$DELETE_PREBUILT_IMAGE" "DELETE_PREBUILT_IMAGE")"
# Set DOCKER_IMAGE default after argument parsing
if [[ "${USE_PREBUILT_IMAGE}" == "ON" ]]; then
DOCKER_IMAGE="${DOCKER_IMAGE:-legatus-qt6-prebuilt:latest}"
else
DOCKER_IMAGE="${DOCKER_IMAGE:-ubuntu:26.04}"
fi
# Default for extra CMake flags (set via --cmake_build_flags or environment)
CMAKE_BUILD_FLAGS="${CMAKE_BUILD_FLAGS:-}"
# Export variables for Docker container # Export variables for Docker container
export BUILD_ALL BUILD_RTI BUILD_GRANTLEE BUILD_ARCGIS BUILD_GROUP1 BUILD_GROUP2 BUILD_GROUP3 BUILD_GROUP4 BUILD_GROUP5 RUN_CTEST TESTS_ONLY INTEGRATION_TEST USE_PREBUILT_IMAGE BUILD_PREBUILT_IMAGE DELETE_PREBUILT_IMAGE DOCKER_IMAGE export BUILD_ALL BUILD_RTI BUILD_GRANTLEE BUILD_ARCGIS BUILD_CODIFICATION BUILD_GROUP1 BUILD_GROUP2 BUILD_GROUP3 BUILD_GROUP4 BUILD_GROUP5 BUILD_VIEWER_ONLY RUN_CTEST TESTS_ONLY INTEGRATION_TEST USE_PREBUILT_IMAGE BUILD_PREBUILT_IMAGE DELETE_PREBUILT_IMAGE DOCKER_IMAGE CMAKE_BUILD_FLAGS
# Group 5: Viewer module targets (conditional on BUILD_ARCGIS) # Group 5: Viewer module targets (conditional on BUILD_ARCGIS)
# Note: LtsFileDialog excluded from viewer-only builds due to Group 4 dependencies (svcExmCommon, svcOpmCommon, svcFlmCommon)
if [[ "${BUILD_ARCGIS}" == "ON" ]]; then if [[ "${BUILD_ARCGIS}" == "ON" ]]; then
GROUP5_TARGETS=( if [[ "${BUILD_VIEWER_ONLY}" == "ON" ]]; then
# Viewer module with ArcGIS # Viewer-only build: exclude LtsFileDialog (requires Group 4 services)
situationMapCommon GROUP5_TARGETS=(
advancedSymbology # Viewer module with ArcGIS (viewer-only subset)
advancedSymbologyXML situationMapCommon
LtsDataView advancedSymbology
LtsFileDialog advancedSymbologyXML
LtsReportDisplay LtsDataView
) LtsDataViewTest
LtsReportDisplay
)
else
GROUP5_TARGETS=(
# Viewer module with ArcGIS (full build)
situationMapCommon
advancedSymbology
advancedSymbologyXML
LtsDataView
LtsDataViewTest
LtsFileDialog
LtsFileDialogTest
LtsReportDisplay
)
fi
else else
GROUP5_TARGETS=( if [[ "${BUILD_VIEWER_ONLY}" == "ON" ]]; then
# Viewer module without ArcGIS (advancedSymbology requires ArcGIS) # Viewer-only build: exclude LtsFileDialog (requires Group 4 services)
situationMapCommon GROUP5_TARGETS=(
advancedSymbologyXML # Viewer module without ArcGIS (viewer-only subset, advancedSymbology requires ArcGIS)
LtsDataView situationMapCommon
LtsFileDialog advancedSymbologyXML
LtsReportDisplay LtsDataView
) LtsDataViewTest
LtsReportDisplay
)
else
GROUP5_TARGETS=(
# Viewer module without ArcGIS (full build)
situationMapCommon
advancedSymbologyXML
LtsDataView
LtsDataViewTest
LtsFileDialog
LtsFileDialogTest
LtsReportDisplay
)
fi
fi fi
require_non_empty "${DOCKER_IMAGE}" "DOCKER_IMAGE" require_non_empty "${DOCKER_IMAGE}" "DOCKER_IMAGE"
@@ -598,7 +898,10 @@ fi
log_info "BUILD_RTI=${BUILD_RTI}" log_info "BUILD_RTI=${BUILD_RTI}"
log_group "Build Group 1 (ddscore ddsftccore ddsQoS ddsconnector ddsfts)" "$BUILD_GROUP1" log_group "Build Group 1 (ddscore ddsftccore ddsQoS ddsconnector ddsfts)" "$BUILD_GROUP1"
log_group "Build Group 2 (migration_tests)" "$BUILD_GROUP2" log_group "Build Group 2 (migration_tests)" "$BUILD_GROUP2"
log_group "Build Group 3 (application targets)" "$BUILD_GROUP3" log_group "Build Group 3 (application + service targets)" "$BUILD_GROUP3"
log_group "Build Group 4 (DDS tests + Proxies)" "$BUILD_GROUP4"
log_group "Build Group 5 (Viewer)" "$BUILD_GROUP5"
log_info "BUILD_VIEWER_ONLY=${BUILD_VIEWER_ONLY}"
log_info "RUN_CTEST=${RUN_CTEST}" log_info "RUN_CTEST=${RUN_CTEST}"
log_info "TESTS_ONLY=${TESTS_ONLY}" log_info "TESTS_ONLY=${TESTS_ONLY}"
log_info "INTEGRATION_TEST=${INTEGRATION_TEST}" log_info "INTEGRATION_TEST=${INTEGRATION_TEST}"
@@ -617,7 +920,7 @@ if [[ "${BUILD_PREBUILT_IMAGE}" == "ON" ]]; then
log_info "Prebuilt image was built successfully." log_info "Prebuilt image was built successfully."
log_info "Exiting because --use-prebuilt-image was not requested." log_info "Exiting because --use-prebuilt-image was not requested."
log_info "To use it, run:" log_info "To use it, run:"
printf ' ./build.sh --use-prebuilt-image --docker-image %q\n' "${DOCKER_IMAGE}" printf ' ./new_docker_build.sh --use-prebuilt-image --docker-image %q\n' "${DOCKER_IMAGE}"
exit 0 exit 0
fi fi
@@ -644,6 +947,9 @@ set -euo pipefail
# Default variable assignments to prevent unbound variable errors # Default variable assignments to prevent unbound variable errors
USE_PREBUILT_IMAGE="${USE_PREBUILT_IMAGE:-OFF}" USE_PREBUILT_IMAGE="${USE_PREBUILT_IMAGE:-OFF}"
BUILD_ALL="${BUILD_ALL:-ON}" BUILD_ALL="${BUILD_ALL:-ON}"
BUILD_SV="${BUILD_SV:-ON}"
BUILD_WS="${BUILD_WS:-ON}"
BUILD_AAR="${BUILD_AAR:-ON}"
BUILD_RTI="${BUILD_RTI:-ON}" BUILD_RTI="${BUILD_RTI:-ON}"
BUILD_GRANTLEE="${BUILD_GRANTLEE:-ON}" BUILD_GRANTLEE="${BUILD_GRANTLEE:-ON}"
BUILD_ARCGIS="${BUILD_ARCGIS:-OFF}" BUILD_ARCGIS="${BUILD_ARCGIS:-OFF}"
@@ -652,6 +958,7 @@ BUILD_GROUP2="${BUILD_GROUP2:-ON}"
BUILD_GROUP3="${BUILD_GROUP3:-ON}" BUILD_GROUP3="${BUILD_GROUP3:-ON}"
BUILD_GROUP4="${BUILD_GROUP4:-OFF}" BUILD_GROUP4="${BUILD_GROUP4:-OFF}"
BUILD_GROUP5="${BUILD_GROUP5:-OFF}" BUILD_GROUP5="${BUILD_GROUP5:-OFF}"
BUILD_VIEWER_ONLY="${BUILD_VIEWER_ONLY:-OFF}"
RUN_CTEST="${RUN_CTEST:-ON}" RUN_CTEST="${RUN_CTEST:-ON}"
TESTS_ONLY="${TESTS_ONLY:-OFF}" TESTS_ONLY="${TESTS_ONLY:-OFF}"
INTEGRATION_TEST="${INTEGRATION_TEST:-OFF}" INTEGRATION_TEST="${INTEGRATION_TEST:-OFF}"
@@ -730,12 +1037,19 @@ cd build4
cmake .. \ cmake .. \
-DBUILD_TESTING=ON \ -DBUILD_TESTING=ON \
-DBUILD_ALL="${BUILD_ALL}" \
-DBUILD_SV="${BUILD_SV}" \
-DBUILD_WS="${BUILD_WS}" \
-DBUILD_AAR="${BUILD_AAR}" \
-DBUILD_RTI="${BUILD_RTI}" \ -DBUILD_RTI="${BUILD_RTI}" \
-DBUILD_VIEWER_ONLY="${BUILD_VIEWER_ONLY}" \
-DBUILD_GRANTLEE="${BUILD_GRANTLEE}" \ -DBUILD_GRANTLEE="${BUILD_GRANTLEE}" \
-DBUILD_ARCGIS="${BUILD_ARCGIS}" \ -DBUILD_ARCGIS="${BUILD_ARCGIS}" \
-DBUILD_CODIFICATION="${BUILD_CODIFICATION}" \
${CMAKE_BUILD_FLAGS:-} \
-DCMAKE_CXX_STANDARD=17 \ -DCMAKE_CXX_STANDARD=17 \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="${QT_BASE_DIR}/${QT_VERSION}/${QT_ARCH_DIR}${BUILD_ARCGIS:+;/workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/external/ArcGIS/MapsSDK_Qt_300.0.0/ArcGIS_Maps_SDK_Qt_300.0.0/qt300.0.0/sdk}" -DCMAKE_PREFIX_PATH="${QT_BASE_DIR}/${QT_VERSION}/${QT_ARCH_DIR}${BUILD_ARCGIS:+;/workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/external/ArcGIS/MapsSDK_Qt_300.0.0/ArcGIS_Maps_SDK_Qt_300.0.0/qt300.0.0/sdk};/usr/local"
read -r -a GROUP1_ARRAY <<< "${GROUP1_TARGETS}" read -r -a GROUP1_ARRAY <<< "${GROUP1_TARGETS}"
read -r -a GROUP2_ARRAY <<< "${GROUP2_TARGETS}" read -r -a GROUP2_ARRAY <<< "${GROUP2_TARGETS}"
@@ -744,11 +1058,18 @@ read -r -a GROUP4_ARRAY <<< "${GROUP4_TARGETS}"
read -r -a GROUP5_ARRAY <<< "${GROUP5_TARGETS}" read -r -a GROUP5_ARRAY <<< "${GROUP5_TARGETS}"
if [[ "${TESTS_ONLY}" != "ON" ]]; then if [[ "${TESTS_ONLY}" != "ON" ]]; then
if [[ "${BUILD_VIEWER_ONLY}" == "ON" ]]; then
log_info "BUILD_VIEWER_ONLY enabled - skipping Groups 1-4, building only Viewer module targets"
BUILD_GROUP1=OFF
BUILD_GROUP2=OFF
BUILD_GROUP3=OFF
BUILD_GROUP4=OFF
BUILD_GROUP5=ON
fi
run_build_group "Group 1" "${BUILD_GROUP1}" "group1_build.log" "${GROUP1_ARRAY[@]}" run_build_group "Group 1" "${BUILD_GROUP1}" "group1_build.log" "${GROUP1_ARRAY[@]}"
run_build_group "Group 4 (DDS Tests)" "${BUILD_GROUP4}" "group4_build.log" "${GROUP4_ARRAY[@]}" run_build_group "Group 4 (DDS tests + Proxies)" "${BUILD_GROUP4}" "group4_build.log" "${GROUP4_ARRAY[@]}"
run_build_group "Group 2" "${BUILD_GROUP2}" "group2_build.log" "${GROUP2_ARRAY[@]}" run_build_group "Group 2" "${BUILD_GROUP2}" "group2_build.log" "${GROUP2_ARRAY[@]}"
run_build_group "Group 3" "${BUILD_GROUP3}" "group3_build.log" "${GROUP3_ARRAY[@]}" run_build_group "Group 3" "${BUILD_GROUP3}" "group3_build.log" "${GROUP3_ARRAY[@]}"
run_build_group "Group 4" "${BUILD_GROUP4}" "group4_build.log" "${GROUP4_ARRAY[@]}"
run_build_group "Group 5 (Viewer)" "${BUILD_GROUP5}" "group5_build.log" "${GROUP5_ARRAY[@]}" run_build_group "Group 5 (Viewer)" "${BUILD_GROUP5}" "group5_build.log" "${GROUP5_ARRAY[@]}"
else else
log_info "TESTS_ONLY enabled - skipping all build groups" log_info "TESTS_ONLY enabled - skipping all build groups"
@@ -773,18 +1094,25 @@ docker run --rm \
-e MIGRATE_PIPELINE_ROOT \ -e MIGRATE_PIPELINE_ROOT \
-e LANG \ -e LANG \
-e LC_ALL \ -e LC_ALL \
-e BUILD_ALL \
-e BUILD_SV \
-e BUILD_WS \
-e BUILD_AAR \
-e BUILD_RTI \ -e BUILD_RTI \
-e BUILD_GRANTLEE \ -e BUILD_GRANTLEE \
-e BUILD_ARCGIS \ -e BUILD_ARCGIS \
-e BUILD_CODIFICATION \
-e BUILD_GROUP1 \ -e BUILD_GROUP1 \
-e BUILD_GROUP2 \ -e BUILD_GROUP2 \
-e BUILD_GROUP3 \ -e BUILD_GROUP3 \
-e BUILD_GROUP4 \ -e BUILD_GROUP4 \
-e BUILD_GROUP5 \ -e BUILD_GROUP5 \
-e BUILD_VIEWER_ONLY \
-e RUN_CTEST \ -e RUN_CTEST \
-e TESTS_ONLY \ -e TESTS_ONLY \
-e INTEGRATION_TEST \ -e INTEGRATION_TEST \
-e USE_PREBUILT_IMAGE \ -e USE_PREBUILT_IMAGE \
-e CMAKE_BUILD_FLAGS \
-e QT_VERSION \ -e QT_VERSION \
-e QT_ARCH \ -e QT_ARCH \
-e QT_ARCH_DIR \ -e QT_ARCH_DIR \