diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 000000000..cc9cd36f1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,289 @@ +# +# Haupt CMakeLists.txt für das Projekt TDS +# +# $Id$ +# $HeadURL$ +# $Author$ +# +# Setzen von CMAKE_INSTALL_PREFIX auf "/shd/CTC" falls nicht über Kommandozeile angegeben +# + +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) +IF(POLICY CMP0069) + CMAKE_POLICY(SET CMP0069 NEW) # cmake >= 3.9.0 - INTERPROCEDURAL_OPTIMIZATION behavior +ENDIF() +IF(POLICY CMP0071) + CMAKE_POLICY(SET CMP0071 NEW) # cmake >= 3.10.0 - automatically process generated sources with AUTOMOC +ENDIF() +IF(POLICY CMP0072) + CMAKE_POLICY(SET CMP0072 NEW) # cmake >= 3.11.0 - prefer libOpenGL.so over legacy libGL.so +ENDIF() + + +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/shd/CTC" CACHE STRING "Install path prefix, prepended onto install directories." FORCE) +ENDIF() +# +# # Setzen von CMAKE_BUILD_TYPE auf "Debug" falls nicht über Kommandozeile angegeben +# +IF(NOT DEFINED CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) +ENDIF() +ADD_DEFINITIONS(-DEXPORT_BDV_TOPIC_AS_JSON) +SET(_ver "1.2.0") +IF(DEFINED LTS_VERSION_MAJOR AND DEFINED LTS_VERSION_MINOR AND DEFINED LTS_VERSION_PATCH) + SET(_ver "${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}") +ENDIF() +PROJECT(LTS VERSION ${_ver}) +MESSAGE(STATUS "LTS Version: ${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}") +SET(LTS_VERSION_DATE "01.01.2018" CACHE STRING "The date when this software was compiled") +ADD_DEFINITIONS(-DLTS_VERSION_MAJOR=\"${LTS_VERSION_MAJOR}\") +ADD_DEFINITIONS(-DLTS_VERSION_MINOR=\"${LTS_VERSION_MINOR}\") +ADD_DEFINITIONS(-DLTS_VERSION_PATCH=\"${LTS_VERSION_PATCH}\") +ADD_DEFINITIONS(-DLTS_VERSION_DATE=\"${LTS_VERSION_DATE}\") +IF(JENKINS_BUILD_NUMBER) + ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"${JENKINS_BUILD_NUMBER}\") +ELSE() + ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"unknown\") +ENDIF() + +ADD_DEFINITIONS(-DAPP6C) +SET(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_CXX_STANDARD 14) +SET(CMAKE_CXX_STANDARD_REQUIRED 14) +SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +SET(CMAKE_CXX_VISIBILITY_PRESET hidden) +SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + +IF(CMAKE_VERSION VERSION_GREATER 3.15.9) + OPTION(USE_UNITY_BUILDS "Use Unity builds to speed up compilation (cmake 3.16 or newer required!)" OFF) + IF (USE_UNITY_BUILDS) + SET(CMAKE_UNITY_BUILD ON) + SET(CMAKE_UNITY_BUILD_BATCH_SIZE 40) + ENDIF() +ENDIF() + +IF(WIN32) + SET(EXTERNAL_LIBRARY_DIR "C:/Development/Projekte/SituationMap/ExtFw" CACHE STRING "Library dir with all external dependencies") + LIST(APPEND CMAKE_PREFIX_PATH "${EXTERNAL_LIBRARY_DIR}") + LIST(APPEND CMAKE_PROGRAM_PATH "${EXTERNAL_LIBRARY_DIR}/bin;${EXTERNAL_LIBRARY_DIR}/dev-utils/bin") +ENDIF() + +ENABLE_TESTING() +INCLUDE(CTest) +CONFIGURE_FILE(CTestCustom.ctest ${CMAKE_BINARY_DIR}/CTestCustom.ctest COPYONLY) +CONFIGURE_FILE(lts-cc.conf ${CMAKE_BINARY_DIR}/lts-cc.conf.distrib COPYONLY) + +SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +IF(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +ELSE(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) +ENDIF() + +# +# Disallow in-source build +# +INCLUDE(MacroEnsureOutOfSourceBuild) + +macro_ensure_out_of_source_build("In-Source build nicht erlaubt!") + +# +# Qt ist wichtig - zuerst suchen +# +SET(CMAKE_AUTOMOC TRUE) +SET(QT_USE_IMPORTED_TARGETS TRUE) +FIND_PACKAGE(Qt5 5.9.0 COMPONENTS Concurrent Core Gui Location LinguistTools + Network OpenGL PrintSupport Sensors Multimedia + Sql Svg SerialPort Test UiTools WebSockets + WebEngineCore WebEngineWidgets Widgets + Xml XmlPatterns + REQUIRED) + +MESSAGE(STATUS "Qt version is ${Qt5Core_VERSION}") +ADD_DEFINITIONS(-DQT_USE_QSTRINGBUILDER) +ADD_DEFINITIONS(-DQT_NO_CAST_TO_ASCII) +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_ASCII) +ADD_DEFINITIONS(-DQT_NO_URL_CAST_FROM_STRING) +ADD_DEFINITIONS(-DQT_DEPRECATED_WARNINGS) +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_BYTEARRAY) +#ADD_DEFINITIONS(-DQT_NO_DEPRECATED) +ADD_DEFINITIONS(-DQT_DISABLE_DEPRECATED_BEFORE=0x050900) +ADD_DEFINITIONS(-DQT_NO_FOREACH) +IF(NOT WIN32) + ADD_DEFINITIONS(-DQT_STRICT_ITERATORS) +ENDIF() + +# +# Ein paar NGL-spezifische Macros +# +INCLUDE(NGLMacros) + +# +# Projektspezifische Einstellungen? +# +NGL_INSTALL(SV AAR WS FILES lts-cc.conf DESTINATION . RENAME lts-cc.conf.distrib) + +OPTION(ETS_MODE "Build for ETS (No B-Contamination etc)" OFF) +IF(ETS_MODE) + ADD_DEFINITIONS(-DETS_MODE) +ENDIF() +OPTION(TABLET_MODE "Build for TABLET " OFF) +IF(TABLET_MODE) + ADD_DEFINITIONS(-DTABLET_MODE) +ENDIF() + +OPTION(GUEZ_MODE "Build for GUEZ " ON) +IF(GUEZ_MODE) + ADD_DEFINITIONS(-DGUEZ_MODE) +ENDIF() + +# +# Doxygen +# +INCLUDE(DoxygenMacros) +IF(NOT DOXYGEN_OUT_DIR) + SET(DOXYGEN_OUT_DIR ${CMAKE_BINARY_DIR}/doxygen) +ENDIF() +ADD_DOXYGEN_TARGET(TDS ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile + ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg + ${DOXYGEN_OUT_DIR}) + +IF(NOT DOXYGEN_OUT_DIR_2025) + SET(DOXYGEN_OUT_DIR_2025 ${CMAKE_BINARY_DIR}/doxygen2025) +ENDIF() +ADD_DOXYGEN_TARGET(TDS2025 ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile2025.in ${CMAKE_BINARY_DIR}/Doxyfile + ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg + ${DOXYGEN_OUT_DIR_2025}) + +# +# Compilerflags +# +IF(WIN32) + ADD_DEFINITIONS(-DWIN32 -D_USE_MATH_DEFINES -D_WIN32_WINNT=0x0501 -DUNICODE) +ELSE() + ADD_DEFINITIONS(-D_LINUX) +ENDIF() + +IF(MSVC) + # C4250: 'class1' : inherits 'class2::member' via dominance + # C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' + # C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow) + # C4496: 'function': was declared deprecated + # C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data + ADD_DEFINITIONS(-wd4250 + -wd4251 + -wd4290 + -wd4496 + -wd4267 + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_NONSTDC_NO_DEPRECATE + -D_SCL_SECURE_NO_WARNINGS + -D_WINSOCK_DEPRECATED_NO_WARNINGS + /bigobj + ) + # komplette Programmoptimierung + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + # .pdb - Datei nicht gefunden + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4099") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4099") + # min() und max() nicht als Macros + ADD_DEFINITIONS(-DNOMINMAX) + SET(CMAKE_MSVCIDE_RUN_PATH "" CACHE PATH "Run path to use when starting programs from MSVC") +ENDIF() + +IF(UNIX) + # Alle Warnungen aktivieren + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wmissing-include-dirs") + # disable + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overloaded-virtual") + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0) + MESSAGE(FATAL_ERROR "gcc 4.8 or higher is required to build TDS: ${CMAKE_CXX_COMPILER_VERSION}") + ENDIF() + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9.99) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=const") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-types") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-methods") +# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override") + ENDIF() + ENDIF() +ENDIF() + +OPTION(USE_IPO "Use interprocedural optimizations (cmake 3.9 or higher required)" OFF) +IF (USE_IPO AND CMAKE_VERSION VERSION_GREATER 3.8.9) + INCLUDE(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + IF(result) + SET(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + ELSE() + MESSAGE(WARNING "IPO is not supported: ${output}") + ENDIF() +ENDIF() + +OPTION(USE_ASAN "Use Address Sanitizer (current Clang only)" OFF) +IF (USE_ASAN) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + MESSAGE(STATUS "enable Address Sanitizer with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1") + ELSE() + MESSAGE(STATUS "Address Sanitizer only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + ENDIF() +ENDIF(USE_ASAN) + +OPTION(USE_UBSAN "Use UndefinedBehavior Sanitizer (current Clang only)" OFF) +IF (USE_UBSAN) + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + ELSE() + MESSAGE(STATUS "UndefinedBehavior only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})") + ENDIF() +ENDIF(USE_UBSAN) + +OPTION(BUILD_RPM "Build a RPM - install script in scripts subdir" OFF) + +IF(BUILD_RPM) + ADD_SUBDIRECTORY(scripts) +ELSE() + ADD_DEFINITIONS(-DLTS_DEBUG) +ENDIF() + +IF (NOT DEFINED _pname) + IF(GUEZ_MODE) + SET (_pname "guez") + ADD_DEFINITIONS(-DPROJECTBUILD="guez") + MESSAGE(STATUS "NO ProjectName givin! BUT GUEZ_MODE set PROJECTBUILD to guez") + ELSE() + MESSAGE(WARNING "NO ProjectName givin! Can't install coresponding lts-cc.conf! and PROJECTBUILD is empty") + ADD_DEFINITIONS(-DPROJECTBUILD="") + ENDIF() +ELSE() + MESSAGE(STATUS "ProjectName givin! PROJECTBUILD is ${_pname} ") + ADD_DEFINITIONS(-DPROJECTBUILD=\"${_pname}\") +ENDIF() + + +# +# DDS benoetigt zwingend RTI +# +FIND_PACKAGE(RTI REQUIRED) + +ADD_SUBDIRECTORY(TetraIF) +ADD_SUBDIRECTORY(Z/src) +ADD_SUBDIRECTORY(Lts) +# at last, to make sure we get all targets in NGL_TS_TARGETS property +ADD_SUBDIRECTORY(translations) +#----------------------------------------------------------------------------------------------------- + + +OPTION(BUILD_QAV "Build script for local QAV analysis" OFF) +IF (BUILD_QAV) + ADD_SUBDIRECTORY(qav) +ENDIF() diff --git a/TetraIF/CMakeLists.txt b/TetraIF/CMakeLists.txt new file mode 100644 index 000000000..2440f9340 --- /dev/null +++ b/TetraIF/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +ADD_SUBDIRECTORY(CoPrtCnv) +ADD_SUBDIRECTORY(LogView) +ADD_SUBDIRECTORY(PrtCnv) diff --git a/TetraIF/CoPrtCnv/CMakeLists.txt b/TetraIF/CoPrtCnv/CMakeLists.txt new file mode 100644 index 000000000..b90771809 --- /dev/null +++ b/TetraIF/CoPrtCnv/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(my_SRCS + tetra_telegram_ids.h + CoPrtCnvCentralTelegram.cpp + CoPrtCnvCentralTelegram.hpp + CoPrtCnvHexDumpHelper.cpp + CoPrtCnvHexDumpHelper.hpp + CoPrtCnvInjectionHeader.hpp + CoPrtCnvLogHeader.hpp + CoPrtCnvRadioTelegram.cpp + CoPrtCnvRadioTelegram.hpp + CoPrtCnvTelegramConverter.hpp + CoPrtCnvTelegramConverterNewIcd.cpp +) + +NGL_ADD_LIBRARY2(AAR SV CoPrtCnv SHARED ${my_SRCS} ${my_HDRS}) +NGL_TARGET_LINK_LIBRARIES(CoPrtCnv + PUBLIC + NGLLogger + tabTelegrams +) +NGL_TARGET_INCLUDE_DIRECTORIES(CoPrtCnv + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) diff --git a/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp new file mode 100644 index 000000000..535211703 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.cpp @@ -0,0 +1,82 @@ + + + +#include "CoPrtCnvCentralTelegram.hpp" +#include + +namespace N_CoPrtCnv +{ + +void CoPrtCnvCentralTelegram::setData(const QByteArray &data) +{ + m_data = data; + m_json = QJsonObject(); +} + +QByteArray CoPrtCnvCentralTelegram::data() +{ + ensureByteArray(); + return m_data; +} + +QJsonObject CoPrtCnvCentralTelegram::json() +{ + ensureJson(); + return m_json; +} + +QJsonObject CoPrtCnvCentralTelegram::jsonData() +{ + return json()[QStringLiteral("data")].toObject(); +} + +TrainingAreaBase::TetraIcd::TelegramId CoPrtCnvCentralTelegram::telegramId() +{ + if (m_telegramId != TrainingAreaBase::TetraIcd::UNKNOWN) + return m_telegramId; + + ensureJson(); + m_telegramId = static_cast(m_json[QStringLiteral("typeId")].toInt()); + return m_telegramId; +} + +void CoPrtCnvCentralTelegram::setCounter(qint32 counter) +{ + if (m_json.isEmpty()) + m_json = QJsonDocument::fromJson(m_data).object(); + m_json[QStringLiteral("counter")] = counter; + m_data.clear(); +} + +qint32 CoPrtCnvCentralTelegram::counter() +{ + ensureJson(); + const QString key(QStringLiteral("counter")); + const QJsonValue sendCounter(m_json[key]); + if (!sendCounter.isDouble()) + throw TrainingAreaBase::TetraIcd::JsonException(m_json, key); + return sendCounter.toInt(-1); +} + +void CoPrtCnvCentralTelegram::ensureJson() +{ + if (m_json.isEmpty()) + { + if (m_data.isEmpty()) + return; + m_json = QJsonDocument::fromJson(m_data).object(); + } +} + +void CoPrtCnvCentralTelegram::ensureByteArray() +{ + if (m_data.isEmpty()) + { + if (m_json.isEmpty()) + return; + m_data = QJsonDocument(m_json).toJson(QJsonDocument::Compact); + } +} + + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp new file mode 100644 index 000000000..dbb062fa8 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvCentralTelegram.hpp @@ -0,0 +1,60 @@ + + + +#pragma once + +#include +#include +#include +#include + +namespace N_CoPrtCnv +{ + + + class COPRTCNV_EXPORT CoPrtCnvCentralTelegram final + { + public: + explicit CoPrtCnvCentralTelegram(TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_telegramId(telegramId) + {} + explicit CoPrtCnvCentralTelegram(const QByteArray &data) + : m_data(data) + , m_telegramId(TrainingAreaBase::TetraIcd::UNKNOWN) + {} + CoPrtCnvCentralTelegram(const QByteArray &data, TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_data(data) + , m_telegramId(telegramId) + {} + CoPrtCnvCentralTelegram(const QByteArray &data, const QJsonObject &json, TrainingAreaBase::TetraIcd::TelegramId telegramId) + : m_data(data) + , m_json(json) + , m_telegramId(telegramId) + {} + + explicit CoPrtCnvCentralTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram &tele) + : m_telegramId(tele.id()) + { + m_json[QStringLiteral("type")] = tele.type(); + m_json[QStringLiteral("typeId")] = tele.id(); + m_json[QStringLiteral("data")] = tele.toJson(); + } + + void setData(const QByteArray &data); + QByteArray data(); + QJsonObject json(); + QJsonObject jsonData(); + TrainingAreaBase::TetraIcd::TelegramId telegramId(); + void setCounter(qint32 counter); + qint32 counter(); + + private: + void ensureJson(); + void ensureByteArray(); + private: + QByteArray m_data; + QJsonObject m_json; + TrainingAreaBase::TetraIcd::TelegramId m_telegramId; + }; + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp new file mode 100644 index 000000000..9981d431a --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.cpp @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvHexDumpHelper.hpp" +#include "CoPrtCnvRadioTelegram.hpp" + +#include +#include + +static std::string dumpSammeldeaktivierung(const N_CoPrtCnv::CoPrtCnvRadioTelegram* sammelTelegram) +{ + const int ANZAHL_POS = 5; + const int SIZE_POS = sammelTelegram->getTelID() == GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN ? 2 : 1; + + std::stringstream sstream; + unsigned int cnt = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS, SIZE_POS); + for (unsigned int i = 0; i < cnt; ++i) { + uint16_t telId = sammelTelegram->getPayloadDataUInt32(ANZAHL_POS + SIZE_POS + 2 * i, 2); + sstream << telId << " "; + } + return sstream.str(); +} + +QByteArray telegramId2String(gef_telegramm_id_et telId) +{ + const char *str = nullptr; + switch (telId) + { + case GEF_BESTAETIGUNG: str = "GEF_BESTAETIGUNG"; break; + case GEF_INIT: str = "GEF_INIT"; break; + case GEF_MANIPULATIONSMELDUNG: str = "GEF_MANIPULATIONSMELDUNG"; break; + case GEF_UMGEBUNGS_MELDUNG2: str = "GEF_UMGEBUNGS_MELDUNG2"; break; + case GEF_AUFFORDERUNG_BITE_MELDUNG: str = "GEF_AUFFORDERUNG_BITE_MELDUNG"; break; + case GEF_BITE_MELDUNG2: str = "GEF_BITE_MELDUNG2"; break; + case GEF_LIZENSIERUNG_TNE: str = "GEF_LIZENSIERUNG_TNE"; break; + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: str = "GEF_BETRIEBSZUSTAND_AUSSTATTUNG"; break; + case GEF_KONFIGURATION_WIRKMODELL: str = "GEF_KONFIGURATION_WIRKMODELL"; break; + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: str = "GEF_ANFORDERUNG_KONFIGURATIONSDATEN"; break; + case GEF_KONFIGURATIONSMELDUNG: str = "GEF_KONFIGURATIONSMELDUNG"; break; + case GEF_FEHLERMELDUNG_GFD: str = "GEF_FEHLERMELDUNG_GFD"; break; + case GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT: str = "GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT"; break; + case GEF_POSITIONS_MELDUNG: str = "GEF_POSITIONS_MELDUNG"; break; + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: str = "GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER"; break; + case GEF_POSITIONS_MELDUNG_LFZ: str = "GEF_POSITIONS_MELDUNG_LFZ"; break; + case GEF_IPS_POSITIONSDATEN: str = "GEF_IPS_POSITIONSDATEN"; break; + case GEF_SCHIEDSRICHTERKOMMANDO: str = "GEF_SCHIEDSRICHTERKOMMANDO"; break; + case GEF_WIRKFELD_EINZELGESCHOSS: str = "GEF_WIRKFELD_EINZELGESCHOSS"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP"; break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: str = "GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN"; break; + case GEF_WIRKFELD_MINENSPERRE: str = "GEF_WIRKFELD_MINENSPERRE"; break; + case GEF_WIRKFELD_STATUS_MINENSPERRE: str = "GEF_WIRKFELD_STATUS_MINENSPERRE"; break; + case GEF_WIRKFELD_A_KAMPFMITTEL: str = "GEF_WIRKFELD_A_KAMPFMITTEL"; break; + case GEF_WIRKFELD_C_KAMPFMITTEL: str = "GEF_WIRKFELD_C_KAMPFMITTEL"; break; + case GEF_DEAKTIVIERUNG_WIRKFELD: str = "GEF_DEAKTIVIERUNG_WIRKFELD"; break; + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: str = "GEF_WIRKFELD_AENDERUNG_BEZEICHNER"; break; + case GEF_DEAKTIVIERUNG_EINZELMINE: str = "GEF_DEAKTIVIERUNG_EINZELMINE"; break; + case GEF_REAKTIVIERUNG_DUS_MINE: str = "GEF_REAKTIVIERUNG_DUS_MINE"; break; + case GEF_DEFINITION_IED: str = "GEF_DEFINITION_IED"; break; + case GEF_ZUSTAND_IED: str = "GEF_ZUSTAND_IED"; break; + case GEF_STATUS_EINZELMINENSIMULATOR: str = "GEF_STATUS_EINZELMINENSIMULATOR"; break; + case GEF_WIRKFELD_EINZELMINENSIMULATOR: str = "GEF_WIRKFELD_EINZELMINENSIMULATOR"; break; + case GEF_TREFFER_EREIGNIS_DUS: str = "GEF_TREFFER_EREIGNIS_DUS"; break; + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION"; break; + case GEF_TREFFER_AUSLOESUNG: str = "GEF_TREFFER_AUSLOESUNG"; break; + case GEF_SCHIEDSRICHTEREINGRIFF: str = "GEF_SCHIEDSRICHTEREINGRIFF"; break; + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: str = "GEF_SELEKTIVE_AUFMUNITIONIERUNG"; break; + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: str = "GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG"; break; + case GEF_TREFFER_EREIGNIS_DUS_IPS: str = "GEF_TREFFER_EREIGNIS_DUS_IPS"; break; + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: str = "GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS"; break; + case GEF_TAKTISCHER_STATUS: str = "GEF_TAKTISCHER_STATUS"; break; + case GEF_FUNKTIONSRAUM: str = "GEF_FUNKTIONSRAUM"; break; + case GEF_EINTRETEN_FUNKTIONSRAUM: str = "GEF_EINTRETEN_FUNKTIONSRAUM"; break; + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: str = "GEF_DEAKTIVIEREN_FUNKTIONSRAUM"; break; + case GEF_DATENVERKEHR_SRT_TDS: str = "GEF_DATENVERKEHR_SRT_TDS"; break; + case GEF_DATENVERKEHR_TDS_SRT: str = "GEF_DATENVERKEHR_TDS_SRT"; break; + case GEF_DATENVERKEHR_DMF_TDS: str = "GEF_DATENVERKEHR_DMF_TDS"; break; + case GEF_DATENVERKEHR_TDS_DMF: str = "GEF_DATENVERKEHR_TDS_DMF"; break; + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: str = "GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME"; break; + case GEF_NOP: str = "GEF_NOP"; break; + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: str = "GEF_SONDERSENSORIK_BETRIEBSZUSTAND"; break; + case GEF_SONDERSENSORIK_FAHRSPUR: str = "GEF_SONDERSENSORIK_FAHRSPUR"; break; + case GEF_SONDERSENSORIK_DATEN: str = "GEF_SONDERSENSORIK_DATEN"; break; + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN"; break; + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: str = "GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN"; break; + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: str = "GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION"; break; + case GEF_SPRACHAUSWAHL: str = "GEF_SPRACHAUSWAHL"; break; + case GEF_ALLGEMEINE_NACHRICHT: str = "GEF_ALLGEMEINE_NACHRICHT"; break; + case GEF_ECHO_ON_OFF: str = "GEF_ECHO_ON_OFF"; break; + case GEF_ESW_MELDUNG: str = "GEF_ESW_MELDUNG"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG: str = "GEF_WF_SAMMELDEAKTIVIERUNG"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: str = "GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN"; break; + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: str = "GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM"; break; + case GEF_DATENVERKEHR_GEOP_TDS: str = "GEF_DATENVERKEHR_GEOP_TDS"; break; + case GEF_DATENVERKEHR_TDS_GEOP: str = "GEF_DATENVERKEHR_TDS_GEOP"; break; + case GEF_DATENVERKEHR_TGTC_TDS: str = "GEF_DATENVERKEHR_TGTC_TDS"; break; + case GEF_DATENVERKEHR_TDS_TGTC: str = "GEF_DATENVERKEHR_TDS_TGTC"; break; + case GEF_GERAETEEREIGNIS: str = "GEF_GERAETEEREIGNIS"; break; + case GEF_WAFFENZUORDNUNG: str = "GEF_WAFFENZUORDNUNG"; break; + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: str = "GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE"; break; + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: str = "GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG"; break; + case GEF_AUSLOESUNG_DUS_TREFFER: str = "GEF_AUSLOESUNG_DUS_TREFFER"; break; + case GEF_ANFORDERUNG_SW_VERSION: str = "GEF_ANFORDERUNG_SW_VERSION"; break; + case GEF_SW_VERSIONSMELDUNG: str = "GEF_SW_VERSIONSMELDUNG"; break; + case GEF_TECHNIK_FUNKTIONSRAUM: str = "GEF_TECHNIK_FUNKTIONSRAUM"; break; + case GEF_TEILNEHMERMODE_SETZEN: str = "GEF_TEILNEHMERMODE_SETZEN"; break; + case GEF_TEILNEHMERMODE_MELDUNG: str = "GEF_TEILNEHMERMODE_MELDUNG"; break; + case GEF_TEILNEHMERMODE_ANFORDERN: str = "GEF_TEILNEHMERMODE_ANFORDERN"; break; + case GEF_TEILNEHMER_KONFIG_ANTWORT: str = "GEF_TEILNEHMER_KONFIG_ANTWORT"; break; + case GEF_TEILNEHMER_KONFIG_SETZEN: str = "GEF_TEILNEHMER_KONFIG_SETZEN"; break; + case GEF_TEILNEHMER_KONFIG_ANFORDERN: str = "GEF_TEILNEHMER_KONFIG_ANFORDERN"; break; + case GEF_SANITAETSDIENST_INSTANDSETZUNG: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG"; break; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: str = "GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN"; break; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: str = "GEF_BESTANDSMELDUNG_SANITAETSMATERIAL"; break; + case GEF_GEFECHTSFELDTELEGRAMM: str = "GEF_GEFECHTSFELDTELEGRAMM"; break; + } + + Q_ASSERT(str); + if (!str) + str = "Unknown"; + return str + QByteArray(" (") + QByteArray::number(int(telId)) + ")"; +} + +QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp) +{ + switch(wirkfeldTyp) + { + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea: + return QLatin1String("MINENSPERRE"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea: + return QLatin1String("FLAECHENFEUER"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle: + return QLatin1String("EINZELFEUER"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination: + return QLatin1String("A_KAMPF"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination: + return QLatin1String("C_KAMPF"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea: + return QLatin1String("FUNKTIONS_RAUM"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::TechnicalArea: + return QLatin1String("FUNKTIONS_RAUM_TECHNIK"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::GasPipeDetonation: + return QLatin1String("GAS_PIPE_DETONATION"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::SpecialArea: + return QLatin1String("SPECIAL_AREA"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::Unknown: + return QLatin1String("DUS"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator: + return QLatin1String("DUS_SINGLE_MINE_SIMULATOR"); + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::BeStillWarning: + return QLatin1String("BE_STILL_WARNING"); + } + return QStringLiteral("Unknown Wirkfeldtyp <%1>").arg(static_cast(wirkfeldTyp)); +} + +static inline QString wirkfeldTyp2Str(int typ) +{ + return wirkfeldTyp2Str(static_cast(typ)); +} + +void dumpTelegram(NGL::INGLLogger &m_logger, int id, N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const char *prefix) +{ + if(!m_logger.isDebugEnabled()) + return; + + if (!prefix) + prefix = ""; + const QByteArray commonLog(prefix + QByteArray("BC: ") + QByteArray::number(id) + + ", " + telegramId2String(a_radioTelegram->getTelID())); + switch (a_radioTelegram->getTelID()) + { + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + { + uint8_t wirkfeldTyp = a_radioTelegram->getPayloadDataUInt32(5, 1); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + DEBUG_LOG(m_logger) << commonLog + << ", type: " << wirkfeldTyp2Str(wirkfeldTyp) << ", kennung: " + << wirkfeldKennung; + break; + } + case GEF_DEAKTIVIERUNG_EINZELMINE: { + uint32_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(9, 2); + uint32_t minenKennung = a_radioTelegram->getPayloadDataUInt32(11, 2); + DEBUG_LOG(m_logger) << commonLog + << ", kennung: " << wirkfeldKennung << ", mineId: " << minenKennung; + break; + } + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + DEBUG_LOG(m_logger) << commonLog << ", kennung: " << wirkfeldKennung; + break; + } + case GEF_TECHNIK_FUNKTIONSRAUM: + { + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + uint8_t funktionsraumtyp = a_radioTelegram->getPayloadDataUInt32(7, 1); + DEBUG_LOG(m_logger) << commonLog + << ", kennung: " << funktionsraumkennung + << " type: " << int(funktionsraumtyp); + break; + } + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + DEBUG_LOG(m_logger) << commonLog << ", Ids: " << dumpSammeldeaktivierung(a_radioTelegram); + break; + case GEF_NOP: + { + uint16_t bcFrom = a_radioTelegram->getPayloadDataUInt32(3, 2); + uint16_t bcTo = a_radioTelegram->getPayloadDataUInt32(5, 2); + DEBUG_LOG(m_logger) << prefix + << commonLog + << ", from BC " << bcFrom << " to " << bcTo; + break; + } + default: + DEBUG_LOG(m_logger) << commonLog; + break; + } +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp new file mode 100644 index 000000000..a8d5db300 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvHexDumpHelper.hpp @@ -0,0 +1,32 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include "tetra_telegram_ids.h" + +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +} + +COPRTCNV_EXPORT QByteArray telegramId2String(gef_telegramm_id_et telId); +COPRTCNV_EXPORT void dumpTelegram(NGL::INGLLogger &m_logger, + int id, + N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, + const char *prefix = nullptr); +COPRTCNV_EXPORT QString wirkfeldTyp2Str(TrainingAreaBase::TetraIcd::AreaEffectSimulationType wirkfeldTyp); diff --git a/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp b/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp new file mode 100644 index 000000000..885ca9d99 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvInjectionHeader.hpp @@ -0,0 +1,52 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace N_CoPrtCnv +{ + + + struct CoPrtCnvInjectionHeader + { + + + uint32_t m_Id1; + + + uint32_t m_Id2; + + + enum Destination + { + eUnknown = 0, + eCentral = 1, + eRadio = 2 + } m_Kind; + + + uint16_t m_Size; + + CoPrtCnvInjectionHeader() + : m_Id1(0x12345678), + m_Id2(0x78236239), + m_Kind(eUnknown), + m_Size(0) + {} + + bool isIdCorrect() const { return (m_Id1 == 0x12345678 && m_Id2 == 0x78236239); } + + }; +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp b/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp new file mode 100644 index 000000000..6da5e4811 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvLogHeader.hpp @@ -0,0 +1,52 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace N_CoPrtCnv +{ + + + struct CoPrtCnvLogHeader + { + + + enum E_CoPrtCnvProtocol + { + e_DestProtocolCentral = 0, + e_DestProtocolWls = 1, + e_DestProtocolTetra = 5, + e_DestProtocolMax = 6, + e_DestProtocolMask = 0x0000000F, + e_DestDirectionMask = 0xC0000000, + e_DestReceive = 0x40000000, + e_DestSend = 0xC0000000 + }; + + + short m_Length = 0; + short m_Version = 0; + int m_Priority = 0; + + + int m_Protocol = 0; + + + int m_Reserved = 0; + + + uint64_t m_Time = 0; + }; +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp new file mode 100644 index 000000000..260e87d17 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.cpp @@ -0,0 +1,1793 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvRadioTelegram.hpp" +#include +#include + +using N_CoPrtCnv::CoPrtCnvRadioTelegram; + +using namespace N_CoPrtCnv; + + + +constexpr uint8_t CoPrtCnvRadioTelegram::MAGIC_NUMBER; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_WITH_TL_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::DATA_IND_REQ_NO_TL_HEADER_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH; +constexpr uint16_t CoPrtCnvRadioTelegram::PAYLOAD_STATUS_LENGTH; +constexpr uint8_t CoPrtCnvRadioTelegram::MAX_NBR_OF_FRAGMENTS; + +int CoPrtCnvRadioTelegram::s_2ndDelay = 60; +int CoPrtCnvRadioTelegram::s_3rdDelay = 60; +int CoPrtCnvRadioTelegram::s_maxBroadcastSendCnt = 0; +bool CoPrtCnvRadioTelegram::s_etsMode = false; + +static const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_ProtocolIdentifier +s_protocolIdentifier = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL; + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI) + : m_data(9, Qt::Uninitialized), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_RegisterInd); + + setSrcISSI(a_sourceISSI); +} + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, + const std::set &groups) + : m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + uint16_t len = groups.size(); + if (len > 5) + len = 5; + m_data.resize(12 + len * 4); + setHeader(m_data, e_GroupMonitorReq); + + + setSrcISSI(a_sourceISSI); + + uint8_t mode = 1; + set1Byte(m_data, 9, mode); + set2Byte(m_data, 10, len); + std::set::iterator it = groups.begin(); + for (uint16_t i = 0; i < len; i++) + { + set4Byte(m_data, 12 + i * 4, *it); + ++it; + } +} + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, + const E_DeliveryStatusForTL_Report a_delivery) + : m_data(17, Qt::Uninitialized), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_ReportIndReq); + + setSrcISSI(a_sourceISSI); + setDestISSI(a_sourceISSI); + set1Byte(m_data, 13, s_protocolIdentifier); + set1Byte(m_data, 14, 0); + set1Byte(m_data, 15, 0); + set1Byte(m_data, 16, a_delivery); +} + + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const QByteArray &a_data) + : m_data(a_data), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ +} + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity) + : m_data(a_payloadSize + DATA_IND_REQ_HEADER_LENGTH, '\0'), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, e_NotFragmented); + + set1Byte(m_data, m_PayloadIndex++, a_telegramId); + set1Byte(m_data, m_PayloadIndex++, 0); + set1Byte(m_data, m_PayloadIndex--, 0); + setIdentity(a_identity); + m_PayloadIndex += 2; +} + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi) + : m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + + const bool withGroupIssis = (a_loginTelegramStatus & e_LoginOtherExercise) == e_LoginOtherExercise; + m_data.resize(DATA_IND_REQ_HEADER_LENGTH + (withGroupIssis ? 12 : 3)); + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + setDestISSI(a_issi); + + + uint16_t size = m_data.size(); + set2Byte(m_data, DATA_IND_REQ_WITH_TL_HEADER_LENGTH, 8 * (size - DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER)); + + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, e_NotFragmented + e_LoginTelegram); + + set1Byte(m_data, m_PayloadIndex++, (a_identity >> 8) & 0x00FF); + set1Byte(m_data, m_PayloadIndex++, a_identity & 0x00FF); + set1Byte(m_data, m_PayloadIndex++, a_loginTelegramStatus); +} + +void CoPrtCnvRadioTelegram::setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2) +{ + + + setPayload3Byte(hostIssi); + + setPayload3Byte(groupIssi1); + + setPayload3Byte(groupIssi2); +} + + + + + + +CoPrtCnvRadioTelegram::CoPrtCnvRadioTelegram(const std::shared_ptr &a_bigTelegram, + const uint8_t a_fragmentIndex, + bool &a_error) + : m_data(), + m_PayloadIndex(0), + m_BroadcastCounter(0), + m_NextSendTime(0), + m_IsBroadcastOnly(false), + m_BroadcastOnlyTelegram(nullptr), + m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram")) +{ + + static const uint16_t MAX_TELEGRAM_SIZE = MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH; + + const int payloadSize = a_bigTelegram->getSize() - DATA_IND_REQ_HEADER_LENGTH; + const uint8_t nbrOfFragmentedTelegrams = uint8_t((payloadSize - 1) / MAX_TELEGRAM_SIZE); + if (nbrOfFragmentedTelegrams > (MAX_NBR_OF_FRAGMENTS - 1)) + { + ERROR_LOG(m_logger) << "Radio-telegram is too big (" << nbrOfFragmentedTelegrams + 1 + << " fragments). There are max " << MAX_NBR_OF_FRAGMENTS + << " fragments of size=" << MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + << " (=" << MAX_NBR_OF_FRAGMENTS *MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + << " bytes) possible."; + a_error = true; + return; + } + if (nbrOfFragmentedTelegrams == 0) + { + ERROR_LOG(m_logger) << "Radio-telegram is too small for fragmentation. It must have at least a size of " + << (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + 1); + a_error = true; + return; + } + uint8_t payloadStatus = e_FirstFragment | nbrOfFragmentedTelegrams; + + + const uint16_t payloadSizeNormal = uint16_t(payloadSize / (nbrOfFragmentedTelegrams + 1)); + const uint16_t payloadSizeLast = uint16_t(payloadSize - (nbrOfFragmentedTelegrams * payloadSizeNormal)); + + uint16_t size = payloadSizeNormal; + if (0 != a_fragmentIndex) + { + if (nbrOfFragmentedTelegrams != a_fragmentIndex) + { + + payloadStatus = e_MiddleFragment | (nbrOfFragmentedTelegrams - a_fragmentIndex); + } + else + { + + payloadStatus = e_LastFragment; + size = payloadSizeLast; + } + } + size += PAYLOAD_STATUS_LENGTH; + + + m_data.resize(size + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader)); + setHeader(m_data, e_DataIndReq); + fillDataIndReqHeader(m_data); + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(m_data, m_PayloadIndex++, payloadStatus); + + if (size > 1) + { + const char *srcData = a_bigTelegram->getData() + DATA_IND_REQ_HEADER_LENGTH + a_fragmentIndex * payloadSizeNormal; + const uint8_t *ptr = reinterpret_cast(srcData); + setPayloadData(ptr, size - 1); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: size must be bigger than 1"; + a_error = true; + return; + } + a_error = false; +} + + + +CoPrtCnvRadioTelegram::~CoPrtCnvRadioTelegram() +{ + if (m_BroadcastOnlyTelegram != nullptr) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr while deletion of radio-telegram"; +} + + + + + +void CoPrtCnvRadioTelegram::setPayload1Byte(const uint8_t a_value) +{ + set1Byte(m_data, m_PayloadIndex, a_value); + m_PayloadIndex += 1; +} + +void CoPrtCnvRadioTelegram::setPayload2Byte(const uint16_t a_value) +{ + setPayloadData(a_value, 2); +} + +void CoPrtCnvRadioTelegram::setPayload3Byte(const uint32_t a_value) +{ + setPayloadData(a_value, 3); +} + +void CoPrtCnvRadioTelegram::setPayload4Byte(const uint32_t a_value) +{ + setPayloadData(a_value, 4); +} + +void CoPrtCnvRadioTelegram::setPayloadData(uint32_t a_value, const uint8_t a_size) +{ + for (int i = m_PayloadIndex + a_size - 1; i >= m_PayloadIndex; i--) + { + set1Byte(m_data, i, a_value & 0xFF); + a_value >>= 8; + } + m_PayloadIndex += a_size; +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadData(const uint8_t *a_data, const uint16_t a_size) +{ + uint8_t *ptr = reinterpret_cast(m_data.data()); + memcpy(&ptr[m_PayloadIndex], a_data, a_size); + m_PayloadIndex += a_size; +} + + + + +void CoPrtCnvRadioTelegram::fixupTelegramIdForEts(bool convertToEtsId) +{ + if (!s_etsMode) + return; + char *ptr = &m_data.data()[DATA_IND_REQ_HEADER_LENGTH]; + if (convertToEtsId) + ++(*ptr); + else + --(*ptr); +} + +void CoPrtCnvRadioTelegram::setEtsMode(bool bIsEtsMode) +{ + s_etsMode = bIsEtsMode; +} + + + + +gef_telegramm_id_et CoPrtCnvRadioTelegram::getTelID() const +{ + return static_cast(static_cast(m_data.at(DATA_IND_REQ_HEADER_LENGTH))); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::zaehler() const +{ + return static_cast(m_data.at(1)); +} + + + + + +void CoPrtCnvRadioTelegram::setZaehler(const uint8_t a_counter) +{ + set1Byte(m_data, 1, a_counter); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const +{ + uint32_t value = 0; + const uint8_t *ptr = reinterpret_cast(m_data.data()); + uint8_t *ptrValue = reinterpret_cast(&value); + a_offset += DATA_IND_REQ_HEADER_LENGTH; + switch (a_size) + { + case 4: + ptrValue[3] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 3: + ptrValue[2] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 2: + ptrValue[1] = ptr[a_offset++]; + Q_FALLTHROUGH(); + case 1: + ptrValue[0] = ptr[a_offset++]; + break; + default: + Q_ASSERT(false); + ERROR_LOG(m_logger) << "a_size must be between 1..4"; + } + + return value; +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getPayloadDataUInt8(size_t a_offset) const +{ + return static_cast(m_data.at(DATA_IND_REQ_HEADER_LENGTH + a_offset)); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getDestISSI() const +{ + return getUInt32(9); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getIdentity() const +{ + return isLoginTelegram() ? getPayloadDataUInt32(0, 2) : getPayloadDataUInt32(1, 2); +} + + + + + +void CoPrtCnvRadioTelegram::setSrcISSI(const uint32_t a_ISSI) +{ + setSrcISSI_Internal(m_data, a_ISSI); +} + + + + + + +bool CoPrtCnvRadioTelegram::mustBroadcastBeSet() const +{ + + + if (isNormalTelegram()) + return getIdentity() == 0 && getBroadcastIndex() == 0; + + return false; +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastIndex(const uint16_t a_broadcastIndex) +{ + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 3, (a_broadcastIndex >> 8) & 0xFF); + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + 4, a_broadcastIndex & 0xFF); +} + + + + + +void CoPrtCnvRadioTelegram::setDestISSI(const uint32_t a_ISSI) +{ + setDestISSI_Internal(m_data, a_ISSI); +} + + + + + +CoPrtCnvRadioTelegram::E_PDU_Type CoPrtCnvRadioTelegram::getPDU_Type() const +{ + return static_cast(m_data.at(4)); +} + + + + + +CoPrtCnvRadioTelegram::E_FragmentStatus CoPrtCnvRadioTelegram::getFragmentStatus() const +{ + return static_cast(m_data.at(26) & e_FragmentStatusMask); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getFragmentCounter() const +{ + return static_cast(m_data.at(26) & e_CounterMask); +} + + + + + + + +bool CoPrtCnvRadioTelegram::isCrcOk() const +{ + if ((m_data.at(26) & e_Checksum) == e_Checksum) + { + + uint32_t sum = getProtocolIdentifier(); + for (int i = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; i < m_data.size() - 2; i++) + sum += static_cast(m_data.at(i)); + + uint16_t checksum = getUInt8(m_data.size() - 2) * 256 + getUInt8(m_data.size() - 1); + checksum = ~checksum; + checksum++; + + auto that = const_cast(this); + that->m_data.resize(m_data.size() - 2); + that->m_data[26] = (m_data.at(26) & ~e_Checksum); + + if (sum != checksum) + { + ERROR_LOG(m_logger) << "Checksum of telegram is wrong: " << QString::number(checksum, 16) + << " (expected: " << QString::number(sum, 16) << "), issi: " << getUInt32(5); + return true; + } + } + return true; +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getSrcISSI() const +{ + return getUInt32(5); +} + + + + + +bool CoPrtCnvRadioTelegram::isLoginTelegram() const +{ + if (e_DataIndReq == getPDU_Type()) + return (e_LoginTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26))); + return false; +} + + + + + +bool CoPrtCnvRadioTelegram::mustBeFragmented() const +{ + if (e_DataIndReq == getPDU_Type()) + return size_t(getSize()) > (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_WITH_TL_HEADER_LENGTH + sizeof(PrtCnvRadioGwHeader)); + return false; +} + + + + + + +const uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset) const +{ + return reinterpret_cast(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]); +} + +uint8_t *CoPrtCnvRadioTelegram::getPayloadDataPtr(uint16_t a_offset) +{ + return reinterpret_cast(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH + a_offset]); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getPayloadSize() const +{ + return static_cast((getPDU_Type() == e_DataIndReq) ? m_data.size() - DATA_IND_REQ_HEADER_LENGTH : 0); +} + + + + + + + + + + +QByteArray CoPrtCnvRadioTelegram::getUnfragmentedData(const std::multimap &a_fragTelegramList) +{ + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvRadioTelegram"); + + uint16_t totalSize = 0; + bool first = true; + uint8_t expectedNextFragment = 0; + CoPrtCnvRadioTelegram *firstFragment = nullptr; + std::multimap::const_reverse_iterator rit; + for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit) + { + CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second; + if (first) + { + if (e_FirstFragment == fragRadioTelegram->getFragmentStatus()) + { + totalSize += fragRadioTelegram->getSize(); + expectedNextFragment = fragRadioTelegram->getFragmentCounter() - 1; + firstFragment = fragRadioTelegram; + first = false; + } + else + { + ERROR_LOG(l) << "The fragment with the highest counter is not marked as first fragment"; + return nullptr; + } + } + else + { + if (e_MiddleFragment == fragRadioTelegram->getFragmentStatus() || e_LastFragment == fragRadioTelegram->getFragmentStatus()) + { + if (expectedNextFragment-- == fragRadioTelegram->getFragmentCounter()) + { + if (e_LastFragment == fragRadioTelegram->getFragmentStatus() && 0 != fragRadioTelegram->getFragmentCounter()) + { + ERROR_LOG(l) << "The last fragment must have a counter of 0, but the counter is " << (int)fragRadioTelegram->getFragmentCounter(); + return nullptr; + } + totalSize += fragRadioTelegram->getPayloadSize(); + } + else + { + ERROR_LOG(l) << "The fragmented Radio-Telegram from TNE with id=" << fragRadioTelegram->getIdentity() << " with fragment-counter=" << (expectedNextFragment + 1) << " was lost"; + return nullptr; + } + } + else + { + ERROR_LOG(l) << "A fragment which is not the first one, is not marked as middle or last fragment"; + return nullptr; + } + } + } + + + if (firstFragment + && totalSize <= (DATA_IND_REQ_HEADER_LENGTH + MAX_NBR_OF_FRAGMENTS * (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH - PAYLOAD_STATUS_LENGTH)) + && totalSize > DATA_IND_REQ_HEADER_LENGTH) + { + QByteArray data(totalSize, Qt::Uninitialized); + + setHeader(data, e_DataIndReq); + fillDataIndReqHeader(data); + setSrcISSI_Internal(data, firstFragment->getSrcISSI()); + setDestISSI_Internal(data, firstFragment->getDestISSI()); + uint16_t index = DATA_IND_REQ_HEADER_LENGTH - PAYLOAD_STATUS_LENGTH; + set1Byte(data, index++, e_NotFragmented); + + + for (rit = a_fragTelegramList.rbegin(); rit != a_fragTelegramList.rend(); ++rit) + { + CoPrtCnvRadioTelegram *fragRadioTelegram = rit->second; + uint16_t fragSize = fragRadioTelegram->getPayloadSize(); + if (index + fragSize <= totalSize) + { + memcpy(&data.data()[index], fragRadioTelegram->getPayloadDataPtr(0), fragSize); + index += fragSize; + } + else + { + + ERROR_LOG(l) << "Internal error: size of allocated datablock is too small"; + return QByteArray(); + } + } + + return data; + } + + ERROR_LOG(l) << "Internal error while building unfragmented radio-telegram: fragTelegram=" << firstFragment << " totalSize=" << totalSize; + return QByteArray(); +} + + + + + +bool CoPrtCnvRadioTelegram::isTelegramLengthOk(const uint16_t a_lengthWithoutFrame) +{ + return (a_lengthWithoutFrame <= (MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH + DATA_IND_REQ_HEADER_LENGTH - sizeof(PrtCnvRadioGwHeader) - PAYLOAD_STATUS_LENGTH)); +} + + + + + + +bool CoPrtCnvRadioTelegram::isNormalTelegram() const +{ + return (e_DataIndReq == getPDU_Type() && (e_NormalTelegram == ((e_FragmentStatusMask | e_CounterMask) & m_data.at(26)))); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getPriority() const +{ + if (isNormalTelegram()) + { + switch (getTelID()) + { + case GEF_INIT: + case GEF_DEAKTIVIERUNG_EINZELMINE: + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + return 2; + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_REAKTIVIERUNG_DUS_MINE: + case GEF_TECHNIK_FUNKTIONSRAUM: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_TDS_GEOP: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + case GEF_POSITIONS_MELDUNG: + return 3; + case GEF_UMGEBUNGS_MELDUNG2: + case GEF_AUFFORDERUNG_BITE_MELDUNG: + case GEF_LIZENSIERUNG_TNE: + case GEF_TREFFER_AUSLOESUNG: + case GEF_SPRACHAUSWAHL: + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + case GEF_SCHIEDSRICHTERKOMMANDO: + return 4; + case GEF_KONFIGURATION_WIRKMODELL: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + case GEF_DATENVERKEHR_TDS_SRT: + case GEF_DATENVERKEHR_TDS_DMF: + case GEF_DATENVERKEHR_TDS_TGTC: + case GEF_TEILNEHMERMODE_SETZEN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_SETZEN: + return 5; + case GEF_ALLGEMEINE_NACHRICHT: + return 6; + case GEF_SW_VERSIONSMELDUNG: + return 7; + + case GEF_NOP: + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + return 99; + default: + ERROR_LOG(m_logger) << "Priority of telegram with telId=" << getTelID() << " not defined."; + +#ifdef DEBUG + abort(); +#endif + } + } + else if (isLoginTelegram()) + return 4; + return 10; +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getBroadcastIndex() const +{ + if (isNormalTelegram() && m_data.size() > (DATA_IND_REQ_HEADER_LENGTH + 4)) + return getPayloadDataUInt32(3, 2); + return 0; +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size) +{ + + + if (1 == a_size) + set1Byte(m_data, DATA_IND_REQ_HEADER_LENGTH + a_index, a_value); + else + { + uint16_t savedPayloadIndex = m_PayloadIndex; + m_PayloadIndex = DATA_IND_REQ_HEADER_LENGTH + a_index; + setPayloadData(a_value, a_size); + m_PayloadIndex = savedPayloadIndex; + } +} + + + + + +void CoPrtCnvRadioTelegram::setPayloadDataComplete(const QByteArray &payload) +{ + m_data.resize(payload.size() + DATA_IND_REQ_HEADER_LENGTH); + setHeader(m_data, getPDU_Type()); + memcpy(&m_data.data()[DATA_IND_REQ_HEADER_LENGTH], payload.data(), payload.size()); +} + + + + + + + + + +void CoPrtCnvRadioTelegram::resetPayloadSize(const uint16_t a_newPayloadSize) +{ + m_data.resize(a_newPayloadSize + DATA_IND_REQ_HEADER_LENGTH); + setHeader(m_data, getPDU_Type()); + + uint16_t size = m_data.size(); + set2Byte(m_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8); + set2Byte(m_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH)); +} + + + + + +void CoPrtCnvRadioTelegram::setIdentity(const uint16_t a_identity) +{ + setPayloadDataWithIndex(isLoginTelegram() ? 0 : 1, a_identity, 2); +} + + + + + +void CoPrtCnvRadioTelegram::setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier) +{ + if (e_DataIndReq == getPDU_Type()) + set1Byte(m_data, 13, a_ProtocolIdentifier); +} + + + + + +void CoPrtCnvRadioTelegram::setMessageReference(const uint8_t a_MessageReference) +{ + if (isSDSTL()) + set1Byte(m_data, 14, a_MessageReference); +} + + + + + +bool CoPrtCnvRadioTelegram::isSDSTL() const +{ + return (e_DataIndReq == getPDU_Type() && (e_UsingSDS_TL == (e_UsingSDS_TL & getProtocolIdentifier()))); +} + + + + + + +CoPrtCnvRadioTelegram::E_RegistrationStatus CoPrtCnvRadioTelegram::getRegistrationStatus() const +{ + return static_cast(m_data.at(5)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getRegistrationStatusAsText() const +{ + switch (getRegistrationStatus()) + { + case e_IssiSuccessfulRegistered: + return "IssiSuccessfulRegistered"; + case e_DuplicateISSI: + return "DuplicateISSI"; + case e_InvalidISSI: + return "InvalidISSI"; + case e_InvalidIpAddress: + return "InvalidIpAddress"; + } + return std::to_string(getRegistrationStatus()); +} + + + + + +CoPrtCnvRadioTelegram::E_ProtocolIdentifier CoPrtCnvRadioTelegram::getProtocolIdentifier() const +{ + return static_cast(m_data.at(13)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getProtocolIdentifierAsText() const +{ + switch (getProtocolIdentifier()) + { + case e_SimpleTextMessagingWithoutSDS_TL: + return "Simple Text Messaging w/o SDS/TL"; + case e_SimpleGPS_WithoutSDS_TL: + return "Simple GPS w/o SDS/TL"; + case e_TDSMessageWithoutSDS_TL: + return "TDS Message w/o SDS/TL"; + case e_UsingSDS_TL: + return "SDS/TL"; + case e_SimpleTextMessagingUsingSDS_TL: + return "Simple Text Messaging with SDS/TL"; + case e_SimpleGPS_UsingSDS_TL: + return "Simple GPS with SDS/TL"; + case e_LoginTest: + return "Login-Test / Hohenfels"; + } + return std::to_string(getProtocolIdentifier()); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getMessageReference() const +{ + return static_cast(m_data.at(14)); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getAreaSelection() const +{ + return static_cast(m_data.at(15)); +} + + + + + +uint8_t CoPrtCnvRadioTelegram::getValidityPeriod() const +{ + return static_cast(m_data.at(16)); +} + + + + + +uint32_t CoPrtCnvRadioTelegram::getForwardAddress() const +{ + return getUInt32(17); +} + + + + + +CoPrtCnvRadioTelegram::E_Flags CoPrtCnvRadioTelegram::getFlags() const +{ + return static_cast(m_data.at(21)); +} + + + + + +std::string CoPrtCnvRadioTelegram::getFlagsAsText() const +{ + switch (getFlags()) + { + case e_FlagsNone: + return "No Flags"; + + case e_StorageAllowed: + return "Storage Allowed"; + + case e_GroupServiceOrOnlyStandardReportAllowed: + return "Group Service or only Standard Report Allowed"; + + case e_ReceivedConfirmationRequested: + return "Received Confirmation Requested"; + + case e_ConsumedConfirmationRequested: + return "Consumed Confirmation Requested"; + + } + std::ostringstream str; + str << getFlags(); + return str.str(); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getLengthInBits() const +{ + return getUInt16(22); +} + + + + + +uint16_t CoPrtCnvRadioTelegram::getLengthInBytes() const +{ + return getUInt16(24); +} + + + + +bool CoPrtCnvRadioTelegram::getWithCrc() const +{ + if (getSize() > 26) + return ((m_data.at(26) & e_Checksum) == e_Checksum); + return false; +} + + + + + + +CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report CoPrtCnvRadioTelegram::getDelivery() const +{ + return static_cast(m_data.at(16)); +} + + + + + + +std::string CoPrtCnvRadioTelegram::getDeliveryAsText() const +{ + switch (getDelivery()) + { + case e_SDS_ReceiptAcknowledgedByDestination: + return "SDS receipt acknowledged by destination"; + + case e_SDS_ConsumedByDestination: + return "SDS consumed by destination"; + + case e_SourceIsNotAuthorizedForSDS: + return "Source is not authorized for SDS"; + + case e_DestinationIsNotAuthorizedForSDS: + return "Destination is not authorized for SDS"; + + case e_UnknownDestinationAddress: + return "Unknown destination address"; + + case e_DeliveryFailed: + return "Delivery failed"; + + case e_DestinationNotRegisteredOnSystem: + return "Destination not registered on system"; + + case e_DestinationQueueFull: + return "Destination queue full"; + + case e_MessageTooLong: + return "Message too long"; + + case e_DestinationHostPC_NotConnected: + return "Destination host PC not connected"; + + case e_ProtocolNotSupported: + return "Protocol not supported"; + + case e_DataCodingSchemeNotSupported: + return "Datat coding scheme not supported"; + + case e_DestinationNotReachable: + return "Destination not reachable"; + + } + std::ostringstream str; + str << getDelivery(); + return str.str(); +} + + + + + + +int32_t CoPrtCnvRadioTelegram::getPayloadDataSInt24(uint16_t a_offset) const +{ + uint32_t value = getPayloadDataUInt32(a_offset, 3); + + if (value & 0x800000) + value |= 0xFF800000; + + return value; +} + + + + + +bool CoPrtCnvRadioTelegram::needsLicensing() const +{ + if (isNormalTelegram()) + { + switch (getTelID()) + { + + case GEF_UMGEBUNGS_MELDUNG2: + case GEF_LIZENSIERUNG_TNE: + case GEF_AUFFORDERUNG_BITE_MELDUNG: + case GEF_ALLGEMEINE_NACHRICHT: + return false; + default: + + break; + } + return true; + } + return false; +} + + + + + + + +bool CoPrtCnvRadioTelegram::hasExpired() const +{ + uint32_t expireTime = getExpireTime(); + if (expireTime > 0) + { + uint32_t now = time(nullptr); + return (now >= expireTime); + } + return false; +} + + + + + + +uint32_t CoPrtCnvRadioTelegram::getExpireTime() const +{ + if (isNormalTelegram()) + { + uint32_t wirkBegin = 0; + uint32_t wirkDauer = 0; + switch (getTelID()) + { + case GEF_WIRKFELD_EINZELGESCHOSS: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = 5; + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 2); + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + wirkBegin = getPayloadDataUInt32(11, 4); + wirkDauer = getPayloadDataUInt32(15, 2); + break; + case GEF_WIRKFELD_A_KAMPFMITTEL: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 2) * 60 * 10; + break; + case GEF_WIRKFELD_C_KAMPFMITTEL: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60; + break; + case GEF_WIRKFELD_MINENSPERRE: + wirkBegin = getPayloadDataUInt32(11 + 5, 4); + wirkDauer = getPayloadDataUInt32(15 + 5, 1) * 60 * 60; + break; + default: + return 0; + } + + if (0 == wirkDauer) + { + return 0; + } + + if (wirkBegin > 0) + return (wirkBegin + wirkDauer); + } + return 0; +} + + + + + + + + + +bool CoPrtCnvRadioTelegram::isContentValid() +{ + if (isNormalTelegram()) + { + uint16_t wirkfeldkennung = 0; + uint8_t wirkfeldtyp = 0; + switch (getTelID()) + { + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + wirkfeldkennung = getPayloadDataUInt32(5, 2); + wirkfeldtyp = 3; + Q_FALLTHROUGH(); + case GEF_DEAKTIVIERUNG_WIRKFELD: + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + if (GEF_DEAKTIVIERUNG_WIRKFELD == getTelID() || GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID()) + { + wirkfeldtyp = getPayloadDataUInt8(5); + wirkfeldkennung = getPayloadDataUInt32(6, 2); + } + + if ((wirkfeldtyp >= 1 && wirkfeldtyp <= 5) || (wirkfeldtyp == 8)) + { + if (wirkfeldkennung > 0 && wirkfeldkennung <= 32767) + return true; + ERROR_LOG(m_logger) << "Wirkfeldkennung (" << wirkfeldkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..32768."; + return false; + } + if (GEF_WIRKFELD_AENDERUNG_BEZEICHNER == getTelID() && wirkfeldkennung > 0) + return true; + + + + ERROR_LOG(m_logger) << "Wirkfeldtyp (" << wirkfeldtyp << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..5 or 8."; + return false; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + if (isPayloadLengthOk(13)) + { + wirkfeldkennung = getPayloadDataUInt32(9, 2); + { + if (wirkfeldkennung > 32767) + { + ERROR_LOG(m_logger) << "DeaktivierungEinzelmine: wirkfeldkennung=" << wirkfeldkennung << " too big. Must be 1..32767"; + return false; + } + } + return true; + } + return false; + + case GEF_TECHNIK_FUNKTIONSRAUM: + case GEF_FUNKTIONSRAUM: + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint32_t funktionsraumkennung = getPayloadDataUInt32(5, 2); + if (funktionsraumkennung > 0) + return true; + + ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535."; + return false; + } + case GEF_EINTRETEN_FUNKTIONSRAUM: + if (isPayloadLengthOk(15)) + { + uint32_t funktionsraumkennung = getPayloadDataUInt32(13, 2); + if (funktionsraumkennung > 0) + return true; + + ERROR_LOG(m_logger) << "Funktionsraumkennung (" << funktionsraumkennung << ") of telegram with telId=" << getTelID() << " is invalid. Must be 1..65535."; + return false; + } + return false; + + case GEF_SPRACHAUSWAHL: + { + uint8_t sprache = getPayloadDataUInt8(5); + if (sprache <= 3) + return true; + + ERROR_LOG(m_logger) << "Sprache (" << sprache << ") of telegram with telId=" << getTelID() << " is invalid. Must be 0..3."; + return false; + } + + + + case GEF_MANIPULATIONSMELDUNG: + return isPayloadLengthOk(12); + + case GEF_BITE_MELDUNG2: + return isPayloadLengthOk(27, 19, 7); + + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + return isPayloadLengthOk(9); + + case GEF_FEHLERMELDUNG_GFD: + return isPayloadLengthOk(9); + + case GEF_POSITIONS_MELDUNG: + return isPayloadLengthOk(14); + + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + return isPayloadLengthOk(15, 14, 2); + + case GEF_POSITIONS_MELDUNG_LFZ: + return isPayloadLengthOk(15); + + case GEF_TREFFER_EREIGNIS_DUS: + return isPayloadLengthOk(23); + + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + return isPayloadLengthOk(22); + + case GEF_SCHIEDSRICHTEREINGRIFF: + return isPayloadLengthOk(16); + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + return isPayloadLengthOk(8,7,8); + + case GEF_TAKTISCHER_STATUS: + return isPayloadLengthOk(16); + + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + { + uint16_t length = m_data.size() - DATA_IND_REQ_HEADER_LENGTH; + + const uint16_t MIN_LENGTH = 7; + if (length >= MIN_LENGTH) + return true; + + ERROR_LOG(m_logger) << "The payload-length of telegram with telId=" << getTelID() << " must be at least " << MIN_LENGTH << ", but it is only " << length; + return false; + } + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + return isPayloadLengthOk(10); + + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + return isPayloadLengthOk(9); + + case GEF_SONDERSENSORIK_FAHRSPUR: + return isPayloadLengthOk(15); + + case GEF_SONDERSENSORIK_DATEN: + return isPayloadLengthOk(17); + + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + return isPayloadLengthOk(24); + + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + return isPayloadLengthOk(25); + + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + return isPayloadLengthOk(16); + + case GEF_DATENVERKEHR_GEOP_TDS: + + return isPayloadLengthOk(15, 14, 1); + + case GEF_DATENVERKEHR_TGTC_TDS: + + return isPayloadLengthOk(8, 7, 1); + + case GEF_GERAETEEREIGNIS: + + return isPayloadLengthOk(25, 24, 1); + + case GEF_WAFFENZUORDNUNG: + + return isPayloadLengthOk(8, 7, 6); + + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + + return isPayloadLengthOk(13, 12, 5); + + case GEF_IPS_POSITIONSDATEN: + + return isPayloadLengthOk(8, 7, 2); + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + return isPayloadLengthOk({13, 17}); + + case GEF_TEILNEHMERMODE_MELDUNG: + return isPayloadLengthOk(15); + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + return isPayloadLengthOk(27); + + case GEF_DEFINITION_IED: + return isPayloadLengthOk(24); + + case GEF_ZUSTAND_IED: + return isPayloadLengthOk(16); + + case GEF_STATUS_EINZELMINENSIMULATOR: + return isPayloadLengthOk(17); + + default: + + + break; + } + } + return true; +} + + + + + + + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize) const +{ + if (0 == a_variableDataElementSize) + return isPayloadLengthOk(a_minLength); + + const uint16_t length = getPayloadSize(); + if (length >= a_minLength) + { + uint8_t dataAmount = getPayloadDataUInt8(a_dataAmountOffset); + uint16_t dataSize = a_variableDataElementSize * dataAmount; + uint16_t expectedLength = dataSize + a_minLength; + if (expectedLength != length) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be " << expectedLength + << ", but it is " << length << " (the amount of variable data in telegram was " + << dataAmount << " => " << dataSize << " bytes)"; + return false; + } + } + else + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " << getTelID() + << " must be at least " << a_minLength << ", but it is only " << length; + return false; + } + return true; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_minLength, + uint16_t a_maxLength) const +{ + if (a_maxLength == 0) + return isPayloadLengthOk(a_minLength); + + const uint16_t length = getPayloadSize(); + if (length < a_minLength) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be greater or equal to " + << a_minLength << ", but it is " << length; + return false; + } + + if (length > a_maxLength) + { + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be fewer than " + << a_minLength << ", but it is " << length; + return false; + } + return true; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(uint16_t a_length) const +{ + const uint16_t length = getPayloadSize(); + if (length == a_length) + return true; + + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << " must be " + << a_length << ", but it is " << length; + return false; +} + +bool CoPrtCnvRadioTelegram::isPayloadLengthOk(const std::vector &a_lengths) const +{ + const uint16_t length = getPayloadSize(); + if (std::any_of(a_lengths.begin(), a_lengths.end(), [length](int len) { return len == length;})) + return true; + + WARNING_LOG(m_logger) << "The payload-length of telegram with telId: " + << getTelID() << ", is: " << length; + return false; +} + + + + + +bool CoPrtCnvRadioTelegram::mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter) +{ + a_wasLastBroadcast = false; + + if (m_BroadcastCounter < s_maxBroadcastSendCnt && m_NextSendTime <= a_currentTime) + { + if (a_updateBroadcastCounter) + { + + switch (m_BroadcastCounter) + { + case 0: + if (s_2ndDelay >= 0) + { + m_NextSendTime = time(nullptr) + s_2ndDelay; + INFO_LOG(m_logger) << "1st Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + break; + } + ++m_BroadcastCounter; + Q_FALLTHROUGH(); + case 1: + if (s_3rdDelay >= 0) + { + m_NextSendTime = time(nullptr) + s_3rdDelay; + INFO_LOG(m_logger) << "2nd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + break; + } + ++m_BroadcastCounter; + Q_FALLTHROUGH(); + default: + INFO_LOG(m_logger) << "3rd Broadcast-Telegram telId=" << getTelID() << " BC=" << getBroadcastIndex(); + m_NextSendTime = 0; + a_wasLastBroadcast = true; + } + ++m_BroadcastCounter; + } + return true; + } + return false; +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay) +{ + s_2ndDelay = a_2ndDelay; + s_3rdDelay = a_3rdDelay; +} + + + + + +void CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(int a_maxSendCnt) +{ + s_maxBroadcastSendCnt = a_maxSendCnt; +} + + + + + + +bool CoPrtCnvRadioTelegram::isMovedToBroadcastList() const +{ + return (m_BroadcastCounter >= 1); +} + + + + + +void CoPrtCnvRadioTelegram::setBroadcastOnly(const bool a_doSet) +{ + m_IsBroadcastOnly = a_doSet; +} + + + + + +bool CoPrtCnvRadioTelegram::isBroadcastOnly() const +{ + return m_IsBroadcastOnly; +} + + + + + + +void CoPrtCnvRadioTelegram::setBroadcastonlyTelegram(const std::shared_ptr &a_radioTelegram) +{ + if (a_radioTelegram != nullptr && m_BroadcastOnlyTelegram != nullptr) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastOnlyTelegram was not nullptr"; + if (a_radioTelegram != nullptr) + { + INFO_LOG(m_logger) << "Set braodcastonly-telegram: telId=" << a_radioTelegram->getTelID() + << " BC=" << a_radioTelegram->getBroadcastIndex(); + } + m_BroadcastOnlyTelegram = a_radioTelegram; +} + + + + + + +std::shared_ptr CoPrtCnvRadioTelegram::getBroadcastonlyTelegram() const +{ + return m_BroadcastOnlyTelegram; +} + + + + + +void CoPrtCnvRadioTelegram::set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint8_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + +void CoPrtCnvRadioTelegram::set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint16_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + +void CoPrtCnvRadioTelegram::set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value) +{ + Q_ASSERT(a_offset < a_data.size()); + uint32_t *ptr = reinterpret_cast(&a_data.data()[a_offset]); + *ptr = a_value; +} + + + + + + + + +uint16_t CoPrtCnvRadioTelegram::getUInt16(const uint16_t a_offset) const +{ + const uint16_t *ptr = reinterpret_cast(&m_data.data()[a_offset]); + return *ptr; +} + + + + + + + + +uint32_t CoPrtCnvRadioTelegram::getUInt32(const uint16_t a_offset) const +{ + const uint32_t *ptr = reinterpret_cast(&m_data.data()[a_offset]); + return *ptr; +} + + + + + + +void CoPrtCnvRadioTelegram::setHeader(QByteArray &data, E_PDU_Type pduType) +{ + + set1Byte(data, 0, MAGIC_NUMBER); + set1Byte(data, 1, 0); + set2Byte(data, 2, data.size() - sizeof(PrtCnvRadioGwHeader)); + set1Byte(data, 4, pduType); +} + + + + + + + + + +void CoPrtCnvRadioTelegram::fillDataIndReqHeader(QByteArray &a_data) +{ + set1Byte(a_data, 4, e_DataIndReq); + setSrcISSI_Internal(a_data, 0); + setDestISSI_Internal(a_data, 0); + + set1Byte(a_data, 13, s_protocolIdentifier); + set1Byte(a_data, 14, 0); + set1Byte(a_data, 15, 0); + set1Byte(a_data, 16, 0); + set1Byte(a_data, 17, 0); + set1Byte(a_data, 18, 0); + set1Byte(a_data, 19, 0); + set1Byte(a_data, 20, 0); + set1Byte(a_data, 21, e_FlagsNone); + + uint16_t size = a_data.size(); + set2Byte(a_data, 22, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH) * 8); + set2Byte(a_data, 24, (size - DATA_IND_REQ_HEADER_LENGTH + PAYLOAD_STATUS_LENGTH)); +} + + + + + +void CoPrtCnvRadioTelegram::setSrcISSI_Internal(QByteArray &data, const uint32_t issi) +{ + set4Byte(data, 5, issi); +} + + + + + + +uint16_t CoPrtCnvRadioTelegram::getBroadcastCounter() const +{ + return m_BroadcastCounter; +} + + + + + +void CoPrtCnvRadioTelegram::setDestISSI_Internal(QByteArray &data, const uint32_t issi) +{ + set4Byte(data, 9, issi); +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp new file mode 100644 index 000000000..e2f0f02df --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvRadioTelegram.hpp @@ -0,0 +1,604 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "tetra_telegram_ids.h" + +namespace NGL +{ +class INGLLogger; +} + +namespace N_CoPrtCnv +{ + + +enum class E_LicensingKind +{ + + + Success = 0, + + + Rejected = 1, + + + Unlicense = 2 +}; + + + +enum class E_LicensingErrorCode +{ + Ok = 0, + Selftest = 1, + Battery = 2, + Configuration = 3, + Unlicense = 4, + IdentityDenied = 5 +}; + + + +class COPRTCNV_EXPORT CoPrtCnvRadioTelegram +{ +public: + + + + enum E_Flags + { + e_FlagsNone = 0x00, + e_StorageAllowed = 0x10, + e_GroupServiceOrOnlyStandardReportAllowed = 0x20, + e_ReceivedConfirmationRequested = 0x40, + e_ConsumedConfirmationRequested = 0x80 + }; + + + + enum E_ProtocolIdentifier + { + e_SimpleTextMessagingWithoutSDS_TL = 0x02, + e_SimpleGPS_WithoutSDS_TL = 0x03, + e_TDSMessageWithoutSDS_TL = 0x50, + e_UsingSDS_TL = 0x80, + e_SimpleTextMessagingUsingSDS_TL = 0x82, + e_SimpleGPS_UsingSDS_TL = 0x83, + e_LoginTest = 0x1D + }; + + + + enum E_FragmentStatus + { + e_NotFragmented = 0x00, + e_FirstFragment = 0x40, + e_MiddleFragment = 0xC0, + e_LastFragment = 0x80, + e_FragmentStatusMask = 0xC0, + e_Checksum = 0x20, + e_CounterMask = 0x0F, + e_NormalTelegram = 0x00, + e_LoginTelegram = 0x02, + e_DgpsTelegram = 0x03 + }; + + + + struct PrtCnvRadioGwHeader + { + + + uint8_t m_MagicNumber; + + + uint8_t m_Counter; + + + uint16_t m_Length; + + }; + + + + enum E_PDU_Type + { + e_RegisterInd = 0, + e_RegisterRsp = 1, + e_DataIndReq = 2, + e_ReportIndReq = 3, + e_StatusIndReq = 4, + e_GroupMonitorReq = 6, + e_AirInterfaceLoadReq = 8, + e_AirLoadHyterra = 19 + }; + + + + enum E_RegistrationStatus + { + e_IssiSuccessfulRegistered = 0, + e_DuplicateISSI = 1, + e_InvalidISSI = 2, + e_InvalidIpAddress = 3 + }; + + + + enum E_DeliveryStatusForTL_Report + { + e_SDS_ReceiptAcknowledgedByDestination = 0x00, + e_SDS_ConsumedByDestination = 0x02, + e_SourceIsNotAuthorizedForSDS = 0x43, + e_DestinationIsNotAuthorizedForSDS = 0x44, + e_UnknownDestinationAddress = 0x45, + e_DeliveryFailed = 0x4A, + e_DestinationNotRegisteredOnSystem = 0x4B, + e_DestinationQueueFull = 0x4C, + e_MessageTooLong = 0x4D, + e_DestinationHostPC_NotConnected = 0x4F, + e_ProtocolNotSupported = 0x50, + e_DataCodingSchemeNotSupported = 0x51, + e_DestinationNotReachable = 0x5A + }; + + + + enum E_LoginStatus + { + e_LoginRequest = 0x40, + e_LoginAccept = 0x80, + e_LoginReject = 0xC0, + e_LoginStatusMask = 0xC0, + e_LoginMastering = 0x20, + + + e_LoginNoExerciseAssignment = 0x00, + e_LoginOtherEqId = 0x02, + e_LoginOtherISSI = 0x04, + e_LoginOtherExercise = 0x06, + }; + + + + static constexpr uint8_t MAGIC_NUMBER = 0xA5; + + + static constexpr uint16_t DATA_IND_REQ_WITH_TL_HEADER_LENGTH = 22; + + + static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH = 27; + + + static constexpr uint16_t DATA_IND_REQ_HEADER_LENGTH_WITHOUT_PAYLOAD_HEADER = DATA_IND_REQ_HEADER_LENGTH -1; + + + static constexpr uint16_t DATA_IND_REQ_NO_TL_HEADER_LENGTH = 14; + + + static constexpr uint16_t MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH = 249; + + + static constexpr uint16_t PAYLOAD_STATUS_LENGTH = 1; + + + static constexpr uint8_t MAX_NBR_OF_FRAGMENTS = 16; + + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI); + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const std::set &groups); + + + + explicit CoPrtCnvRadioTelegram(const uint32_t a_sourceISSI, const E_DeliveryStatusForTL_Report a_delivery); + + + + explicit CoPrtCnvRadioTelegram(const QByteArray &a_data); + + + + explicit CoPrtCnvRadioTelegram(const gef_telegramm_id_et a_telegramId, const uint16_t a_payloadSize, const uint16_t a_identity); + + + + explicit CoPrtCnvRadioTelegram(const E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, uint32_t a_issi); + + void setLoginIssis(int hostIssi, int groupIssi1, int groupIssi2); + + + + explicit CoPrtCnvRadioTelegram(const std::shared_ptr &a_bigTelegram, + const uint8_t a_fragmentIndex, bool &a_error); + + + virtual ~CoPrtCnvRadioTelegram(); + + + + void fixupTelegramIdForEts(bool convertToEtsId); + static void setEtsMode(bool bIsEtsMode); + + + + void setPayload1Byte(uint8_t a_value); + void setPayload2Byte(uint16_t a_value); + void setPayload3Byte(uint32_t a_value); + void setPayload4Byte(uint32_t a_value); + void setPayloadData(uint32_t a_value, const uint8_t a_size); + + + + void setPayloadData(const uint8_t a_value) { return setPayload1Byte(a_value); } + + + + void setPayloadData(const uint8_t *a_data, const uint16_t a_size); + + + + const char *getData() const { return m_data.data(); } + char *getData() { return m_data.data(); } + QByteArray data() const { return m_data; } + + + + int getSize() const { return m_data.size(); } + + + + gef_telegramm_id_et getTelID() const; + + + + uint8_t zaehler() const; + + + + void setZaehler(const uint8_t a_counter); + + + + uint32_t getPayloadDataUInt32(size_t a_offset, uint16_t a_size) const; + + + + uint8_t getPayloadDataUInt8(size_t a_offset) const; + + + + uint32_t getDestISSI() const; + + + + uint16_t getIdentity() const; + + + + void setSrcISSI(const uint32_t a_ISSI); + + + + bool mustBroadcastBeSet() const; + + + + void setBroadcastIndex(const uint16_t a_broadcastIndex); + + + + void setDestISSI(const uint32_t a_ISSI); + + + + CoPrtCnvRadioTelegram::E_PDU_Type getPDU_Type() const; + + + + CoPrtCnvRadioTelegram::E_FragmentStatus getFragmentStatus() const; + + + + uint8_t getFragmentCounter() const; + + + + bool isCrcOk() const; + + + + uint32_t getSrcISSI() const; + + + + bool isLoginTelegram() const; + + + + bool mustBeFragmented() const; + + + + const uint8_t *getPayloadDataPtr(uint16_t a_offset) const; + uint8_t *getPayloadDataPtr(uint16_t a_offset); + + + + virtual uint16_t getPayloadSize() const; + + + + static QByteArray getUnfragmentedData(const std::multimap &a_fragTelegramList); + + + + static bool isTelegramLengthOk(const uint16_t a_lengthWithoutFrame); + + + + bool isNormalTelegram() const; + + + + uint8_t getPriority() const; + + + + uint16_t getBroadcastIndex() const; + + + + void setPayloadDataWithIndex(const uint16_t a_index, const uint32_t a_value, const uint16_t a_size); + + + + void setPayloadDataComplete(const QByteArray &payload); + + + + void resetPayloadSize(const uint16_t a_newPayloadSize); + + + + void setIdentity(const uint16_t a_identity); + + + + void setProtocolIdentifier(const E_ProtocolIdentifier a_ProtocolIdentifier); + + + + void setMessageReference(const uint8_t a_MessageReference); + + + + bool isSDSTL() const; + + + + CoPrtCnvRadioTelegram::E_RegistrationStatus getRegistrationStatus() const; + + + + std::string getRegistrationStatusAsText() const; + + + + CoPrtCnvRadioTelegram::E_ProtocolIdentifier getProtocolIdentifier() const; + + + + std::string getProtocolIdentifierAsText() const; + + + + uint8_t getMessageReference() const; + + + + uint8_t getAreaSelection() const; + + + + uint8_t getValidityPeriod() const; + + + + uint32_t getForwardAddress() const; + + + + CoPrtCnvRadioTelegram::E_Flags getFlags() const; + + + + std::string getFlagsAsText() const; + + + + uint16_t getLengthInBits() const; + + + + uint16_t getLengthInBytes() const; + + + + bool getWithCrc() const; + + + + CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report getDelivery() const; + + + + std::string getDeliveryAsText() const; + + + + int32_t getPayloadDataSInt24(uint16_t a_offset) const; + + + + bool needsLicensing() const; + + + + bool hasExpired() const; + + + + uint32_t getExpireTime() const; + + + + bool isContentValid(); + + + + bool mustBeSentAsBroadcast(time_t a_currentTime, bool &a_wasLastBroadcast, const bool a_updateBroadcastCounter = true); + + + + static void setBroadcastDelayTimes(int a_2ndDelay, int a_3rdDelay); + + + + static void setMaxBroadcastSendCnt(int a_maxSendCnt); + + + + bool isMovedToBroadcastList() const; + + + + void setBroadcastOnly(const bool a_doSet = true); + + + + bool isBroadcastOnly() const; + + + + void setBroadcastonlyTelegram(const std::shared_ptr &a_radioTelegram); + + + + std::shared_ptr getBroadcastonlyTelegram() const; + + + + uint16_t getBroadcastCounter() const; + + + + +protected: + + + + QByteArray m_data; + + + + uint16_t m_PayloadIndex; + + + uint16_t m_BroadcastCounter; + + + time_t m_NextSendTime; + + + static int s_2ndDelay; + + + static int s_3rdDelay; + + + static int s_maxBroadcastSendCnt; + + + bool m_IsBroadcastOnly; + + + std::shared_ptr m_BroadcastOnlyTelegram; + + + + static bool s_etsMode; + + + + bool isPayloadLengthOk(uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize) const; + bool isPayloadLengthOk(uint16_t a_minLength, + uint16_t a_maxLength) const; + bool isPayloadLengthOk(uint16_t a_length) const; + bool isPayloadLengthOk(const std::vector &a_lengths) const; + + + + static void set1Byte(QByteArray &a_data, uint16_t a_offset, uint8_t a_value); + + + + static void set2Byte(QByteArray &a_data, uint16_t a_offset, uint16_t a_value); + + + + static void set4Byte(QByteArray &a_data, uint16_t a_offset, uint32_t a_value); + + + uint8_t getUInt8(const uint16_t a_offset) const { return static_cast(m_data.at(a_offset)); } + uint16_t getUInt16(const uint16_t a_offset) const; + uint32_t getUInt32(const uint16_t a_offset) const; + + + + static void setHeader(QByteArray &data, E_PDU_Type pduType); + + + + static void fillDataIndReqHeader(QByteArray &a_data); + + + + static void setSrcISSI_Internal(QByteArray &data, const uint32_t issi); + + + + static void setDestISSI_Internal(QByteArray &data, const uint32_t issi); + +private: + + + NGL::INGLLogger &m_logger; + +}; + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp new file mode 100644 index 000000000..49eb1aa75 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverter.hpp @@ -0,0 +1,57 @@ + + + + + + + + + + + + + +#pragma once + +#include + +namespace TrainingAreaBase +{ +namespace TetraIcd +{ +struct TrainingAreaTelegram; +} +} +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +class CoPrtCnvCentralTelegram; + + + + +namespace CoPrtCnvTelegramConverter +{ + + +COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(CoPrtCnvCentralTelegram *a_telegram); +COPRTCNV_EXPORT CoPrtCnvRadioTelegram *convertToRadio(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *a_telegram); + + + +COPRTCNV_EXPORT CoPrtCnvCentralTelegram *convertToCentral(const CoPrtCnvRadioTelegram *a_radioTelegram); +COPRTCNV_EXPORT TrainingAreaBase::TetraIcd::TrainingAreaTelegram *convertToTabTele(const CoPrtCnvRadioTelegram *a_radioTelegram); + + + + +COPRTCNV_EXPORT void setTetraTextCodec(const char *codecName); + + + +COPRTCNV_EXPORT void setUse2BytesForSingleFireDiameter(bool bUse); +COPRTCNV_EXPORT void setUsePvSan(bool bUse); + +} + +} diff --git a/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp new file mode 100644 index 000000000..09fed4816 --- /dev/null +++ b/TetraIF/CoPrtCnv/CoPrtCnvTelegramConverterNewIcd.cpp @@ -0,0 +1,2131 @@ + + + + + + + + + + + + + + +#include "CoPrtCnvTelegramConverter.hpp" + + +#include +#include +#include +#include +#include "CoPrtCnvCentralTelegram.hpp" +#include "CoPrtCnvRadioTelegram.hpp" +#include +#include +#include +#include + +using namespace TrainingAreaBase::TetraIcd; +namespace N_CoPrtCnv +{ + +namespace CoPrtCnvTelegramConverter +{ + +static QTextCodec *s_TetraTextCodec = nullptr; +static bool s_needTextCodec = false; +static bool s_use2BytesForSingleFireDiameter = true; +static bool s_usePvSan = false; + +static inline NGL::INGLLogger &logger() +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CoPrtCnvTelegramConverter"); +} + +template +static inline bool checkBitmask(const T &d, int bitmask) +{ + return ((d & bitmask) == bitmask); +} + +template +void getSpecialSensorData(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t offset, T *tele) +{ + const uint8_t betrZust = a_radioTelegram->getPayloadDataUInt32(offset, 1); + const uint8_t spuerfunktion = a_radioTelegram->getPayloadDataUInt32(offset + 1, 1); + tele->operationalState = betrZust; + tele->airSensor = checkBitmask(spuerfunktion, 0x80); + tele->tireSensor = checkBitmask(spuerfunktion, 0x40); + tele->pointSensor = checkBitmask(spuerfunktion, 0x20); + tele->solidMatterSampleExtractor = checkBitmask(spuerfunktion, 0x10); +} + +int getVitality(uint32_t index) +{ + uint32_t vitalty = (index &= 0xF000); + uint32_t retVitalty = 0; + retVitalty = vitalty >> 12; + if (retVitalty > 0) + { + retVitalty -= 1; + return retVitalty * 10; + } + return UINT16_MAX; +} + +void setVitality(uint16_t &index, uint16_t vitality) +{ + if (vitality == UINT16_MAX) + vitality = 0; + else + { + vitality /= 10; + vitality += 1; + if (vitality > 11) + { + ERROR_LOG(logger()) << "Cant convert Vitality!"; + return; + } + } + for (int i = 0; i <= 3; i++) + { + if (((vitality) & (1 << (i)))) + index |= (1UL << (i + 12)); + } +} +template +void getTaktZustand(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t iOffset, T *tele) +{ + tele->vulnerabilityState = static_cast( + a_radioTelegram->getPayloadDataUInt32(iOffset + 0, 1)); + + const uint32_t teilnehmertyp = a_radioTelegram->getPayloadDataUInt32(iOffset + 1, 1); + const uint32_t index = a_radioTelegram->getPayloadDataUInt32(iOffset + 2, 2); + if (index) + { + uint32_t indexForVulnerabilit = index; + indexForVulnerabilit &= 0x0FFF; + tele->tasVulnerabilityKindId = teilnehmertyp; + tele->tasVulnerabilityKindId <<= 16; + tele->tasVulnerabilityKindId |= indexForVulnerabilit; + tele->tasVitality = getVitality(index); + } + else + tele->tasVulnerabilityKindId = 0; + + + tele->vulnerabilityBits = 0; + int tmp = a_radioTelegram->getPayloadDataUInt32(iOffset + 4, 2); + + if (tmp == 0) + tele->vulnerabilityBits |= 0x1; + else + { + + for (int i = 1; i <= static_cast(VulnerabilityState::CContamination); ++i) + tele->vulnerabilityBits |= ((tmp >> (16 - i)) & 0x1) << (i); + } +} + +static BiteError getBiteError(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t iOffset) +{ + BiteError ret; + ret.canDeviceNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 0); + ret.subdeviceNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 1); + ret.uniqueId = a_radioTelegram->getPayloadDataUInt32(iOffset + 2, 4); + ret.errorNumber = a_radioTelegram->getPayloadDataUInt8(iOffset + 6); + + return ret; +} + +static void convertToTetraEncoding(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegramm, + const std::string &stdString, + const uint16_t a_size) +{ + QByteArray encodedData; + if (s_needTextCodec && s_TetraTextCodec) + { + + const QString str = QString::fromUtf8(stdString.c_str()); + + encodedData = s_TetraTextCodec->fromUnicode(str); + } + else + encodedData = QByteArray(stdString.c_str(), a_size); + + encodedData = encodedData.leftJustified(a_size, '\0', true); + + encodedData[a_size - 1] = '\0'; + + const uint8_t *data = reinterpret_cast(encodedData.data()); + radioTelegramm->setPayloadData(data, a_size); +} + +void setTetraTextCodec(const char *codecName) +{ + if (codecName) + s_TetraTextCodec = QTextCodec::codecForName(codecName); + else + s_TetraTextCodec = nullptr; + s_needTextCodec = (s_TetraTextCodec != nullptr); +} + +void setUse2BytesForSingleFireDiameter(bool bUse) +{ + s_use2BytesForSingleFireDiameter = bUse; +} + +void setUsePvSan(bool bUse) +{ + s_usePvSan = bUse; +} + +template +T fromJson(CoPrtCnvCentralTelegram *radioTelegram) +{ + return T::fromJson(radioTelegram->jsonData()); +} + +template +const T &fromJson(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTelegram) +{ + return static_cast(*tabTelegram); +} + +TrainingAreaBase::TetraIcd::TelegramId getTelegramId(CoPrtCnvCentralTelegram *centralTelegram) +{ + return TrainingAreaBase::TetraIcd::TelegramId(centralTelegram->telegramId()); +} + +TrainingAreaBase::TetraIcd::TelegramId getTelegramId( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tabTelegram) +{ + return tabTelegram->id(); +} + +void convertToSecAndSetTime(int64_t timeStamp, N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData((uint32_t)(timeStamp / 1000), 4); +} + +template +void setCommonAesParams(const T &tele, CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData((uint32_t) 0, 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.partyId, 1); + convertToSecAndSetTime(tele.effectStart, radioTelegram); +} + +template +void setAesPosition(const T &tele, CoPrtCnvRadioTelegram *radioTelegram) +{ + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); +} + + +static inline int compassToMathAngleForSfm(double compassDegree) +{ + int ret = qRound((90.0 - compassDegree) * 100.0); + while (ret < 0) + ret += 36000; + while (ret > 36000) + ret -= 36000; + return ret; +} + + + + + +template +static CoPrtCnvRadioTelegram *convertToRadioInternal(T *a_telegram) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram = nullptr; + switch (getTelegramId(a_telegram)) + { + case Constraints::id(): + { + const Init &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_INIT, 4, tele.header.equipmentNumber); + uint8_t initialisierungsdaten = 0; + initialisierungsdaten |= ((uint8_t(tele.resetVulnerabilityState) & 0x01) << 6); + initialisierungsdaten |= ((uint8_t(tele.restockCharges) & 0x01) << 5); + initialisierungsdaten |= ((uint8_t(tele.resetManipulation) & 0x01) << 0); + initialisierungsdaten |= ((uint8_t(tele.restockSanitationMaterial) & 0x01) << 1); + + + + radioTelegram->setPayloadData(initialisierungsdaten); + break; + } + + case Constraints::id(): + { + const SetVulnerabilityModel &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_KONFIGURATION_WIRKMODELL, + 9, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelMineIed); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelAreaFire); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelOperatingResource); + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityModelAcWeaponry); + break; + } + case Constraints::id(): + { + const DemandEquipmentConfigurationReport &tele( + fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ANFORDERUNG_KONFIGURATIONSDATEN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const StateChange &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TAKTISCHER_STATUS, + 16, + tele.header.equipmentNumber); + + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + radioTelegram->setPayloadData((uint8_t) tele.vulnerabilityState); + radioTelegram->setPayloadData((uint8_t)(tele.tasVulnerabilityKindId & 0xFF)); + uint16_t vulnerabilityVitalityIndex = 0; + vulnerabilityVitalityIndex = (uint16_t)((tele.tasVulnerabilityKindId >> 16) & 0xFFFF); + setVitality(vulnerabilityVitalityIndex, tele.tasVitality); + radioTelegram->setPayloadData((uint16_t) vulnerabilityVitalityIndex, 2); + + + radioTelegram->setPayloadData((uint16_t) tele.vulnerabilityBits, 2); + + radioTelegram->setPayloadData((uint8_t) tele.originatorId); + radioTelegram->setPayloadData((uint16_t) tele.originatorType, 2); + break; + } + case Constraints::id(): + { + const BiteReport &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BITE_MELDUNG2, + 27, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData((uint8_t) tele.loginType); + radioTelegram->setPayloadData((uint32_t) tele.biteState, 3); + radioTelegram->setPayloadData((uint8_t) tele.batteryState); + + if (tele.biteErrors.size() > 0) + { + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].canDeviceNumber); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].subdeviceNumber); + radioTelegram->setPayloadData((uint32_t) tele.biteErrors[0].uniqueId, 4); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors[0].errorNumber); + radioTelegram->setPayloadData((uint8_t) tele.biteErrors.size() - 1); + } + else + { + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint32_t) 0, 4); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + } + + radioTelegram->setPayloadData((uint32_t) 0, 3); + radioTelegram->setPayloadData((uint8_t) tele.configError); + radioTelegram->setPayloadData((uint32_t) tele.configState, 3); + + for (const BiteError &be : tele.biteErrors) + { + radioTelegram->setPayloadData((uint8_t) be.canDeviceNumber); + radioTelegram->setPayloadData((uint8_t) be.subdeviceNumber); + radioTelegram->setPayloadData((uint32_t) be.uniqueId, 4); + radioTelegram->setPayloadData((uint8_t) be.errorNumber); + } + break; + } + case Constraints::id(): + { + const ExerciseEnvironmentData &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_UMGEBUNGS_MELDUNG2, + 20, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.exerciseId, 2); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData( + (uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) tele.timeZone); + radioTelegram->setPayloadData((uint8_t) tele.utmZone); + radioTelegram->setPayloadData(tele.utmBand); + radioTelegram->setPayloadData((uint8_t *) tele.grid.c_str(), 2); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint8_t) 0); + radioTelegram->setPayloadData((uint32_t) 0, + 4); + break; + } + case Constraints::id(): + { + const DemandBite &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_AUFFORDERUNG_BITE_MELDUNG, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.withSelfTest, 1); + break; + } + case Constraints::id(): + { + const PositionReport &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_POSITIONS_MELDUNG, + 14, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.relPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relPosition.offsetX, 3); + radioTelegram->setPayloadData((uint8_t)(((tele.gpsQuality.moreThan4SatellitesAvailable) ? 0x80 + : 0) + | ((tele.gpsQuality.dgpsModeAvailable) ? 0x40 : 0) + | (tele.gpsQuality.pdopValue & 0x3f)), + 1); + break; + } + case Constraints::id(): + { + const CreateSingleExplosion &tele(fromJson(a_telegram)); + + const int teleSize = s_use2BytesForSingleFireDiameter ? 29 : 28; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_EINZELGESCHOSS, + teleSize, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + setAesPosition(tele, radioTelegram); + if (s_use2BytesForSingleFireDiameter) + { + Q_ASSERT(tele.effectDiameter < 256 * 256 && tele.effectDiameter >= 0); + radioTelegram->setPayloadData(tele.effectDiameter, 2); + } + else + { + Q_ASSERT(tele.effectDiameter < 256 && tele.effectDiameter >= 0); + radioTelegram->setPayloadData(tele.effectDiameter, 1); + } + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + break; + } + case Constraints::id(): + { + const CreateAreaExplosion &tele(fromJson(a_telegram)); +#ifdef GUEZ_MODE + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER, + 44 + tele.mhPoints.size() * 6, + tele.header.equipmentNumber); +#else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER, + 36, + tele.header.equipmentNumber); +#endif + + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / 1000, 2); + + + + + + + + + + + + + + + + + radioTelegram->setPayloadData(tele.relCorner.offsetY, 3); + radioTelegram->setPayloadData(tele.relCorner.offsetX, 3); + radioTelegram->setPayloadData(tele.width / 5, 1); + radioTelegram->setPayloadData(tele.height / 5, 1); + radioTelegram->setPayloadData( + compassToMathAngleForSfm(tele.rotationAngle + 90.0), + 2); + +#ifdef GUEZ_MODE + + radioTelegram->setPayloadData(tele.mhpWidth / 5, 1); + radioTelegram->setPayloadData(tele.mhpLength / 5, 1); + + radioTelegram->setPayloadData( + compassToMathAngleForSfm(tele.mhpRotation + 90.0), + 2); +#endif + radioTelegram->setPayloadData(tele.impactCount, 2); +#ifdef GUEZ_MODE + radioTelegram->setPayloadData(tele.impactRadius, 2); +#else + radioTelegram->setPayloadData(tele.impactEdgeLength, 1); +#endif + radioTelegram->setPayloadData(tele.chargeTypeId, 1); +#ifdef GUEZ_MODE + + radioTelegram->setPayloadData((tele.hazardDistance / 5), 1); + radioTelegram->setPayloadData((uint8_t) 0); + + radioTelegram->setPayloadData(tele.mhPoints.size(), 1); + for(auto pos : qAsConst(tele.mhPoints)) + { + radioTelegram->setPayloadData(pos.offsetY, 3); + radioTelegram->setPayloadData(pos.offsetX, 3); + } +#endif + + break; + } + case Constraints::id(): + { + const PauseEffectSimulation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP, + 7, + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + break; + } + case Constraints::id(): + { + const ResumeEffectSimulation &tele(fromJson(a_telegram)); + radioTelegram + = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN, + 17, + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.sequelNumber, 2); + radioTelegram->setPayloadData(tele.nextImpact, 2); + convertToSecAndSetTime(tele.resumeTime, radioTelegram); + radioTelegram->setPayloadData(tele.remainDuration / 1000, 2); + break; + } + case Constraints::id(): + { + const CreateMineArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_MINENSPERRE, 5 + 22 + tele.segments.size() * 12, tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60 * 60), 1); + + + + radioTelegram->setPayloadData(qRound(tele.layingDepth), 1); + radioTelegram->setPayloadData(qRound(tele.layingDensity * 100), 1); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + + double length =0; + for (const MineAreaSegment &ms : tele.segments) + { + length+= QLineF(ms.relStart.offsetX, ms.relStart.offsetY, ms.relEnd.offsetX, ms.relEnd.offsetY).length(); + } + int minecount = qRound(length*tele.layingDensity); + if (minecount > 1200) + minecount = 1200; + radioTelegram->setPayloadData((uint32_t)minecount, 2); + radioTelegram->setPayloadData(tele.segments.size(), 1); + for (const MineAreaSegment &ms : tele.segments) + { + radioTelegram->setPayloadData(ms.relStart.offsetY, 3); + radioTelegram->setPayloadData(ms.relStart.offsetX, 3); + radioTelegram->setPayloadData(ms.relEnd.offsetY, 3); + radioTelegram->setPayloadData(ms.relEnd.offsetX, 3); + } + break; + } + case Constraints::id(): + { + const MineAreaSingleMineState &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_STATUS_MINENSPERRE, + 5 + 4 + tele.mineState.size(), + 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.mineCount, 2); + radioTelegram->setPayloadData((uint8_t *)(tele.mineState.data()), tele.mineState.size()); + break; + } + case Constraints::id(): + { + const CreateNContamination &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_A_KAMPFMITTEL, + 38, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60), 2); + setAesPosition(tele, radioTelegram); + radioTelegram->setPayloadData(tele.innerRadius, 2); + radioTelegram->setPayloadData(tele.borderLengthInner, 2); + radioTelegram->setPayloadData(tele.borderLengthOuter, 2); + radioTelegram->setPayloadData(qRound(tele.spanAngle * 100), 2); + radioTelegram->setPayloadData(compassToMathAngleForSfm(tele.rotationAngle), + 2); + break; + } + case Constraints::id(): + { + const CreateCContamination &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_C_KAMPFMITTEL, + 45, + tele.header.equipmentNumber); + setCommonAesParams(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectDuration / (1000 * 60), 1); + setAesPosition(tele, radioTelegram); + radioTelegram->setPayloadData(tele.effectRadius, 2); + radioTelegram->setPayloadData(qRound(tele.expansionFactor * 100), 1); + radioTelegram->setPayloadData(compassToMathAngleForSfm(tele.propagationDirection), + 2); + radioTelegram->setPayloadData(tele.windSpeed, 1); + convertToSecAndSetTime(tele.validityTimeWind, radioTelegram); + radioTelegram->setPayloadData(tele.relPositionValidityTimeWind.offsetY, 3); + radioTelegram->setPayloadData(tele.relPositionValidityTimeWind.offsetX, 3); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + radioTelegram->setPayloadData((uint8_t) tele.volatility, 1); + break; + } + case Constraints::id(): + { + const DeactivateEffectSimulation &tele(fromJson(a_telegram)); + if (tele.aesType == AreaEffectSimulationType::FunctionalArea) + { + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIEREN_FUNKTIONSRAUM, 7, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + } + else + { + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIERUNG_WIRKFELD, 8, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.aesType, 1); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + } + break; + } + case Constraints::id(): + { + const ModifyAreaEffectSimulationName &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_AENDERUNG_BEZEICHNER, 16, 0); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.aesType, 1); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + break; + } + case Constraints::id(): + { + const MineTriggered &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DEAKTIVIERUNG_EINZELMINE, + 13, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.mineAreaId, 2); + radioTelegram->setPayloadData(tele.mineIndex, 2); + break; + } + case Constraints::id(): + { + const DusMineReactivation &tele(fromJson(a_telegram)); + + const size_t cnt = tele.dusSerialNumbers.size() > 500 ? 500 : tele.dusSerialNumbers.size(); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_REAKTIVIERUNG_DUS_MINE, + 3 + 2 + 2 + 2 * cnt, + tele.header.equipmentNumber); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayload2Byte(cnt); + for (size_t i = 0; i < cnt; i++) + radioTelegram->setPayload2Byte(tele.dusSerialNumbers.at(i)); + break; + } + case Constraints::id(): + { + const CreateDusSingleMine &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_WIRKFELD_EINZELMINENSIMULATOR, + 21, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.partyId, 1); + radioTelegram->setPayloadData(tele.mineId, 2); + convertToSecAndSetTime(tele.effectStart, radioTelegram); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); + radioTelegram->setPayloadData(tele.chargeTypeId, 1); + break; + } + case Constraints::id(): + { + const DemandVulnerabilityStateChange &tele(fromJson(a_telegram)); +#ifdef GUEZ_MODE + if (s_usePvSan) + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 10, + tele.header.equipmentNumber); + else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 8, + tele.header.equipmentNumber); +#else + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_AUSLOESUNG, + 8, + tele.header.equipmentNumber); +#endif + + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData((uint8_t) tele.reqestedState, 1); + +#ifdef GUEZ_MODE + if (s_usePvSan) + radioTelegram->setPayloadData((uint16_t) tele.vulnerabilityVitalityIndex, 2); +#endif + + break; + } + case Constraints::id(): + { + const TechnicalArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TECHNIK_FUNKTIONSRAUM, + 34, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + radioTelegram->setPayloadData(tele.taType, 1); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.relCorner.offsetY, 3); + radioTelegram->setPayloadData(tele.relCorner.offsetX, 3); + radioTelegram->setPayloadData(tele.width, 2); + radioTelegram->setPayloadData(tele.height, 2); + radioTelegram->setPayloadData((uint32_t) 0, 4); + radioTelegram->setPayloadData((uint32_t) 0, 4); + break; + } + case Constraints::id(): + { + const CreateFunctionalArea &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_FUNKTIONSRAUM, + 30, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.aesDdsId, 2); + convertToTetraEncoding(radioTelegram, tele.name, 8); + radioTelegram->setPayloadData(tele.partyId, 1); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetY, 3); + radioTelegram->setPayloadData(tele.relEffectPosition.offsetX, 3); + radioTelegram->setPayloadData(tele.width / 5, 1); + radioTelegram->setPayloadData(tele.height / 5, 1); + radioTelegram->setPayloadData((uint8_t) tele.deconMode, 1); + radioTelegram->setPayloadData(tele.deconTimeout / 1000 / 60 / 10, + 1); + radioTelegram->setPayloadData((uint8_t) tele.maintenanceMode, 1); + radioTelegram->setPayloadData(tele.maintenanceTimeout / 1000 / 60 / 10, + 1); + radioTelegram->setPayloadData((uint8_t) tele.medicalMode, 1); + radioTelegram->setPayloadData(tele.medicalTimeout / 1000 / 60 / 10, + 1); + break; + } + case Constraints::id(): + { + const LanguageSelection &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SPRACHAUSWAHL, + 6, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.languageSelection, 1); + break; + } + case Constraints::id(): + { + + const EquipmentMessage &tele(fromJson(a_telegram)); + + + + + int len = 0; + int messageLength = (tele.message.size() > 81) + ? 81 + : tele.message.size(); + if (tele.msgId == -1) + len = messageLength + 6; + + + else + len = 9; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ALLGEMEINE_NACHRICHT, + len, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + if (tele.msgId != -1) + { + + + radioTelegram->setPayloadData(3, 1); + + + + radioTelegram->setPayloadData((uint32_t) 0, 1); + radioTelegram->setPayloadData(tele.msgId, 2); + + + + } + else + { + radioTelegram->setPayloadData(tele.message.size(), 1); + radioTelegram->setPayloadData((uint8_t *)(tele.message.c_str()), messageLength); + } + break; + } + case Constraints::id(): + { + const OpaquePayloadDataOut &tele(fromJson(a_telegram)); + switch (tele.payloadType) + { + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::FireSmokeMarker: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_DMF, + tele.payload.size() + 3, + tele.header.equipmentNumber); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::Geopairing: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_GEOP, + tele.payload.size() + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.payload.size(), 1); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::Target: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_TGTC, + tele.payload.size() + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.payload.size(), 1); + break; + case TrainingAreaBase::TetraIcd::OpaquePayloadDataBase::Type::OC: + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_DATENVERKEHR_TDS_SRT, + tele.payload.size() + 3, + tele.header.equipmentNumber); + break; + } + + radioTelegram->setPayloadData((uint8_t *)(tele.payload.data()), tele.payload.size()); + break; + } + + case Constraints::id(): + { + const CesHitInformation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_AUSLOESUNG_DUS_TREFFER, + 16, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayloadData(tele.chargeTasCodeDirect, 2); + radioTelegram->setPayloadData(tele.directionDegree, 2); + radioTelegram->setPayloadData(tele.distance, 2); + radioTelegram->setPayloadData(tele.effectPercent, 1); + radioTelegram->setPayloadData(tele.originatorEquipmentNumber, 2); + break; + } + + case Constraints::id(): + { + const ParticipantSwVersionsRequest &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_ANFORDERUNG_SW_VERSION, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.equipmentFunctionId, 1); + break; + } + + case Constraints::id(): + { + const ParticipantMode &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMERMODE_SETZEN, + 13, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData((uint8_t) tele.language, 1); + radioTelegram->setPayloadData((uint8_t) tele.operationMode, 1); + radioTelegram->setPayloadData(tele.reactivationDetoxication / 10, 1); + radioTelegram->setPayloadData(tele.reactivationMaintenance / 10, 1); + radioTelegram->setPayloadData(tele.reactivationMedic / 10, 1); + unsigned char wph_mode = 0; + wph_mode |= ((uint8_t) tele.modeHelmet & 0x03); + wph_mode |= ((uint8_t) tele.modeVest & 0x03) << 2; + wph_mode |= ((uint8_t) tele.personellProtectionMode & 0x07) << 4; + radioTelegram->setPayloadData(wph_mode, 1); + + unsigned char protection_mode = 0; + protection_mode |= ((uint8_t) tele.protectionLevel & 0x07); + protection_mode |= ((uint8_t) tele.abcProtectionMode & 0x03) << 3; + radioTelegram->setPayloadData(protection_mode, 1); + + unsigned char specialFunction = 0; + specialFunction |= ((uint8_t) tele.handgrenadeSearchMode & 0x03); + specialFunction |= ((uint8_t) tele.internationalMode & 0x03) << 2; + specialFunction |= ((uint8_t) tele.abcProtectionMode & 0x03) << 3; + radioTelegram->setPayloadData(specialFunction, 1); + break; + } + case Constraints::id(): + { + const DemandParticipantMode &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMERMODE_ANFORDERN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const ParticipantConfiguration &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMER_KONFIG_SETZEN, + 25, + tele.header.equipmentNumber); + radioTelegram->setPayloadData((uint32_t) 0, + 2); + radioTelegram->setPayloadData(tele.positionIntervallVehicle, 2); + radioTelegram->setPayloadData(tele.positionIntervallPersonell, 2); + radioTelegram->setPayloadData(tele.positionIntervallAircraft, 2); + radioTelegram->setPayloadData(tele.positionTransmissionIntervall, 2); + radioTelegram->setPayloadData(tele.heightbarrier, 2); + unsigned char tmp = ((uint8_t) tele.faultPositionHandling & 0x03) << 6; + tmp |= ((uint8_t) tele.switchingPositionIntervall & 0x03); + radioTelegram->setPayloadData(tmp, 1); + radioTelegram->setPayloadData(tele.waittimeAdditionalBroadcastDemand, 2); + radioTelegram->setPayloadData(tele.factorWaittimeIncreaseAtHighload, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel1, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel2, 1); + radioTelegram->setPayloadData(tele.waittimeAutomaticVulnerabilityIncreaseLevel3, 1); + radioTelegram->setPayloadData((uint8_t) tele.opticalCode, 1); + radioTelegram->setPayloadData(tele.vulnerabilityModel, 1); + radioTelegram->setPayloadData(tele.validTimeOps, 1); + break; + } + case Constraints::id(): + { + const DemandParticipantConfiguration &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TEILNEHMER_KONFIG_ANFORDERN, + 3, + tele.header.equipmentNumber); + break; + } + case Constraints::id(): + { + const SanitationRepair &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SANITAETSDIENST_INSTANDSETZUNG, + 19, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + radioTelegram->setPayload1Byte(uint8_t(tele.originatorType)); + radioTelegram->setPayload2Byte(tele.equipmentNumberOrigin); + radioTelegram->setPayload1Byte(uint8_t(tele.stateStart)); + + unsigned int bitfield1 = 0; + if (tele.timeOfTreatment) + bitfield1 |= 0x7F; + if (tele.triage) + bitfield1 |= 0x80; + radioTelegram->setPayload1Byte(bitfield1); + + radioTelegram->setPayload1Byte(tele.tyeOfDamage); + + unsigned int bitfield2 = 0; + bitfield2 |= (uint8_t(tele.stateResult) | 0x0F); + bitfield2 |= ((uint8_t(tele.treatmentResult) | 0x30) << 4); + bitfield2 |= (0xC0 << 6); + radioTelegram->setPayload1Byte(bitfield2); + + radioTelegram->setPayload1Byte(tele.fullState); + radioTelegram->setPayloadData(tele.timeOfTreatment, 2); + radioTelegram->setPayloadData(tele.timeOfRecovery, 2); + break; + } + case Constraints::id(): + { + const SanitaryMaterialStockReport &tele(fromJson(a_telegram)); + + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BESTANDSMELDUNG_SANITAETSMATERIAL, + 15 + tele.sanitaryMaterialCount, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + radioTelegram->setPayload4Byte(tele.uniqueId); + radioTelegram->setPayload2Byte(tele.originatorEquipmentNumber); + radioTelegram->setPayload1Byte((uint8_t) tele.qualification); + + radioTelegram->setPayload1Byte(tele.sanitaryMaterialCount); + + for (const auto stock : tele.sanitaryMaterialStock) + radioTelegram->setPayloadData(stock, 1); + + break; + } + case Constraints::id(): + { + const Sanitation &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN, + 23, + tele.header.equipmentNumber); + convertToSecAndSetTime(tele.header.timeStamp, radioTelegram); + + int p1 = tele.proceduresTaken & 0xFFFFFFFF; + int p2 = tele.proceduresTaken >> 32; + + radioTelegram->setPayloadData(p2, 4); + radioTelegram->setPayloadData(p1, 4); + radioTelegram->setPayloadData(tele.uniqeId, 4); + radioTelegram->setPayloadData(tele.originatorEquipmentNumber, 2); + radioTelegram->setPayloadData((uint8_t) tele.qualification, 1); + + quint8 sanResultAndEvaluation = (((uint8_t) tele.sanitationEvaluation & 0x03) << 6) + + ((uint8_t) tele.sanitationResult & 0x3f); + radioTelegram->setPayloadData(sanResultAndEvaluation, 1); + + break; + } + case Constraints::id(): + { + const CesHitRequest &tele(fromJson(a_telegram)); + + + + + + + + + + + + + + int chargeTasCode = tele.chargeTasCodeDirect; + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG, + 17, + tele.header.equipmentNumber); + const bool insideBuilding = (tele.roomId > 0 && tele.buildingId > 0); + int remainEffectOrTasCodeDirect = 0; + int reserve1 = tele.mineId; + int reserve2 = 0; + int gpsZeit = tele.header.timeStamp ; + switch (tele.aesType) + { + case AreaEffectSimulationType::Unknown: + + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + if (remainEffectOrTasCodeDirect == 100) + { + remainEffectOrTasCodeDirect = 49; + } + break; + case AreaEffectSimulationType::FunctionalArea: + + + + + + + + + + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + + + + chargeTasCode = tele.chargeTasCodeIndirect; + reserve1 = tele.reserve1; + reserve2 = tele.reserve2; + break; + case AreaEffectSimulationType::AirSupport: + case AreaEffectSimulationType::NContamination: + case AreaEffectSimulationType::MineArea: + case AreaEffectSimulationType::CContamination: + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + chargeTasCode = tele.chargeTasCodeIndirect; + break; + case AreaEffectSimulationType::DangerZoneExplosion: + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + chargeTasCode = tele.chargeTasCodeIndirect; + reserve1 = tele.reserve1; + break; + case AreaEffectSimulationType::ExplosionArea: + case AreaEffectSimulationType::ExplosionSingle: + if (insideBuilding) + { + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + } + else + { + + remainEffectOrTasCodeDirect = 255; + chargeTasCode = tele.chargeTasCodeIndirect; + } + break; + case AreaEffectSimulationType::GasPipeDetonation: + + remainEffectOrTasCodeDirect = tele.remainEffectTasCodeDirect; + break; + default: + + remainEffectOrTasCodeDirect = tele.remainEffectPercent; + chargeTasCode = tele.chargeTasCodeIndirect; + break; + } + + radioTelegram->setPayloadData((uint32_t) gpsZeit, 4); + radioTelegram->setPayload2Byte(chargeTasCode); + if (tele.aesDdsId != 0) + radioTelegram->setPayload2Byte(tele.aesDdsId); + else + radioTelegram->setPayload2Byte(tele.originatorEquipmentNumber); + + radioTelegram->setPayload1Byte(uint8_t(tele.aesType)); + radioTelegram->setPayload1Byte(remainEffectOrTasCodeDirect); + radioTelegram->setPayload2Byte(reserve1); + radioTelegram->setPayload2Byte(reserve2); + DEBUG_LOG(logger()) << "Reserve1 of CesHitRequest: " << reserve1 << " Reserve2: " << reserve2; + + break; + } + case Constraints::id(): + { + const SelectiveReammunition &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SELEKTIVE_AUFMUNITIONIERUNG, + 8 + tele.reammunitions.size() * 8, + tele.header.equipmentNumber); + radioTelegram->setPayload4Byte(tele.gearId); + radioTelegram->setPayload1Byte(tele.reammunitions.size()); + for (const auto &reammunition : tele.reammunitions) + { + radioTelegram->setPayload2Byte(reammunition.chargeTypeId); + radioTelegram->setPayload1Byte(reammunition.location); + radioTelegram->setPayload2Byte(reammunition.newStock); + radioTelegram->setPayload2Byte(reammunition.newDefaultStock); + radioTelegram->setPayload1Byte(reammunition.tracerRatio); + } + break; + } + case Constraints::id(): + { + const OcCommand &tele(fromJson(a_telegram)); + radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_SCHIEDSRICHTERKOMMANDO, + 4, + tele.header.equipmentNumber); + radioTelegram->setPayloadData(tele.action, 1); + break; + } + default: + { + ERROR_LOG(logger()) << "Conversion of Central-Telegram to Radio-Telegram with telId=" + << getTelegramId(a_telegram) << " not implemented!"; + } + + + } + return radioTelegram; +} + +CoPrtCnvRadioTelegram *convertToRadio(CoPrtCnvCentralTelegram *a_telegram) +{ + return convertToRadioInternal(a_telegram); +} + +CoPrtCnvRadioTelegram *convertToRadio( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *a_telegram) +{ + return convertToRadioInternal(a_telegram); +} + +static inline Header getHeader(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t tsOffset) +{ + Header hdr; + hdr.equipmentNumber = a_radioTelegram->getIdentity(); + hdr.timeStamp = a_radioTelegram->getPayloadDataUInt32(tsOffset, 4) * 1000LL; + return hdr; +} + +static inline RelativePosition getRelativePosition(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offset) +{ + RelativePosition pos; + pos.offsetY = a_radioTelegram->getPayloadDataSInt24(offset); + pos.offsetX = a_radioTelegram->getPayloadDataSInt24(offset + 3); + return pos; +} + +static inline GpsQuality getGpsQuality(const CoPrtCnvRadioTelegram *a_radioTelegram, size_t offset) +{ + const uint8_t gps = a_radioTelegram->getPayloadDataUInt8(offset); + GpsQuality ret; + ret.moreThan4SatellitesAvailable = ((gps & 0x80) == 0x80); + ret.dgpsModeAvailable = ((gps & 0x40) == 0x40); + ret.pdopValue = (gps & 0x3f); + return ret; +} + +static inline OpsPosition getOpsPosition(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offset, + size_t *newOffset = nullptr) +{ + const uint8_t opsLen = a_radioTelegram->getPayloadDataUInt8(offset); + offset += 1; + OpsPosition pos; + pos.opsId = -1; + if (opsLen > 0) + { + std::vector opse; + opse.reserve(opsLen); + for (uint32_t i = 0; i < opsLen; i++) + { + opse.push_back(a_radioTelegram->getPayloadDataUInt32(offset, 2)); + offset += 2; + } + pos.opsId = opse.at(opse.size() - 1); + } + if (newOffset) + *newOffset = offset; + return pos; +} + +static inline std::vector getPayload(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offsetData) +{ + int payloadLen = a_radioTelegram->getPayloadSize(); + payloadLen -= offsetData; + if (payloadLen <= 0) + { + ERROR_LOG(logger()) << "Radio-Telegram Datenverkehr SRT-TDS contains too less data: " + << payloadLen; + return {}; + } + std::vector ret; + ret.resize(payloadLen); + memcpy(ret.data(), a_radioTelegram->getPayloadDataPtr(offsetData), payloadLen); + return ret; +} + +static inline std::vector getPayload(const CoPrtCnvRadioTelegram *a_radioTelegram, + size_t offsetLen, + size_t offsetData) +{ + int payloadLen = a_radioTelegram->getPayloadDataUInt8(offsetLen); + if (payloadLen <= 0) + { + ERROR_LOG(logger()) << "Radio-Telegram Datenverkehr SRT-TDS contains too less data: " + << payloadLen; + return {}; + } + std::vector ret; + ret.resize(payloadLen); + memcpy(ret.data(), a_radioTelegram->getPayloadDataPtr(offsetData), payloadLen); + return ret; +} + +static N_CoPrtCnv::CoPrtCnvCentralTelegram *toCentral( + const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *data) +{ + QJsonObject obj; + obj[QStringLiteral("data")] = data->toJson(); + obj[QStringLiteral("type")] = data->type(); + obj[QStringLiteral("typeId")] = data->id(); + const QByteArray ba = QJsonDocument(obj).toJson(QJsonDocument::Compact); + return new N_CoPrtCnv::CoPrtCnvCentralTelegram(ba, + static_cast( + data->id())); +} + +template +void fixupEnum(T lowerBound, T upperBound, T defaultVal, T &valToFixup) +{ + if (valToFixup >= lowerBound && valToFixup <= upperBound) + return; + valToFixup = defaultVal; +} + + + + + + +static bool isPayloadLengthOk(const CoPrtCnvRadioTelegram *tele, uint16_t a_length) +{ + const uint16_t length = tele->getPayloadSize(); + if (length >= a_length) + return true; + + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be " << a_length << ", but it is " << length; + return false; +} + +static bool isPayloadLengthOk(const CoPrtCnvRadioTelegram *tele, + uint16_t a_minLength, + const uint16_t a_dataAmountOffset, + const uint8_t a_variableDataElementSize, + bool useHalf = false) +{ + if (0 == a_variableDataElementSize) + return isPayloadLengthOk(tele, a_minLength); + + const uint16_t length = tele->getPayloadSize(); + if (length >= a_minLength) + { + uint8_t dataAmount = tele->getPayloadDataUInt8(a_dataAmountOffset); + uint16_t dataSize = a_variableDataElementSize * dataAmount; + if (useHalf) + { + if ((dataAmount % 2) == 1) + dataSize = a_variableDataElementSize * ((dataAmount / 2.0) + 0.5); + else + dataSize = a_variableDataElementSize * (dataAmount / 2); + } + uint16_t expectedLength = dataSize + a_minLength; + if (expectedLength != length) + { + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be " << expectedLength << ", but it is " << length + << " (the amount of variable data in telegram was " << dataAmount + << " => " << dataSize << " bytes)"; + return false; + } + } + else + { + WARNING_LOG(logger()) << "The payload-length of telegram with telId: " << tele->getTelID() + << " must be at least " << a_minLength << ", but it is only " << length; + return false; + } + return true; +} + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *convertToCentral(const CoPrtCnvRadioTelegram *a_radioTelegram) +{ + auto tab = convertToTabTele(a_radioTelegram); + if (!tab) + return nullptr; + auto ret = toCentral(tab); + delete tab; + return ret; +} + +TrainingAreaTelegram *convertToTabTele(const CoPrtCnvRadioTelegram *a_radioTelegram) +{ + switch (a_radioTelegram->getTelID()) + { + case GEF_MANIPULATIONSMELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 12)) + return nullptr; + + auto tele = new ManipulationReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->isManipulation = a_radioTelegram->getPayloadDataUInt32(7, 1); + tele->equipmentFunctionId = a_radioTelegram->getPayloadDataUInt32(8, 1); + + + + + return tele; + } + + case GEF_BITE_MELDUNG2: + { + + if (!isPayloadLengthOk(a_radioTelegram, 27, 19, 7)) + return nullptr; + + auto tele = new BiteReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->loginType = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + + uint32_t ergebnisCAN = a_radioTelegram->getPayloadDataUInt32(8, 3); + tele->biteState = ergebnisCAN; + + uint8_t ergebnisAusstattung = a_radioTelegram->getPayloadDataUInt8(11); + tele->batteryState = ergebnisAusstattung; + + const auto nonDynamic = getBiteError(a_radioTelegram, 12); + if (nonDynamic.errorNumber != 0 || nonDynamic.canDeviceNumber != 0 + || nonDynamic.subdeviceNumber != 0 || nonDynamic.uniqueId != 0) + tele->biteErrors.push_back(nonDynamic); + + const uint8_t fehlerLen = a_radioTelegram->getPayloadDataUInt8(19); + tele->biteErrors.reserve(tele->biteErrors.size() + fehlerLen); + for (uint8_t i = 0; i < fehlerLen; ++i) + { + const uint8_t iPos = 27 + i * 7; + tele->biteErrors.push_back(getBiteError(a_radioTelegram, iPos)); + } + a_radioTelegram->getPayloadDataUInt32(20, 3); + + tele->configError = a_radioTelegram->getPayloadDataUInt8(23); + uint32_t aktuelleKonfiguration = a_radioTelegram->getPayloadDataUInt32(24, 3); + tele->configState = aktuelleKonfiguration; + return tele; + } + + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 18)) + return nullptr; + + auto tele = new EquipmentGearEvent; + tele->header = getHeader(a_radioTelegram, 3); + tele->charge.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(7, 4); + tele->charge.gearTasCode = a_radioTelegram->getPayloadDataUInt8(11); + tele->charge.chargeTypeId = a_radioTelegram->getPayloadDataUInt32(12, 2); + tele->chargeAmount = a_radioTelegram->getPayloadDataUInt32(14, 2); + const short remain = a_radioTelegram->getPayloadDataUInt32(16, 2); + tele->charge.remain = remain; + return tele; + } + + case GEF_SW_VERSIONSMELDUNG: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 8)) + return nullptr; + + auto tele = new ParticipantSwVersions; + tele->header = getHeader(a_radioTelegram, 3); + + const uint8_t versionsliste_len = a_radioTelegram->getPayloadDataUInt8(7); + tele->equipments.reserve(versionsliste_len); + for (uint32_t i = 0; i < versionsliste_len; i++) + { + const uint8_t iPos = 8 + i * 8; + EquipmentSwVersion ver; + ver.equipmentFunctionId = a_radioTelegram->getPayloadDataUInt8(iPos); + ver.subDeviceId = a_radioTelegram->getPayloadDataUInt8(iPos + 1); + ver.uniqueId = a_radioTelegram->getPayloadDataUInt32(iPos + 2, 4); + ver.swVersion = a_radioTelegram->getPayloadDataUInt32(iPos + 6, 2); + } + return tele; + } + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 19)) + return nullptr; + + auto tele = new SanitationRepair; + tele->header = getHeader(a_radioTelegram, 3); + tele->originatorType = static_cast( + a_radioTelegram->getPayloadDataUInt8(7)); + tele->equipmentNumberOrigin = a_radioTelegram->getPayloadDataUInt32(8, 2); + tele->stateStart = static_cast( + a_radioTelegram->getPayloadDataUInt8(10)); + unsigned int bitfield1 = a_radioTelegram->getPayloadDataUInt8(11); + tele->typeOfTreatment = bitfield1 & 0x7F; + tele->triage = (bitfield1 & 0x80) >> 7; + tele->tyeOfDamage = a_radioTelegram->getPayloadDataUInt8(12); + unsigned int bitfield2 = a_radioTelegram->getPayloadDataUInt8(13); + tele->stateResult = static_cast( + bitfield2 & 0x0F); + tele->treatmentResult + = static_cast( + (bitfield2 & 0x30) >> 4); + tele->triagePriority = ((bitfield2 & 0xC0) >> 6); + tele->fullState = a_radioTelegram->getPayloadDataUInt8(14); + tele->timeOfTreatment = a_radioTelegram->getPayloadDataUInt32(15, 2); + tele->timeOfRecovery = a_radioTelegram->getPayloadDataUInt32(17, 2); + return tele; + } + + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + { + if (!isPayloadLengthOk(a_radioTelegram, 15, 14, 1)) + return nullptr; + + auto tele = new SanitaryMaterialStockReport; + tele->header = getHeader(a_radioTelegram, 3); + + tele->uniqueId = a_radioTelegram->getPayloadDataUInt32(7, 4); + tele->originatorEquipmentNumber = a_radioTelegram->getPayloadDataUInt32(11, 2); + tele->qualification = static_cast(a_radioTelegram->getPayloadDataUInt8(13)); + + const uint16_t sanitaryMaterialCount = a_radioTelegram->getPayloadDataUInt8(14); + + tele->sanitaryMaterialCount = sanitaryMaterialCount; + double size = sanitaryMaterialCount; + + + if (tele->sanitaryMaterialCount != 0) + { + int pos = 15; + std::vector stock; + stock.reserve(sanitaryMaterialCount); + for (int i = 0; i < size; i++) + { + + unsigned int in = a_radioTelegram->getPayloadDataUInt8(pos++); + stock.emplace_back(in); + } + + tele->sanitaryMaterialStock = stock; + } + else + tele->sanitaryMaterialStock = std::vector(); + return tele; + } + + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + { + if (!isPayloadLengthOk(a_radioTelegram, 23)) + return nullptr; + auto tele = new Sanitation; + tele->header = getHeader(a_radioTelegram, 3); + + qint64 proceduresP1 = a_radioTelegram->getPayloadDataUInt32(7, 4); + qint64 proceduresP2 = a_radioTelegram->getPayloadDataUInt32(11, 4); + + tele->proceduresTaken = (proceduresP1 << 32) + proceduresP2; + + tele->uniqeId = a_radioTelegram->getPayloadDataUInt32(15, 4); + tele->originatorEquipmentNumber = a_radioTelegram->getPayloadDataUInt32(19, 2); + tele->qualification = static_cast(a_radioTelegram->getPayloadDataUInt8(21)); + quint8 enumByte = a_radioTelegram->getPayloadDataUInt8(22); + tele->sanitationEvaluation = static_cast((enumByte & 0xc0) >> 6); + tele->sanitationResult = static_cast(enumByte & 0x3f); + return tele; + } + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new EquipmentOperationalState; + tele->header = getHeader(a_radioTelegram, 3); + + + + + + + + uint8_t abcSchutz = a_radioTelegram->getPayloadDataUInt8(8); + + tele->nbcProtectionActive = checkBitmask(abcSchutz, 0x40); + return tele; + } + case GEF_FEHLERMELDUNG_GFD: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new CtaDataError; + tele->header = getHeader(a_radioTelegram, 3); + tele->reason = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + tele->originTelegramId = a_radioTelegram->getPayloadDataUInt8(8); + return tele; + } + case GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT: + { + if (!isPayloadLengthOk(a_radioTelegram, 31)) + return nullptr; + + auto tele = new RestoreRadioReadiness; + + tele->header = getHeader(a_radioTelegram, 3); + tele->readinessLossPosition = getRelativePosition(a_radioTelegram, 7); + tele->readinessLossTime = a_radioTelegram->getPayloadDataUInt32(13, 4); + tele->readinessRestorePosition = getRelativePosition(a_radioTelegram, 17); + tele->readinessRestoreTime = a_radioTelegram->getPayloadDataUInt32(23, 4); + + return tele; + } + case GEF_POSITIONS_MELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 14)) + return nullptr; + + auto tele = new PositionReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->gpsQuality = getGpsQuality(a_radioTelegram, 13); + return tele; + } + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + { + + if (!isPayloadLengthOk(a_radioTelegram, 15, 14, 2)) + return nullptr; + + auto tele = new PositionReportWithMountedEquipments; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + const uint8_t gps = a_radioTelegram->getPayloadDataUInt8(13); + tele->gpsQuality.moreThan4SatellitesAvailable = ((gps & 0x80) == 0x80); + tele->gpsQuality.dgpsModeAvailable = ((gps & 0x40) == 0x40); + tele->gpsQuality.pdopValue = (gps & 0x3f); + + const uint8_t aufgesessene_teilnehmer_len = a_radioTelegram->getPayloadDataUInt8(14); + tele->mountedEquipments.reserve(aufgesessene_teilnehmer_len); + + for (uint8_t i = 0; i < aufgesessene_teilnehmer_len; i++) + { + int eqId = a_radioTelegram->getPayloadDataUInt32(15 + 2 * i, 2); + tele->mountedEquipments.push_back(eqId); + } + return tele; + } + + + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + if (!isPayloadLengthOk(a_radioTelegram, 13)) + return nullptr; + + auto tele = new MineTriggered; + tele->header = getHeader(a_radioTelegram, 5); + tele->mineAreaId = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->mineIndex = a_radioTelegram->getPayloadDataUInt32(11, 2); + return tele; + } + case GEF_DEFINITION_IED: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new DefinitionIed; + tele->header = getHeader(a_radioTelegram, 3); + tele->iedId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->iedType = static_cast(a_radioTelegram->getPayloadDataUInt8(9)); + tele->trigger = a_radioTelegram->getPayloadDataUInt8(10); + tele->explosiveForce = a_radioTelegram->getPayloadDataUInt8(11); + tele->relPosition = getRelativePosition(a_radioTelegram, 12); + tele->partyId = a_radioTelegram->getPayloadDataUInt8(18); + tele->pairingState = static_cast(a_radioTelegram->getPayloadDataUInt8(19)); + tele->pairedId = a_radioTelegram->getPayloadDataUInt32(20, 2); + tele->tacticalState = static_cast(a_radioTelegram->getPayloadDataUInt8(22)); + tele->statePyrotechnics = a_radioTelegram->getPayloadDataUInt8(23); + + + fixupEnum(IedType::SuicideIed, IedType::IedBigPyro, IedType::SuicideIed, tele->iedType); + fixupEnum(IedPairingState::NotPaired, + IedPairingState::PairedToOps, + IedPairingState::NotPaired, + tele->pairingState); + fixupEnum(IedTacticalState::NotActive, + IedTacticalState::TriggeredByControlDevice, + IedTacticalState::Unknown, + tele->tacticalState); + return tele; + } + case GEF_ZUSTAND_IED: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new StateIed; + tele->header = getHeader(a_radioTelegram, 3); + tele->iedId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->tacticalState = static_cast(a_radioTelegram->getPayloadDataUInt8(9)); + tele->statePyrotechnics = a_radioTelegram->getPayloadDataUInt8(10); + tele->batteryWarnings = a_radioTelegram->getPayloadDataUInt8(11); + tele->errorStateElectronics = static_cast(a_radioTelegram->getPayloadDataUInt8(12)); + tele->errorStatePyrotechnics1 = static_cast(a_radioTelegram->getPayloadDataUInt8(13)); + tele->errorStatePyrotechnics2 = static_cast(a_radioTelegram->getPayloadDataUInt8(14)); + tele->errorStatePyrotechnics3 = static_cast(a_radioTelegram->getPayloadDataUInt8(15)); + + + fixupEnum(IedTacticalState::NotActive, + IedTacticalState::TriggeredByControlDevice, + IedTacticalState::Unknown, + tele->tacticalState); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStateElectronics); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics1); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics2); + fixupEnum(IedError::NoError, + IedError::DeviceMissing, + IedError::DeviceMissing, + tele->errorStatePyrotechnics3); + return tele; + } + case GEF_STATUS_EINZELMINENSIMULATOR: + { + if (!isPayloadLengthOk(a_radioTelegram, 17)) + return nullptr; + + auto tele = new DusSingleMineState; + tele->header = getHeader(a_radioTelegram, 3); + tele->mineId = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->relPosition = getRelativePosition(a_radioTelegram, 9); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt8(15); + tele->state = a_radioTelegram->getPayloadDataUInt8(16); + tele->effectStart = tele->header.timeStamp; + return tele; + } + case GEF_TREFFER_EREIGNIS_DUS: + { + if (!isPayloadLengthOk(a_radioTelegram, 23)) + return nullptr; + + auto tele = new StateChangeDirect; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getTaktZustand(a_radioTelegram, 13, tele); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt32(19, 2); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(21, 2); + return tele; + } + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + { + if (!isPayloadLengthOk(a_radioTelegram, 22)) + return nullptr; + + auto tele = new StateChangeIndirect; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getTaktZustand(a_radioTelegram, 13, tele); + + + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(20, 2); + return tele; + } + case GEF_SCHIEDSRICHTEREINGRIFF: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new OperatorAction; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->action = a_radioTelegram->getPayloadDataUInt8(13); + tele->operatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + return tele; + } + case GEF_TREFFER_EREIGNIS_DUS_IPS: + { + + if (!isPayloadLengthOk(a_radioTelegram, 18, 17, 2)) + return nullptr; + + auto tele = new StateChangeDirect; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + tele->chargeTypeId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(15, 2); + + size_t iPos = 17; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + return tele; + } + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + { + + if (!isPayloadLengthOk(a_radioTelegram, 17, 16, 2)) + return nullptr; + + auto tele = new StateChangeIndirect; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + + + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + size_t iPos = 16; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + tele->isSecondaryEffect = true; + return tele; + } + case GEF_TAKTISCHER_STATUS: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new StateChange; + tele->header = getHeader(a_radioTelegram, 3); + getTaktZustand(a_radioTelegram, 7, tele); + + tele->originatorType = static_cast( + a_radioTelegram->getPayloadDataUInt8(13)); + tele->originatorId = a_radioTelegram->getPayloadDataUInt32(14, 2); + return tele; + } + + case GEF_EINTRETEN_FUNKTIONSRAUM: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new FunctionalAreaEntry; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->aesDdsId = a_radioTelegram->getPayloadDataUInt32(13, 2); + return tele; + } + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + { + if (!isPayloadLengthOk(a_radioTelegram, 9)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + getSpecialSensorData(a_radioTelegram, 7, tele); + return tele; + } + case GEF_SONDERSENSORIK_FAHRSPUR: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + getSpecialSensorData(a_radioTelegram, 13, tele); + return tele; + } + case GEF_SONDERSENSORIK_DATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new SpecialSensorData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->type = a_radioTelegram->getPayloadDataUInt32(13, 1); + getSpecialSensorData(a_radioTelegram, 14, tele); + tele->nbcType = a_radioTelegram->getPayloadDataUInt32(16, 1); + return tele; + } + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new MinelayerTrailerData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->barrierId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->layingDensity = a_radioTelegram->getPayloadDataUInt32(15, 1); + tele->effectStart = a_radioTelegram->getPayloadDataUInt32(16, 4) * 1000LL; + tele->effectDuration = a_radioTelegram->getPayloadDataUInt32(20, 1); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(21, 1); + tele->mineCount = a_radioTelegram->getPayloadDataUInt32(22, 2); + return tele; + } + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + { + if (!isPayloadLengthOk(a_radioTelegram, 25)) + return nullptr; + + auto tele = new MinelayerThrowerData; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->barrierId = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->layingDensity = a_radioTelegram->getPayloadDataUInt32(15, 1); + tele->effectStart = a_radioTelegram->getPayloadDataUInt32(16, 4) * 1000LL; + tele->effectDuration = a_radioTelegram->getPayloadDataUInt32(20, 1); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(21, 1); + tele->throwingType = static_cast( + a_radioTelegram->getPayloadDataUInt32(22, 2)); + tele->mineCount = a_radioTelegram->getPayloadDataUInt32(23, 2); + return tele; + } + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + { + if (!isPayloadLengthOk(a_radioTelegram, 16)) + return nullptr; + + auto tele = new MinelayerTrailerPosition; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->dusSerialNo = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->indirectChargeTasCode = a_radioTelegram->getPayloadDataUInt32(15, 1); + return tele; + } + case GEF_DATENVERKEHR_SRT_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::OC; + tele->payload = getPayload(a_radioTelegram, 7); + return tele; + } + case GEF_DATENVERKEHR_DMF_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::FireSmokeMarker; + tele->payload = getPayload(a_radioTelegram, 7); + return tele; + } + case GEF_DATENVERKEHR_GEOP_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 14)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->gpsQuality = getGpsQuality(a_radioTelegram, 13); + tele->payloadType = OpaquePayloadDataBase::Type::Geopairing; + tele->payload = getPayload(a_radioTelegram, 14, 15); + return tele; + } + case GEF_DATENVERKEHR_TGTC_TDS: + { + if (!isPayloadLengthOk(a_radioTelegram, 7)) + return nullptr; + + auto tele = new OpaquePayloadDataIn; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->payloadType = OpaquePayloadDataBase::Type::Target; + tele->payload = getPayload(a_radioTelegram, 7, 8); + return tele; + } + case GEF_GERAETEEREIGNIS: + { + if (!isPayloadLengthOk(a_radioTelegram, 24)) + return nullptr; + + auto tele = new EquipmentEvent; + tele->header = getHeader(a_radioTelegram, 3); + tele->relPosition = getRelativePosition(a_radioTelegram, 7); + tele->equipmentFunctionId = a_radioTelegram->getPayloadDataUInt8(13); + tele->subDeviceId = a_radioTelegram->getPayloadDataUInt8(14); + tele->uniqueId = a_radioTelegram->getPayloadDataUInt32(15, 4); + tele->code = a_radioTelegram->getPayloadDataUInt8(23); + tele->payload = getPayload(a_radioTelegram, 24, 25); + return tele; + } + + case GEF_WAFFENZUORDNUNG: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 6)) + return nullptr; + + auto tele = new EquipmentGearAssignment; + tele->header = getHeader(a_radioTelegram, 3); + + const uint8_t waffen_len = a_radioTelegram->getPayloadDataUInt8(7); + tele->gears.reserve(waffen_len); + for (uint32_t i = 0; i < waffen_len && i < 10; i++) + { + const uint8_t iPos = 8 + i * 6; + + Gear gear; + gear.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(iPos, 4); + gear.gearTasCode = a_radioTelegram->getPayloadDataUInt8(iPos + 4); + gear.chargeCounting = a_radioTelegram->getPayloadDataUInt8(iPos + 5) != 0; + tele->gears.push_back(std::move(gear)); + } + return tele; + } + case GEF_IPS_POSITIONSDATEN: + { + + if (!isPayloadLengthOk(a_radioTelegram, 8, 7, 2)) + return nullptr; + + auto tele = new PositionReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->header.timeStamp + += 1; + size_t iPos = 7; + tele->opsPosition = getOpsPosition(a_radioTelegram, iPos); + if (tele->opsPosition.opsId == -1) + { + delete tele; + tele = nullptr; + } + return tele; + } + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + { + + constexpr int varSize = 5; + + if (!isPayloadLengthOk(a_radioTelegram, 13, 12, varSize)) + return nullptr; + + auto tele = new EquipmentGearChargeState; + tele->header = getHeader(a_radioTelegram, 3); + GearCharge gc; + gc.gearSerialNumber = a_radioTelegram->getPayloadDataUInt32(7, 4); + gc.gearTasCode = a_radioTelegram->getPayloadDataUInt8(11); + const uint8_t munitionsliste_len = a_radioTelegram->getPayloadDataUInt8(12); + tele->charges.reserve(munitionsliste_len); + for (uint32_t i = 0; i < munitionsliste_len; i++) + { + int iPos = 13; + const int offset = 5 * i; + gc.location = a_radioTelegram->getPayloadDataUInt8(iPos + offset); + iPos++; + short munitionsmenge = a_radioTelegram + ->getPayloadDataUInt32(iPos + offset, + 2); + iPos += 2; + gc.remain = munitionsmenge < 0 ? -1 : munitionsmenge; + gc.chargeTypeId = a_radioTelegram->getPayloadDataUInt32(iPos + offset, 2); + tele->charges.push_back(gc); + } + return tele; + } + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 13)) + return nullptr; + + auto tele = new CesHitRequest; + tele->header = getHeader(a_radioTelegram, 3); + tele->chargeTasCodeDirect = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->aesDdsId = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->aesType = static_cast(a_radioTelegram->getPayloadDataUInt8(11)); + tele->remainEffectTasCodeDirect = a_radioTelegram->getPayloadDataUInt8(12); + return tele; + } + case GEF_TEILNEHMERMODE_MELDUNG: + { + if (!isPayloadLengthOk(a_radioTelegram, 15)) + return nullptr; + + auto tele = new ParticipantModeReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->language = static_cast(a_radioTelegram->getPayloadDataUInt8(7)); + tele->operationMode = static_cast( + a_radioTelegram->getPayloadDataUInt8(8)); + tele->reactivationDetoxication = a_radioTelegram->getPayloadDataUInt8(9) + * 10; + tele->reactivationMaintenance = a_radioTelegram->getPayloadDataUInt8(10) + * 10; + tele->reactivationMedic = a_radioTelegram->getPayloadDataUInt8(11) * 10; + unsigned char wph_mode = a_radioTelegram->getPayloadDataUInt8(12); + tele->modeHelmet = static_cast(wph_mode & 0x03); + tele->modeVest = static_cast((wph_mode >> 2) & 0x03); + tele->personellProtectionMode = static_cast((wph_mode >> 4) & 0x07); + + unsigned char protection_mode = a_radioTelegram->getPayloadDataUInt8(13); + tele->protectionLevel = static_cast(protection_mode & 0x06); + tele->abcProtectionMode = static_cast((protection_mode >> 3) & 0x03); + + unsigned char specialFunction = a_radioTelegram->getPayloadDataUInt8( + 14); + tele->handgrenadeSearchMode = static_cast( + specialFunction & 0b11); + tele->internationalMode = static_cast( + (specialFunction >> 2) & 0b11); + return tele; + } + case GEF_TEILNEHMER_KONFIG_ANTWORT: + { + if (!isPayloadLengthOk(a_radioTelegram, 27)) + return nullptr; + + auto tele = new ParticipantConfigurationReport; + tele->header = getHeader(a_radioTelegram, 3); + tele->positionIntervallVehicle = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->positionIntervallPersonell = a_radioTelegram->getPayloadDataUInt32(9, 2); + tele->positionIntervallAircraft = a_radioTelegram->getPayloadDataUInt32(11, 2); + tele->positionTransmissionIntervall = a_radioTelegram->getPayloadDataUInt32(13, 2); + tele->heightbarrier = a_radioTelegram->getPayloadDataUInt32(15, 2); + unsigned char tmp = a_radioTelegram->getPayloadDataUInt8(17); + tele->faultPositionHandling = static_cast( + (tmp >> 6) & 0x03); + tele->switchingPositionIntervall + = static_cast( + tmp & 0x03); + tele->waittimeAdditionalBroadcastDemand = a_radioTelegram->getPayloadDataUInt32(18, 2); + tele->factorWaittimeIncreaseAtHighload = a_radioTelegram->getPayloadDataUInt8(20); + tele->waittimeAutomaticVulnerabilityIncreaseLevel1 = a_radioTelegram->getPayloadDataUInt8(21); + tele->waittimeAutomaticVulnerabilityIncreaseLevel2 = a_radioTelegram->getPayloadDataUInt8(22); + tele->waittimeAutomaticVulnerabilityIncreaseLevel3 = a_radioTelegram->getPayloadDataUInt8(23); + tele->opticalCode = static_cast( + a_radioTelegram->getPayloadDataUInt8(24)); + tele->vulnerabilityModel = a_radioTelegram->getPayloadDataUInt8(25); + tele->validTimeOps = a_radioTelegram->getPayloadDataUInt8(26); + return tele; + } + case GEF_ESW_MELDUNG: + + return nullptr; + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + { + if (!isPayloadLengthOk(a_radioTelegram, 10)) + return nullptr; + + auto tele = new RequestBroadcastTelegrams; + tele->header = getHeader(a_radioTelegram, 3); + tele->resetCounter = a_radioTelegram->getPayloadDataUInt8(7); + tele->broadcastIndex = a_radioTelegram->getPayloadDataUInt32(8, 2); + return tele; + } + case GEF_LASER_TARGET_DESIGNATOR_UPDATE: + { + auto tele = new ApacheLaserDesignation; + + tele->header = getHeader(a_radioTelegram, 3); + tele->code = a_radioTelegram->getPayloadDataUInt32(7, 2); + tele->outputPower = a_radioTelegram->getPayloadDataUInt8(9); + tele->gearId = a_radioTelegram->getPayloadDataUInt32(10, 4); + + return tele; + } + default: + { + ERROR_LOG(logger()) << "Conversion of Radio-Telegram to Central-Telegram with telId=" + << a_radioTelegram->getTelID() << " not implemented."; + } + } + return nullptr; +} + +} + +} diff --git a/TetraIF/CoPrtCnv/tetra_telegram_ids.h b/TetraIF/CoPrtCnv/tetra_telegram_ids.h new file mode 100644 index 000000000..f2a03acf8 --- /dev/null +++ b/TetraIF/CoPrtCnv/tetra_telegram_ids.h @@ -0,0 +1,116 @@ + + + +#pragma once + +enum gef_telegramm_id_et +{ + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + GEF_WIEDERHERSTELLUNG_FUNKBEREITSCHAFT = 13, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_IPS_POSITIONSDATEN = 201, + + GEF_SCHIEDSRICHTERKOMMANDO = 25, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFMITTEL = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTC_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTC = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_LASER_TARGET_DESIGNATOR_UPDATE = 214, + + GEF_GEFECHTSFELDTELEGRAMM = 300 +}; diff --git a/TetraIF/LogView/CMakeLists.txt b/TetraIF/LogView/CMakeLists.txt new file mode 100644 index 000000000..bd3ee7067 --- /dev/null +++ b/TetraIF/LogView/CMakeLists.txt @@ -0,0 +1,104 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# +ADD_SUBDIRECTORY(Console) +SET(my_SRCS + IntegerCalculator.cpp + IntegerCalculator.hpp + logger.cpp + logger.h + LogViewBooleanEdit.cpp + LogViewBooleanEdit.hpp + LogViewDateTimeEdit.cpp + LogViewDateTimeEdit.hpp + LogViewEnumEdit.cpp + LogViewEnumEdit.hpp + LogViewField.cpp + LogViewField.hpp + LogViewGui.cpp + LogViewGui.hpp + LogViewInjectionThread.cpp + LogViewInjectionThread.hpp + LogViewMain.cpp + LogViewModels.cpp + LogViewModels.hpp + LogViewOptionDialog.cpp + LogViewOptionDialog.hpp + LogViewSpinBox.cpp + LogViewSpinBox.hpp + LogViewTableWidget.cpp + LogViewTableWidget.hpp + LogViewTabWidget.cpp + LogViewTabWidget.hpp + LogViewTelegram.cpp + LogViewTelegramDialog.cpp + LogViewTelegramDialog.hpp + LogViewTelegramEdit.cpp + LogViewTelegramEdit.hpp + LogViewTelegramEditModel.cpp + LogViewTelegramEditModel.hpp + LogViewTelegram.hpp + LogViewTelegramSelectionDialog.cpp + LogViewTelegramSelectionDialog.hpp + LogViewTetraTelegramsParser.cpp + LogViewTetraTelegramsParser.hpp + LogViewTextEdit.cpp + LogViewTextEdit.hpp + LogViewValueEdit.cpp + LogViewValueEdit.hpp + LogViewWidget.cpp + LogViewWidget.hpp + LogViewXdrElement.cpp + LogViewXdrElement.hpp + LogViewXdrParser.cpp + LogViewXdrParser.hpp + LogViewXdrStandardType.cpp + LogViewXdrStandardType.hpp + LogViewXdrStruct.cpp + LogViewXdrStruct.hpp + LogViewXdrType.cpp + LogViewXdrType.hpp + LogViewXdrValue.cpp + LogViewXdrValue.hpp + zsksxd_tetraForLogView.x +) + +QT5_ADD_RESOURCES(my_SRCS LogViewResources.qrc) +NGL_ADD_TOOL_ICON(my_SRCS) +NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION LogView ${my_SRCS}) + +NGL_TARGET_LINK_LIBRARIES(LogView + Qt5::Core + Qt5::Gui + Qt5::Network + CoPrtCnv + nglwidgets + NGLLogger + nglapplication + ngltools +) +NGL_INSTALL_TARGET(LogView) +NGL_INSTALL(AAR SV FILES LogView_log4cxx.props DESTINATION bin) + + + +# install on RPM build and copy for local builds so that LogView automatically finds the zsksxd_tetraForLogView.x file +if (BUILD_RPM) + add_custom_target(zsksxd_tetraForLogView.x_bin) # empty target so that LogView still builds on RPM build + NGL_INSTALL(AAR SV FILES zsksxd_tetraForLogView.x DESTINATION bin) +else() + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/zsksxd_tetraForLogView.x + COMMENT "[Local build] Copy zsksxd_tetraForLogView.x for LogView into bin/" + ) + add_custom_target(zsksxd_tetraForLogView.x_bin DEPENDS ${CMAKE_BINARY_DIR}/bin/zsksxd_tetraForLogView.x) +endif() + +if (TARGET LogView) + add_dependencies(LogView zsksxd_tetraForLogView.x_bin training_area_telegrams.h_bin) +endif() + diff --git a/TetraIF/LogView/Console/CMakeLists.txt b/TetraIF/LogView/Console/CMakeLists.txt new file mode 100644 index 000000000..a2a9e61f2 --- /dev/null +++ b/TetraIF/LogView/Console/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(console_SRCS + main.cpp +) + +NGL_ADD_TOOL_ICON(console_SRCS) +NGL_ADD_EXECUTABLE(AAR SV LogView_console ${console_SRCS}) +NGL_INSTALL_TARGET(LogView_console) +NGL_TARGET_LINK_LIBRARIES(LogView_console + CoPrtCnv + NGLLogger +) diff --git a/TetraIF/LogView/Console/main.cpp b/TetraIF/LogView/Console/main.cpp new file mode 100644 index 000000000..fcdac2bc6 --- /dev/null +++ b/TetraIF/LogView/Console/main.cpp @@ -0,0 +1,201 @@ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static QSet s_eqIds; +template +bool validEqId(const T &tele) +{ + if (!s_eqIds.isEmpty() && !s_eqIds.contains(tele.header.equipmentNumber)) + return false; + return true; +} + +QByteArray formatTime(quint64 t) +{ + const quint64 secs = t >> 32; + const quint64 usecs = t & 0xFFFFFFFF; + const quint64 msecs = usecs / 1000; + return QDateTime::fromMSecsSinceEpoch(secs * 1000 + msecs).toString(QLatin1String("yy-MM-dd hh:mm:ss.zzz")).toUtf8(); +} + +int main(int argc, char **argv) +{ + using namespace TrainingAreaBase::TetraIcd; + + QCoreApplication app(argc, argv); + + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false); + + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + + if (app.arguments().count() < 3) + { + ERROR_LOG(logger) << "Usage: " << app.arguments().at(0) + << " "; + return 1; + } + + QFile telegramFile(app.arguments().at(1)); + if (!telegramFile.open(QIODevice::ReadOnly)) + { + ERROR_LOG(logger) << "Error opening " << telegramFile.fileName() + << " for reading: " << telegramFile.errorString(); + return 2; + } + bool bOk; + int telIdToSearch = app.arguments().at(2).toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Error reading telId - not a (valid) number: " + << app.arguments().at(2); + return 3; + } + s_eqIds.clear(); + for (int i = 3; i < app.arguments().size(); ++i) + { + int eqId = app.arguments().at(i).toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Error reading equipId - not a (valid) number: " + << app.arguments().at(i); + return 4; + } + s_eqIds += eqId; + } + + + while (true) + { + + N_CoPrtCnv::CoPrtCnvLogHeader lh; + if (sizeof(lh) == telegramFile.read((char *)&lh, sizeof(lh))) + { + if (lh.m_Version == 3) + { + + qint64 telegramLength = lh.m_Length - sizeof(lh); + QByteArray telegramData(telegramLength, Qt::Uninitialized); + if (telegramLength == telegramFile.read(telegramData.data(), telegramLength)) + { + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol dest = (N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol) + (lh.m_Protocol & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); + + switch (dest) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + { + const QJsonObject obj = QJsonDocument::fromJson(telegramData).object(); + int telId = obj.value(QStringLiteral("typeId")).toInt(); + if (telIdToSearch != telId) + continue; + + const QJsonObject objData = obj.value(QStringLiteral("data")).toObject(); + + const QByteArray tBA = formatTime(lh.m_Time); + const char *timeStr = tBA.constData(); + + switch (telId) + { + case Constraints::id(): + { + const CreateFunctionalArea tele(CreateFunctionalArea::fromJson(objData)); + if (!validEqId(tele)) + break; + fprintf(stdout, "%s, FUNKTIONSRAUM: '%s', %d, %d\n", + timeStr, + tele.name.c_str(), + tele.aesDdsId, + tele.header.equipmentNumber + ); + break; + } + case Constraints::id(): + { + const DeactivateEffectSimulation tele(DeactivateEffectSimulation::fromJson(objData)); + fprintf(stdout, "%s, DEAKTIVIERUNG_WIRKFELD: typ: %d - kennung: %d\n", + timeStr, + int(tele.aesType), + tele.aesDdsId + ); + break; + } + case Constraints::id(): + { + const PositionReport tele(PositionReport::fromJson(objData)); + if (!validEqId(tele)) + break; + if (tele.opsPosition.opsId == 0) + break; + fprintf(stdout, "%s, IPS_POSITIONSDATEN: %d - OPS: %d\n", + timeStr, + tele.header.equipmentNumber, + tele.opsPosition.opsId + ); + break; + } + case BESTAETIGUNG: + case UMGEBUNGS_MELDUNG2: + break; + default: + fprintf(stderr, "Printing telegram with id %d not implemented\n", telId); + break; + + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(telegramData); + gef_telegramm_id_et telId = radioTelegram.getTelID(); + if (telId == GEF_UMGEBUNGS_MELDUNG2) + { + const QByteArray tBA = formatTime(lh.m_Time); + const char *timeStr = tBA.constData(); + static uint16_t bci = 0xFFFF; + if (bci != radioTelegram.getBroadcastIndex()) + { + if (bci > radioTelegram.getBroadcastIndex() && bci != 0xFFFF) + { + fprintf(stdout, "BCI reset in %s at %s!\n", + qPrintable(telegramFile.fileName()), + timeStr); + } + fprintf(stdout, "BCI: %d\n", radioTelegram.getBroadcastIndex()); + bci = radioTelegram.getBroadcastIndex(); + } + } + break; + } + default: + break; + } + } + } + else + { + ERROR_LOG(logger) << "Wrong LogHeader version: " << lh.m_Version; + return 4; + } + } + else + break; + } + return 0; +} diff --git a/TetraIF/LogView/IntegerCalculator.cpp b/TetraIF/LogView/IntegerCalculator.cpp new file mode 100644 index 000000000..a31e417e0 --- /dev/null +++ b/TetraIF/LogView/IntegerCalculator.cpp @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + +#include "IntegerCalculator.hpp" + +#include +#include + +namespace N_SST +{ +IntegerCalculator::IntegerCalculator() + : m_OperationList({{"*", 6},{"/", 6},{"%", 6},{"+", 5},{"-", 5},{"<<", 4},{">>", 4}}) + , m_AdditionalErrorText() + , m_ParanthesisCount(0) + , m_Error(IntegerCalculator::e_Ok) +{ +} + + + + + + + + +int64_t IntegerCalculator::calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText) +{ + std::string calcText = a_calcText; + + for (auto iter = m_OperationList.begin(); iter != m_OperationList.end(); ++iter) + replace(calcText, iter->first, " "+iter->first+" "); + + + replace(calcText, "(", " ( "); + replace(calcText, ")", " ) "); + + + + m_ParanthesisCount = 0; + m_Error = e_Ok; + m_AdditionalErrorText = ""; + size_t pos = 0; + bool dummy; + int64_t value = calc(calcText, pos, dummy, "", 0, "+"); + + + + if (m_Error == e_Ok) + { + if (m_ParanthesisCount > 0) + { + m_Error = e_MissingRightParanthesis; + } + else if (m_ParanthesisCount < 0) + { + m_Error = e_MissingLeftParanthesis; + } + else if (pos != calcText.length()) + { + m_Error = e_UnknownError; + } + } + + + a_error = m_Error; + if (a_error != e_Ok) + { + value = 0; + if (a_addErrorText) + { + *a_addErrorText = m_AdditionalErrorText; + } + } + return value; +} + + + + +void IntegerCalculator::addVariable(const std::string& a_name, const int64_t a_value) +{ + std::map::iterator iter = m_VariableList.find(a_name); + if (iter != m_VariableList.end()) + removeVariable(a_name); + m_VariableList.insert(std::make_pair(a_name, a_value)); +} + + + + + +void IntegerCalculator::removeVariable(const std::string& a_name) +{ + std::map::iterator iter = m_VariableList.find(a_name); + if (iter != m_VariableList.end()) + m_VariableList.erase(iter); +} + + + + + +int64_t IntegerCalculator::calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, + const std::string& a_prevOp, const int64_t a_prevValue, + const std::string& a_initOp) +{ + std::string operation = a_initOp; + int64_t value1 = a_prevValue; + bool isNegative = false; + std::string calcText = a_calcText; + a_IsEndParanthesis = false; + + while (a_pos < calcText.length()) + { + if (' ' == calcText[a_pos]) + { + a_pos++; + } + else if ('(' == calcText[a_pos]) + { + m_ParanthesisCount++; + bool dummy; + int64_t value2 = calcSign(calc(calcText, ++a_pos, dummy), isNegative); + value1 = doOperation(value1, operation, value2); + + + size_t tmpPos = a_pos; + std::string nextOp = getToken(a_calcText, tmpPos); + if (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp)) + { + + return value1; + } + + operation = ""; + } + else if (')' == calcText[a_pos]) + { + m_ParanthesisCount--; + a_pos++; + a_IsEndParanthesis = true; + return value1; + } + else if (isDigit(calcText[a_pos])) + { + + + int64_t value2 = calcSign(convertValue(calcText, a_pos), isNegative); + if (calcWithPriority(calcText, a_pos, value1, operation, value2, a_prevOp)) return value1; + } + else + { + + + std::string oldOperation = operation; + operation = getToken(calcText, a_pos); + + + if (!isOperation(operation)) + { + int64_t value2 = 0; + if (getVariableValue(operation, value2)) + { + value2 = calcSign(value2, isNegative); + if (calcWithPriority(calcText, a_pos, value1, oldOperation, value2, a_prevOp)) return value1; + operation = ""; + } + else + { + + m_Error = e_UnknownOperationOrVariable; + m_AdditionalErrorText = operation; + } + } + else + { + + if (oldOperation != "") + { + if (operation == "+") + { + operation = oldOperation; + } + else if (operation == "-") + { + isNegative = !isNegative; + operation = oldOperation; + } + else + { + m_Error = e_NoOperandBetweenOperators; + m_AdditionalErrorText = oldOperation + " " + operation; + return 0; + } + } + } + } + } + return value1; +} + + + + + + +bool IntegerCalculator::calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, std::string& a_operation, int64_t a_value2, const std::string& a_prevOp) +{ + bool isParaEnd = false; + + size_t tmpPos = a_pos; + std::string nextOp = getToken(a_calcText, tmpPos); + if (isOperation(a_operation) && isOperation(nextOp) && isOperationPriorityHigher(nextOp, a_operation)) + { + + a_value2 = calc(a_calcText, a_pos, isParaEnd, a_operation, a_value2); + } + a_value1 = doOperation(a_value1, a_operation, a_value2); + if (isParaEnd || (isOperation(nextOp) && isOperation(a_prevOp) && !isOperationPriorityHigher(nextOp, a_prevOp))) + { + + return true; + } + a_operation = ""; + return false; +} + + + + + + + + +int64_t IntegerCalculator::calcSign(const int64_t a_value, bool& a_isNegative) +{ + if (a_isNegative) + { + a_isNegative = false; + return -a_value; + } + return a_value; +} + + + + + + +int64_t IntegerCalculator::convertValue(const std::string &a_valueText, size_t& a_pos) +{ + std::string valueText = a_valueText.substr(a_pos); + int base = 10; + size_t startpos = 0; + + bool isHex = (0 == valueText.find("0X")) || (0 == valueText.find("0x")); + bool isBin = (0 == valueText.find("0B")) || (0 == valueText.find("0b")); + if (isHex) + { + base = 16; + startpos = 2; + } + else if (isBin) + { + base = 2; + startpos = 2; + } + + size_t i; + for (i=startpos; i i && valueText[i] != ' ') + { + m_Error = e_InvalidOperand; + int spacePos = valueText.find(' '); + m_AdditionalErrorText = valueText.substr(0, spacePos); + } + a_pos += i; + + int64_t value = 0; + std::stringstream stream; + stream.str(valueText.substr(startpos, i-startpos)); + if (2 == base) + { + + const std::string binValueAsText = stream.str(); + for (const char c : binValueAsText) + { + value = value << 1; + if (c == '1') + value += 1; + } + } + else + { + stream << std::setbase(base); + stream >> value; + } + return value; +} + + + + + + +std::string IntegerCalculator::getToken(const std::string &a_calcText, size_t& a_pos) +{ + + while (a_pos < a_calcText.length()) + { + if (a_calcText[a_pos] == ' ') a_pos++; + else break; + } + + + size_t startPos = a_pos; + while (a_pos < a_calcText.length()) + { + if (' ' == a_calcText[a_pos]) break; + a_pos++; + } + return a_calcText.substr(startPos, a_pos-startPos); +} + + + + + +bool IntegerCalculator::isOperation(const std::string& a_operation) const +{ + std::map::const_iterator iter = m_OperationList.find(a_operation); + return (iter != m_OperationList.end()); +} + + + + + + +int64_t IntegerCalculator::doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2) +{ + + if (("+" == a_operation) || a_operation.empty()) + { + return a_value1 + a_value2; + } + else if ("-" == a_operation) + { + return a_value1 - a_value2; + } + else if ("*" == a_operation) + { + return a_value1 * a_value2; + } + else if ("/" == a_operation) + { + if (0 == a_value2) + { + m_Error = e_DivisionByZero; + } + else + { + return a_value1 / a_value2; + } + } + else if ("%" == a_operation) + { + if (0 == a_value2) + { + m_Error = e_DivisionByZero; + } + else + { + return a_value1 % a_value2; + } + } + else if ("<<" == a_operation) + { + return a_value1 << a_value2; + } + else if (">>" == a_operation) + { + return a_value1 >> a_value2; + } + else + { + m_Error = e_UnknownOperationOrVariable; + m_AdditionalErrorText = a_operation; + } + return 0; +} + + + + + + +bool IntegerCalculator::isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const +{ + return (getPriority(a_operation1) > getPriority(a_operation2)); +} + + + + + + + + + +bool IntegerCalculator::getVariableValue(const std::string& a_variableName, int64_t& a_value) const +{ + auto iter = m_VariableList.find(a_variableName); + if (iter != m_VariableList.end()) + { + a_value = iter->second; + return true; + } + + + return false; +} + + + + + + + +bool IntegerCalculator::isDigit(const char a_char, const bool a_isHex, const bool a_isBin) +{ + if (a_isHex) + { + + return (a_char >= '0' && a_char <= '9') || (a_char >= 'A' && a_char <= 'F') || (a_char >= 'a' && a_char <= 'f'); + } + else if (a_isBin) + { + + return (a_char >= '0' && a_char <= '1'); + } + + return (a_char >= '0' && a_char <= '9'); +} + + + + + + +int16_t IntegerCalculator::getPriority(const std::string& a_operation) const +{ + std::map::const_iterator iter = m_OperationList.find(a_operation); + if (iter != m_OperationList.end()) + return iter->second; + + return -1; +} + + + + + + +void IntegerCalculator::replace(std::string& a_haystack, const std::string &a_searchText, const std::string &a_replaceText) +{ + std::string::size_type searchSize = a_searchText.length(); + std::string::size_type replaceSize = a_replaceText.length(); + + std::string::size_type pos = a_haystack.find(a_searchText, 0); + while (std::string::npos != pos) + { + a_haystack.replace(pos, searchSize, a_replaceText); + pos += replaceSize; + pos = a_haystack.find(a_searchText, pos); + } +} + +} diff --git a/TetraIF/LogView/IntegerCalculator.hpp b/TetraIF/LogView/IntegerCalculator.hpp new file mode 100644 index 000000000..22fbf2db7 --- /dev/null +++ b/TetraIF/LogView/IntegerCalculator.hpp @@ -0,0 +1,143 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include + +namespace N_SST +{ + + + class IntegerCalculator + { + public: + + + + enum E_Error + { + + + e_Ok, + + + e_DivisionByZero, + + + e_UnknownOperationOrVariable, + + + e_NoOperandBetweenOperators, + + + e_InvalidOperand, + + + e_MissingLeftParanthesis, + + + e_MissingRightParanthesis, + + + e_UnknownError + }; + + + IntegerCalculator(); + virtual ~IntegerCalculator() = default; + + + + int64_t calc(const std::string& a_calcText, E_Error& a_error, std::string* a_addErrorText = nullptr); + + + + void addVariable(const std::string& a_name, const int64_t a_value); + + + + void removeVariable(const std::string& a_name); + + protected: + + + + const std::map m_OperationList; + + + std::map m_VariableList; + + + std::string m_AdditionalErrorText; + + + int32_t m_ParanthesisCount; + E_Error m_Error; + + + + + int64_t calc(const std::string& a_calcText, size_t& a_pos, bool& a_IsEndParanthesis, + const std::string& a_prevOp = std::string(), const int64_t a_prevValue = 0, + const std::string& a_initOp = std::string()); + + + + bool calcWithPriority(const std::string& a_calcText, size_t& a_pos, int64_t& a_value1, + std::string& a_operation, int64_t a_value2, const std::string& a_prevOp); + + + + static int64_t calcSign(const int64_t a_value, bool& a_isNegative); + + + + int64_t convertValue(const std::string& a_valueText, size_t& a_pos); + + + + static std::string getToken(const std::string& a_calcText, size_t& a_pos); + + + + bool isOperation(const std::string& a_operation) const; + + + + int64_t doOperation(const int64_t a_value1, const std::string& a_operation, const int64_t a_value2); + + + + bool isOperationPriorityHigher(const std::string& a_operation1, const std::string& a_operation2) const; + + + + virtual bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const; + + + + static bool isDigit(const char a_char, const bool a_isHex = false, const bool a_isBin = false); + + + + int16_t getPriority(const std::string& a_operation) const; + + + + static void replace(std::string& a_haystack, const std::string& a_searchText, const std::string& a_replaceText); + + }; + +} diff --git a/TetraIF/LogView/LogViewBooleanEdit.cpp b/TetraIF/LogView/LogViewBooleanEdit.cpp new file mode 100644 index 000000000..4b3ec1b6b --- /dev/null +++ b/TetraIF/LogView/LogViewBooleanEdit.cpp @@ -0,0 +1,36 @@ + + + +#include "LogViewBooleanEdit.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewBooleanEdit::LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QCheckBox (a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + const QString valueText = a_field->value(0); + + setChecked(valueText.toInt() == 1); + setEnabled(!a_readonly); +} + + +bool LogViewBooleanEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (m_Valid) + { + if (a_telegram->isJsonTelegram()) + a_telegram->setJsonValue(m_Field->jsonPath(), isChecked()); + else + a_telegram->setUIntX(getSize(), isChecked()); + return true; + } + return false; +} + +} diff --git a/TetraIF/LogView/LogViewBooleanEdit.hpp b/TetraIF/LogView/LogViewBooleanEdit.hpp new file mode 100644 index 000000000..abcba5c04 --- /dev/null +++ b/TetraIF/LogView/LogViewBooleanEdit.hpp @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + class LogViewBooleanEdit : public QCheckBox, public LogViewWidget + { + Q_OBJECT + public: + LogViewBooleanEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + bool saveContent(LogViewTelegram* a_telegram) override; + }; + +} diff --git a/TetraIF/LogView/LogViewDateTimeEdit.cpp b/TetraIF/LogView/LogViewDateTimeEdit.cpp new file mode 100644 index 000000000..b3af104e4 --- /dev/null +++ b/TetraIF/LogView/LogViewDateTimeEdit.cpp @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + +#include "LogViewDateTimeEdit.hpp" +#include +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewDateTimeEdit::LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QDateTimeEdit(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + if (a_readonly) + { + setReadOnly(true); + setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft); + } + + + qint64 unixTime = 0; + if (a_field->hasContent()) + { + if (a_field->isMSecsField()) + unixTime = a_field->value(0, true).toLongLong(); + else + unixTime = a_field->value(0, true).toInt() * 1000LL; + } + + if (0 == unixTime && !a_readonly) + unixTime = ::time(nullptr) * 1000LL; + + + setDateTime(QDateTime::fromMSecsSinceEpoch(unixTime)); + setDisplayFormat(QLatin1String("dd MMM yyyy hh:mm:ss")); + setCalendarPopup(true); + updateToolTip(QString::number(unixTime)); + + + + connect(this, &LogViewDateTimeEdit::editingFinished, + this, &LogViewDateTimeEdit::checkAndOvertakeContent); +} + + + +void LogViewDateTimeEdit::checkAndOvertakeContent() +{ + updateToolTip(QString::number(dateTime().toMSecsSinceEpoch() / 1000)); +} + + + + + + +bool LogViewDateTimeEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (a_telegram->isJsonTelegram()) + { + a_telegram->setJsonValue(m_Field->jsonPath(), dateTime().toMSecsSinceEpoch()); + } + else + { + a_telegram->setNextFieldAsGpsTimeField(); + a_telegram->setUIntX(getSize(), dateTime().toMSecsSinceEpoch() / 1000); + } + return true; +} + +} + diff --git a/TetraIF/LogView/LogViewDateTimeEdit.hpp b/TetraIF/LogView/LogViewDateTimeEdit.hpp new file mode 100644 index 000000000..a77b3b562 --- /dev/null +++ b/TetraIF/LogView/LogViewDateTimeEdit.hpp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewDateTimeEdit : public QDateTimeEdit, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewDateTimeEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + public slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewEnumEdit.cpp b/TetraIF/LogView/LogViewEnumEdit.cpp new file mode 100644 index 000000000..8f8da7b96 --- /dev/null +++ b/TetraIF/LogView/LogViewEnumEdit.cpp @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + +#include "LogViewEnumEdit.hpp" +#include "LogViewXdrStruct.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + + +namespace N_LogView +{ + + + +LogViewEnumEdit::LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index) + : QComboBox(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + QString value = a_field->value(a_index); + + + setToolTip(a_field->toolTipText()); + + + bool bCurrentIndexSet = false; + int i = 0; + while (LogViewXdrValue* child = (static_cast(a_field->xdrElement()))->getChildAsValue(i++)) + { + QString enumText = LogViewField::makeClean(child->getName()); + if (!a_readonly || enumText == value) + { + addItem(QStringLiteral("%1 (%2)").arg(enumText).arg(child->getValue()), QVariant::fromValue(child->getValue())); + if (a_readonly) + bCurrentIndexSet = true; + } + + if (enumText == value) + { + setCurrentIndex(a_readonly ? 0 : i - 1); + bCurrentIndexSet = true; + if (!a_readonly || (0 != a_index)) + updateToolTip(itemData(currentIndex()).toString()); + } + } + + if (!bCurrentIndexSet) + { + addItem(value); + setCurrentIndex(findText(value)); + } + + + connect(this, QOverload::of(&LogViewEnumEdit::currentIndexChanged), + this, &LogViewEnumEdit::checkAndOvertakeContent); +} + + + +uint16_t LogViewEnumEdit::getSize() const +{ + + const LogViewXdrStruct* xdrStruct = static_cast(m_Field->xdrElement()); + return xdrStruct->getEnumSize(); +} + + + +void LogViewEnumEdit::checkAndOvertakeContent() +{ + updateToolTip(itemData(currentIndex()).toString()); +} + + + + + + +bool LogViewEnumEdit::saveContent(LogViewTelegram* a_telegram) +{ + bool ok; + int value = itemData(currentIndex()).toInt(&ok); + if (ok) + { + if (a_telegram->isJsonTelegram()) + a_telegram->setJsonValue(m_Field->jsonPath(), value); + else + a_telegram->setUIntX(getSize(), value); + return true; + } + return false; +} + +} diff --git a/TetraIF/LogView/LogViewEnumEdit.hpp b/TetraIF/LogView/LogViewEnumEdit.hpp new file mode 100644 index 000000000..6198720e1 --- /dev/null +++ b/TetraIF/LogView/LogViewEnumEdit.hpp @@ -0,0 +1,43 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewEnumEdit : public QComboBox, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewEnumEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly, const int a_index); + + + uint16_t getSize() const override; + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + protected slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewField.cpp b/TetraIF/LogView/LogViewField.cpp new file mode 100644 index 000000000..4646f018f --- /dev/null +++ b/TetraIF/LogView/LogViewField.cpp @@ -0,0 +1,275 @@ + + + + + + + + + + + + + +#include "LogViewField.hpp" +#include +#include "LogViewXdrElement.hpp" +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + + +LogViewField::LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement) + : m_Name(a_name), + m_IsRightAligned(false), + m_Offset(0), + m_Size(0), + m_MaxArraySize(0), + m_IsDynamicArray(false), + m_HasContent(true), + m_bDeleteXdr(false), + m_Kind(a_kind), + m_XdrElement(a_xdrElement), + m_logger(getLogger("LogViewField")) +{ +} + + +LogViewField::~LogViewField() +{ + for (LogViewField *f : qAsConst(m_Child)) + delete f; + if (m_bDeleteXdr) + delete m_XdrElement; +} + +LogViewField *LogViewField::clone(int arrayIdx) const +{ + LogViewField *f = new LogViewField(*this); + f->m_Child.clear(); + f->m_bDeleteXdr = false; + for (auto * c : m_Child) + { + auto *clonedChild = c->clone(-1); + if (arrayIdx >= 0) + { + QStringList sl = clonedChild->jsonPath(); + if (sl.size() > 1 && sl.at(sl.size() - 2).startsWith(QStringLiteral("index: "))) + { + sl[sl.size() - 2] = QStringLiteral("index: %1").arg(arrayIdx); + clonedChild->setJsonPath(sl); + } + } + f->addChild(clonedChild); + } + for (auto &val : f->m_ValueList) + val.clear(); + return f; +} + + + +void LogViewField::addChild(LogViewField* a_child) +{ + if (a_child) + m_Child.push_back(a_child); +} + + +void LogViewField::removeLastChild() +{ + if (m_Child.empty()) + return; + delete m_Child.takeLast(); +} + + + +LogViewField* LogViewField::child(int arrayIdx) +{ + if (m_Child.size() > arrayIdx) + return m_Child.at(arrayIdx); + return nullptr; +} + + +void LogViewField::addValue(const QString &value) +{ + m_ValueList.append(value); +} + + +void LogViewField::addValueBinaryHex(const QString &value) +{ + const QByteArray ba = QByteArray::fromHex(value.toLatin1()); + for (const char c : ba) + m_ValueList.append(QString::number(static_cast(c))); +} + + + + + + + + + +QString LogViewField::value(int arrayIdx, const bool a_doNotMakeSpecialConversions) const +{ + if (m_ValueList.size() > arrayIdx) + { + const QString &ret = m_ValueList.at(arrayIdx); + if (!a_doNotMakeSpecialConversions) + { + if (isDateTimeField()) + return QDateTime::fromMSecsSinceEpoch(ret.toLongLong() * 1000).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz")); + if (isMSecsField()) + return QDateTime::fromMSecsSinceEpoch(ret.toLongLong()).toString(QStringLiteral("dd.mm.yy hh:mm:ss.zzz")); + } + return ret; + } + return QString(); +} + + +int64_t LogViewField::getHighestValue() const +{ + switch (m_XdrElement->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + { + int64_t highest = 1; + + uint16_t bitSize = 8*static_cast(m_XdrElement)->getEditSize(); + + if ((0 == m_Name.compare(QLatin1String("utm nordwert"), Qt::CaseInsensitive)) || + (0 == m_Name.compare(QLatin1String("utm ostwert"), Qt::CaseInsensitive))) + bitSize -= 8; + + switch (static_cast(m_XdrElement)->getValueKind()) { + case LogViewXdrStandardType::e_Boolean: + return 1; + case LogViewXdrStandardType::e_Signed: + bitSize--; + Q_FALLTHROUGH(); + case LogViewXdrStandardType::e_Unsigned: + case LogViewXdrStandardType::e_Data: + highest = highest << bitSize; + highest--; + break; + default: + highest = 0; + break; + } + return highest; + } + default: + ERROR_LOG(m_logger) << "Case not implemented"; + } + return 0; +} + + + +int64_t LogViewField::getLowestValue() const +{ + switch (m_XdrElement->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + { + int64_t lowest = 0; + + switch (static_cast(m_XdrElement)->getValueKind()) { + case LogViewXdrStandardType::e_Boolean: + return 0; + case LogViewXdrStandardType::e_Signed: + lowest = getHighestValue() + 1; + lowest = -lowest; + break; + default: + break; + } + return lowest; + } + default: + ERROR_LOG(m_logger) << "Case not implemented"; + break; + } + return 0; +} + + + +void LogViewField::dump(const QString &a_indent) const +{ + INFO_LOG(m_logger) << a_indent << "["; + INFO_LOG(m_logger) << a_indent << "Field[" << m_Name << "]: m_Kind=" << m_Kind << " m_Offset=" << m_Offset << " m_Size=" << m_Size << " m_MaxArraySize=" << m_MaxArraySize << " m_IsRightAligned=" << m_IsRightAligned << " m_IsDynamicArray=" << m_IsDynamicArray << " m_ToolTipText=" << m_ToolTipText; + + for (int i=0; i pos) + { + a_uncleanText[pos] = a_uncleanText[pos].toUpper(); + pos = a_uncleanText.indexOf(QLatin1Char(' '), pos + 1); + if (-1 == pos) + break; + pos++; + } + + return a_uncleanText; +} + + + + + +bool LogViewField::isDateTimeField() const +{ + QString name = m_Name.toLower(); + return name == QLatin1String("gps_zeit"); +} + +bool LogViewField::isMSecsField() const +{ + QString name = m_Name.toLower(); + return (name == QLatin1String("timestamp")) || (name == QLatin1String("effectstart")); +} + + + +void LogViewField::setMaxArraySize(uint16_t newVal, const bool a_isDynamic) +{ + m_MaxArraySize = newVal; + m_IsDynamicArray = a_isDynamic; +} + +} diff --git a/TetraIF/LogView/LogViewField.hpp b/TetraIF/LogView/LogViewField.hpp new file mode 100644 index 000000000..e9c4e8cfe --- /dev/null +++ b/TetraIF/LogView/LogViewField.hpp @@ -0,0 +1,142 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include "logger.h" + +namespace N_LogView +{ + class LogViewXdrElement; + class LogViewField + { + public: + enum E_FieldKind + { + e_FieldKindBorder, + e_FieldKindEdit, + e_FieldKindTab, + e_FieldKindTabChild, + e_FieldKindPodArray, + e_FieldKindPodArrayChild + }; + + + LogViewField(const QString& a_name, const E_FieldKind a_kind, const LogViewXdrElement* a_xdrElement); + virtual ~LogViewField(); + + LogViewField *clone(int arrayIdx) const; + + QString cleanName() const { return makeClean(m_Name); } + QString name() const { return m_Name; } + void setName(const QString &newVal) { m_Name = newVal; } + + + void addChild(LogViewField* a_child); + void removeLastChild(); + LogViewField *child(int arrayIdx); + int childCount() const { return m_Child.size(); } + + QString type() const { return m_type; } + void setType(const QString &type) { m_type = type; } + + LogViewField::E_FieldKind kind() const { return m_Kind; } + + void addValue(const QString &value); + void addValueBinaryHex(const QString &value); + + + + QString value(int arrayIdx, const bool a_doNotMakeSpecialConversions = false) const; + int valueListSize() const { return m_ValueList.size(); } + + + bool isRightAligned() const { return m_IsRightAligned; } + void setIsRightAligned(bool newVal) { m_IsRightAligned = newVal; } + + + QString toolTipText() const { return m_ToolTipText; } + void setToolTipText(const QString &newVal) { m_ToolTipText = newVal; } + + + int64_t getHighestValue() const; + int64_t getLowestValue() const; + + + + void dump(const QString &a_indent = QString()) const; + + + + static QString makeClean(const QString &text); + + + int size() const { return m_Size; } + void setSize(int newVal) { m_Size = newVal; } + + + const LogViewXdrElement* xdrElement() const { return m_XdrElement; } + + + + bool isDateTimeField() const; + bool isMSecsField() const; + + + uint16_t maxArraySize() const { return m_MaxArraySize; } + void setMaxArraySize(uint16_t newVal, const bool a_isDynamic); + + + + bool isDynamicArray() const { return m_IsDynamicArray; } + + + bool hasContent() const { return m_HasContent; } + void setHasContent(bool newVal) { m_HasContent = newVal; } + + void setDeleteXdr(bool bDelete) { m_bDeleteXdr = bDelete; } + + void setJsonPath(const QStringList &path) { m_jsonPath = path; } + QStringList jsonPath() const { return m_jsonPath; } + + protected: + + QString m_Name; + QString m_type; + QStringList m_ValueList; + QStringList m_jsonPath; + bool m_IsRightAligned; + QString m_ToolTipText; + uint16_t m_Offset; + int m_Size; + uint16_t m_MaxArraySize; + + + bool m_IsDynamicArray; + bool m_HasContent; + bool m_bDeleteXdr; + QVector m_Child; + + E_FieldKind m_Kind; + + const LogViewXdrElement *m_XdrElement; + + private: + + + NGL::INGLLogger &m_logger; + + }; +} diff --git a/TetraIF/LogView/LogViewGui.cpp b/TetraIF/LogView/LogViewGui.cpp new file mode 100644 index 000000000..439fa873b --- /dev/null +++ b/TetraIF/LogView/LogViewGui.cpp @@ -0,0 +1,1013 @@ + + + + + + + + + + + + + + +#include "LogViewGui.hpp" + +#include "LogViewTelegram.hpp" +#include "LogViewXdrParser.hpp" +#include "LogViewTelegramDialog.hpp" +#include "LogViewOptionDialog.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LogViewInjectionThread.hpp" +#include "LogViewTelegramEdit.hpp" +#include "LogViewTetraTelegramsParser.hpp" +#include + +namespace N_LogView +{ + + +const QLatin1String LogViewGui::WINDOW_GROUP("MainWindow"); +const QLatin1String LogViewGui::SIZE("Size"); +const QLatin1String LogViewGui::SCREEN("Screen"); +const QLatin1String LogViewGui::POS("Pos"); +const QLatin1String LogViewGui::SPLITTPOS("SplittPos"); +const QLatin1String LogViewGui::TOOLBOXINDEX("ToolBoxIndex"); + + + + + +LogViewGui::LogViewGui(QWidget* a_parent) + : QMainWindow(a_parent) + , RADIO_BUTTON_ICON_SIZE(16, 16) + , m_LogfileSize(0) + , m_DoReload(false) + , m_EditTelegramController(new TelegramEdit(this)) + , m_TailTimer(nullptr) + , m_InjectionThread(nullptr) + , m_replayTimer(new QTimer(this)) + , m_currentReplayRow(-1) + , m_logger(getLogger("LogViewGui")) +{ + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); + + QSettings settings; + settings.beginGroup(WINDOW_GROUP); + + + m_InjectionStatus = new QLabel(this); + m_InjectionStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_InjectionStatus); + m_ParticipantStatus = new QLabel(this); + m_ParticipantStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_ParticipantStatus); + m_TelegramStatus = new QLabel(this); + m_TelegramStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); + statusBar()->addPermanentWidget(m_TelegramStatus); + + + + QToolBar* toolBar = addToolBar(tr("Datei")); + toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + QString tipText; + QAction* action = new QAction(tr("Neue Log-Datei"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/document-new.png"))); + action->setShortcut(tr("Ctrl+N")); + tipText = tr("Eine neue Telegram-Log-Datei anzeigen (Ctrl-N)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::newTelegramFile); + toolBar->addAction(action); + + action = new QAction(tr("Log-Datei hinzu"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/document-import.png"))); + action->setShortcut(tr("Ctrl+O")); + tipText = tr("Eine weitere Telegramm-Log-Datei anzeigen (Ctrl-O)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::loadTelegramFile); + toolBar->addAction(action); + + m_reloadAction = new QAction(tr("&Reload"), this); + m_reloadAction->setCheckable(true); + m_reloadAction->setChecked(m_DoReload); + m_reloadAction->setIcon(QIcon(QLatin1String(":icons/16x16/edit-redo.png"))); + m_reloadAction->setShortcut(tr("Ctrl+R")); + tipText = tr("Reload des Logfiles ein-/ausschalten (Ctrl-R)"); + m_reloadAction->setStatusTip(tipText); + m_reloadAction->setToolTip(tipText); + connect(m_reloadAction, &QAction::triggered, this, &LogViewGui::reloadOnOff); + toolBar->addAction(m_reloadAction); + + action = new QAction(tr("&Einstellungen"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/configure.png"))); + action->setShortcut(tr("Ctrl+E")); + tipText = tr("Verhalten des Programmes einstellen (Ctrl-E)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::changeSettings); + toolBar->addAction(action); + + toolBar->addSeparator(); + action = new QAction(tr("&Beenden"), this); + action->setIcon(QIcon(QLatin1String(":icons/16x16/edit-delete.png"))); + action->setShortcut(tr("Alt-F4")); + tipText = tr("LogView beenden (Alt-F4)"); + action->setStatusTip(tipText); + action->setToolTip(tipText); + connect(action, &QAction::triggered, this, &LogViewGui::close); + toolBar->addAction(action); + + createCentralSelectionWidget(); + createTetraSelectionWidget(); + createWlsSelectionWidget(); + + + + m_ParticipantTableView = new QTableView(this); + m_participantProxyModel = new QSortFilterProxyModel(this); + m_participantModel = new ParticipantModel(this); + m_participantProxyModel->setSourceModel(m_participantModel); + m_ParticipantTableView->setModel(m_participantProxyModel); + m_ParticipantTableView->setAlternatingRowColors(true); + m_ParticipantTableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_ParticipantTableView->setSelectionMode(QAbstractItemView::MultiSelection); + m_ParticipantTableView->setSortingEnabled(true); + m_ParticipantTableView->setTabKeyNavigation(false); + m_ParticipantTableView->verticalHeader()->hide(); + m_ParticipantTableView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); + m_ParticipantTableView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); + m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + connect(m_ParticipantTableView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &LogViewGui::selectedParticipantChanged); + QVBoxLayout* participantBox = new QVBoxLayout; + participantBox->addWidget(m_ParticipantTableView); + m_ParticipantSelectionGroup = new QGroupBox(tr("Teilnehmer-Filter &aktivieren"), this); + m_ParticipantSelectionGroup->setCheckable(true); + m_ParticipantSelectionGroup->setChecked(false); + m_ParticipantSelectionGroup->setLayout(participantBox); + connect(m_ParticipantSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::selectedParticipantChanged); + + + m_ToolBox = new QToolBox(this); + m_ToolBox->addItem(m_CentralSelectionGroup, QIcon(QLatin1String(":/image/Central.png")), tr("&Zentral-Telegramm-Filter")); + m_ToolBox->addItem(m_TetraSelectionGroup, QIcon(QLatin1String(":/image/Tetra.png")), tr("TET&RA-Telegramm-Filter")); + m_ToolBox->addItem(m_WlsSelectionGroup, QIcon(QLatin1String(":/image/Wls.png")), tr("&WLS-Telegramm-Filter")); + m_ToolBox->addItem(m_ParticipantSelectionGroup, QIcon(QLatin1String(":/image/TNE.png")), tr("Teilnehmer-&Filter")); + m_ToolBox->addItem(m_EditTelegramController->tableView(), QIcon(QLatin1String(":icons/16x16/document-edit.png")), tr("&Edit && Sende Telegramme")); + m_ToolBox->setCurrentIndex(settings.value(TOOLBOXINDEX).toInt()); + + + + m_logTelegramView = new QTableView(this); + m_logTelegramView->setAlternatingRowColors(true); + m_logTelegramView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_logTelegramView->setSelectionMode(QAbstractItemView::ContiguousSelection); + m_logTelegramView->verticalHeader()->hide(); + m_logTelegramView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); + m_logTelegramView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); + m_logTelegramView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + m_logTelegramView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_logTelegramView, &QTableView::customContextMenuRequested, + this, &LogViewGui::customMenuRequested); + m_telegramModel = new TelegramModel(m_logTelegramView); + m_telegramProxyModel = new TelegramProxyModel(m_logTelegramView); + m_telegramProxyModel->setSourceModel(m_telegramModel); + m_logTelegramView->setModel(m_telegramProxyModel); + connect(m_logTelegramView, &QTableView::doubleClicked, + this, &LogViewGui::onLogTelegramViewDoubleClicked); + m_logTelegramView->horizontalHeader()->setSortIndicatorShown(true); + m_logTelegramView->horizontalHeader()->setSortIndicator(3, Qt::AscendingOrder); + m_logTelegramView->setSortingEnabled(true); + + QVBoxLayout* telegramBox = new QVBoxLayout; + telegramBox->addWidget(m_logTelegramView); + QGroupBox* telegramGroup = new QGroupBox(tr("&Log-Telegramme"), this); + telegramGroup->setLayout(telegramBox); + + + m_Splitter = new QSplitter(Qt::Horizontal, this); + m_Splitter->addWidget(m_ToolBox); + m_Splitter->addWidget(telegramGroup); + const QList splitterSizesAsVariant = settings.value(SPLITTPOS).toList(); + QList splitterSizes; + splitterSizes.reserve(splitterSizesAsVariant.size()); + if (splitterSizesAsVariant.isEmpty()) + { + splitterSizes << 235 << 1000; + } + else + { + for (const QVariant &item : splitterSizesAsVariant) + splitterSizes << item.toInt(); + } + m_Splitter->setSizes(splitterSizes); + setCentralWidget(m_Splitter); + + + + m_CentralSelectionGroup->setChecked(true); + m_ackCentralTelCheckBox->setChecked(true); + m_ackCentralTelCheckBox->setChecked(false); + m_PosCentralTelCheckBox->setChecked(true); + m_PosCentralTelCheckBox->setChecked(false); + m_SentCentralTelCheckBox->setChecked(true); + m_ReceivedCentralTelCheckBox->setChecked(true); + + m_TetraSelectionGroup->setChecked(true); + m_SentTetraTelCheckBox->setChecked(true); + m_ReceivedTetraTelCheckBox->setChecked(true); + m_PosTetraTelCheckBox->setChecked(true); + m_PosTetraTelCheckBox->setChecked(false); + m_FragmentedTetraTelCheckBox->setChecked(true); + m_LoginTetraTelCheckBox->setChecked(true); + m_RegisterTetraTelCheckBox->setChecked(true); + m_ReportTetraTelCheckBox->setChecked(false); + m_AirInterfaceLoadTetraTelCheckBox->setChecked(false); + + m_WlsSelectionGroup->setChecked(true); + m_PosWlsTelCheckBox->setChecked(true); + m_PosWlsTelCheckBox->setChecked(false); + m_SentWlsTelCheckBox->setChecked(true); + m_ReceivedWlsTelCheckBox->setChecked(true); + + + QSize size = settings.value(SIZE, sizeHint()).toSize(); + resize(size.isNull() ? QSize(1280, 768) : size); + move(settings.value(POS, QPoint(0, 0)).toPoint()); + settings.endGroup(); + + connect(m_replayTimer, &QTimer::timeout, this, &LogViewGui::onReplayTimerTimeout); + + QTimer::singleShot(0, this, &LogViewGui::loadSpecificationFiles); + + startInjectionThread(); +} + +void LogViewGui::createCentralSelectionWidget() +{ + + m_SentCentralTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2C.png")); + + m_ReceivedCentralTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/C2P.png")); + + m_PosCentralTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/CentralPos.png")); + + m_ackCentralTelCheckBox = createRadioButton(tr("&Bestaetigungstelegramme"), QLatin1String(":/image/CentralAck.png")); + + QVBoxLayout* centralFilterBox = new QVBoxLayout; + centralFilterBox->addWidget(m_SentCentralTelCheckBox); + centralFilterBox->addWidget(m_ReceivedCentralTelCheckBox); + centralFilterBox->addWidget(m_PosCentralTelCheckBox); + centralFilterBox->addWidget(m_ackCentralTelCheckBox); + centralFilterBox->addStretch(1); + + m_CentralSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_CentralSelectionGroup->setCheckable(true); + m_CentralSelectionGroup->setChecked(false); + m_CentralSelectionGroup->setLayout(centralFilterBox); + connect(m_CentralSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + +void LogViewGui::createTetraSelectionWidget() +{ + + m_SentTetraTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/T2P.png")); + + m_ReceivedTetraTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/P2T.png")); + + m_PosTetraTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/TetraPos.png")); + + m_FragmentedTetraTelCheckBox = createRadioButton(tr("&Fragmentierte Meldungen"), QLatin1String(":/image/TetraFragmented.png")); + + m_LoginTetraTelCheckBox = createRadioButton(tr("&Loginmeldungen"), QLatin1String(":/image/TetraLogin.png")); + + m_RegisterTetraTelCheckBox = createRadioButton(tr("&Registermeldungen"), QLatin1String(":/image/TetraRegister.png")); + + m_ReportTetraTelCheckBox = createRadioButton(tr("&Reportmeldungen"), QLatin1String(":/image/TetraReport.png")); + + m_AirInterfaceLoadTetraTelCheckBox = createRadioButton(tr("&Air-Load Meldungen"), QLatin1String(":/image/TetraAirInterface.png")); + + QVBoxLayout* tetraFilterBox = new QVBoxLayout; + tetraFilterBox->addWidget(m_SentTetraTelCheckBox); + tetraFilterBox->addWidget(m_ReceivedTetraTelCheckBox); + tetraFilterBox->addWidget(m_PosTetraTelCheckBox); + tetraFilterBox->addWidget(m_FragmentedTetraTelCheckBox); + tetraFilterBox->addWidget(m_LoginTetraTelCheckBox); + tetraFilterBox->addWidget(m_RegisterTetraTelCheckBox); + tetraFilterBox->addWidget(m_ReportTetraTelCheckBox); + tetraFilterBox->addWidget(m_AirInterfaceLoadTetraTelCheckBox); + tetraFilterBox->addStretch(1); + + m_TetraSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_TetraSelectionGroup->setCheckable(true); + m_TetraSelectionGroup->setChecked(false); + m_TetraSelectionGroup->setLayout(tetraFilterBox); + connect(m_TetraSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + +void LogViewGui::createWlsSelectionWidget() +{ + + m_SentWlsTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2W.png")); + + m_ReceivedWlsTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/W2P.png")); + + m_PosWlsTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/WlsPos.png")); + + QVBoxLayout* wlsFilterBox = new QVBoxLayout; + wlsFilterBox->addWidget(m_SentWlsTelCheckBox); + wlsFilterBox->addWidget(m_ReceivedWlsTelCheckBox); + wlsFilterBox->addWidget(m_PosWlsTelCheckBox); + wlsFilterBox->addStretch(1); + + m_WlsSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); + m_WlsSelectionGroup->setCheckable(true); + m_WlsSelectionGroup->setChecked(false); + m_WlsSelectionGroup->setLayout(wlsFilterBox); + connect(m_WlsSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); +} + + + +void LogViewGui::customMenuRequested(const QPoint &pos) +{ + + QMenu menu(this); + menu.addAction(tr("Add Telegram to EditList"), this, &LogViewGui::addTelegramToEdit); + menu.addAction(tr("Show HexData"), this, &LogViewGui::showHexData); + menu.addAction(tr("Export as CSV file"), this, &LogViewGui::exportAsCsv); + menu.addAction(tr("Export as JSon file"), this, &LogViewGui::exportAsJson); +#ifdef LTS_DEBUG + if (m_EditTelegramController && m_EditTelegramController->isInjectionPossible()) + { + const QString str = m_replayTimer->isActive() ? tr("Stop replay") : tr("Start Replay from here"); + menu.addAction(str, this, &LogViewGui::onStartLogReplay); + } +#endif + menu.exec(m_logTelegramView->viewport()->mapToGlobal(pos)); +} + + + +void LogViewGui::addTelegramToEdit() +{ + for (const QModelIndex &orig: m_logTelegramView->selectionModel()->selectedRows()) + { + const QModelIndex idx = m_telegramProxyModel->mapToSource(orig); + QSharedPointer tele = m_telegramModel->telegram(idx.row()); + if (!tele) + continue; + m_EditTelegramController->appendTelegram(tele); + } +} + + + +void LogViewGui::showHexData() +{ + const QModelIndex idx = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()); + QSharedPointer tele = m_telegramModel->telegram(idx.row()); + if (!tele) + return; + + LogViewTelegramDialog* showTelegramDialog = new LogViewTelegramDialog(this, true); + showTelegramDialog->showDataDump(tele, false); +} + + +void LogViewGui::exportAsCsv() +{ + const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); + const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); + const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as CSV"), suggestion, tr("CSV file (*.csv)")); + if (fn.isEmpty()) + return; + QFile f(fn); + if (!f.open(QIODevice::WriteOnly)) + return; + for (int c = 0; c < m_telegramProxyModel->columnCount(); ++c) + { + f.write(m_telegramProxyModel->headerData(c, Qt::Horizontal).toString().toUtf8()); + f.write(";"); + } + f.write("ISSI\n"); + const int rc = m_telegramProxyModel->rowCount(); + for (int r = 0; r < rc; ++r) + { + QSharedPointer tele = m_telegramProxyModel->telegram(r); + if (!tele) + continue; + f.write(QByteArray::number(tele->getDestination())); + f.write(";"); + f.write(tele->getName().toUtf8()); + f.write(";"); + f.write(QByteArray::number(tele->getParticipantId())); + f.write(";"); + f.write(QByteArray::number(tele->getLogTimeMsec())); + f.write(";"); + f.write(QByteArray::number(tele->getGpsTime())); + f.write(";"); + f.write(QByteArray::number(tele->getDelay())); + f.write(";"); + f.write(QByteArray::number(tele->getISSI())); + f.write("\n"); + } + f.close(); +} + +void LogViewGui::exportAsJson() +{ + const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); + const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); + const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as Json"), suggestion, tr("JSon file (*.json)")); + if (fn.isEmpty()) + return; + QFile f(fn); + if (!f.open(QIODevice::WriteOnly)) + return; + QJsonArray arr; + const int rc = m_telegramProxyModel->rowCount(); + for (int r = 0; r < rc; ++r) + { + QSharedPointer tele = m_telegramProxyModel->telegram(r); + if (!tele) + continue; + if (tele->jsonData().isEmpty()) + continue; + arr += tele->jsonData(); + } + f.write(QJsonDocument(arr).toJson(QJsonDocument::Indented)); + f.close(); +} + + +void LogViewGui::onStartLogReplay() +{ +#ifndef LTS_DEBUG + return; +#endif + if (m_replayTimer->isActive()) + { + m_replayTimer->stop(); + return; + } + m_reloadAction->setChecked(false); + m_PosCentralTelCheckBox->setChecked(true); + if (!m_EditTelegramController || !m_EditTelegramController->isInjectionPossible()) + return; + m_currentReplayRow = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()).row(); + if (m_currentReplayRow < 0) + return; + m_replayTimer->start(0); +} + +void LogViewGui::onReplayTimerTimeout() +{ + auto findNextCentralTelegram = [&]() + { + static constexpr auto sendToCentralBits = N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral | + N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend; + auto tele = m_telegramModel->telegram(m_currentReplayRow); + while (tele && (tele->getDestination() != sendToCentralBits || + tele->getTelId() == GEF_BESTAETIGUNG)) + tele = m_telegramModel->telegram(++m_currentReplayRow); + return tele; + }; + + QSharedPointer tele = findNextCentralTelegram(); + auto checkTele = [&]() + { + if (!tele) + { + m_replayTimer->stop(); + m_currentReplayRow = -1; + QMessageBox::information(this, tr("Sending finished"), tr("No more telegrams to send - stopping")); + return false; + } + return true; + }; + + if (!checkTele()) + return; + const uint64_t curSendTime = tele->getLogTimeMsec(); + auto teleCopy = QSharedPointer(new LogViewTelegram(*(tele.data()))); + teleCopy->actualizeGpsTime(); + m_InjectionThread->sendTelegram(teleCopy.data(), true); + ++m_currentReplayRow; + tele = findNextCentralTelegram(); + if (!checkTele()) + return; + + uint64_t nextSendTime = (tele->getLogTimeMsec() - curSendTime); + DEBUG_LOG(m_logger) << "Next SendTime: " << nextSendTime + << ", telId: " << tele->getTelId() + << ", next row: " << m_currentReplayRow + << ", equipNo: " << tele->getParticipantId(); + QModelIndex idx = m_telegramModel->index(m_currentReplayRow, 0, QModelIndex()); + m_logTelegramView->setCurrentIndex(m_telegramProxyModel->mapFromSource(idx)); + m_replayTimer->start(nextSendTime); +} + + +void LogViewGui::loadSpecificationFiles() +{ + QSettings settings; + settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + + + QString defString = QCoreApplication::applicationDirPath() + QLatin1String("/training_area_telegrams.h"); + QString filename = settings.value(LogViewOptionDialog::P0_FILENAME, defString).toString(); + INFO_LOG(m_logger) << "Load central-protocol spezification-file: " << filename.toStdString(); + if (!QFile::exists(filename)) + { + QMessageBox::warning(this, tr("LogView"), tr("Die Spezifikations-Datei \'%1\' fuer Zentral-Telegramme existiert nicht!

Werde die Default-Datei verwenden...").arg(filename)); + filename = defString; + } + LogViewTelegram::jsonParser()->parse(filename); + + + defString = QCoreApplication::applicationDirPath() + QLatin1String("/zsksxd_tetraForLogView.x"); + filename = settings.value(LogViewOptionDialog::P5_FILENAME, defString).toString(); + INFO_LOG(m_logger) << "Load tetra-protocol spezification-file: " << filename.toStdString(); + if (!QFile::exists(filename)) + { + QMessageBox::warning(this, tr("LogView"), tr("Die Spezifikations-Datei \'%1\' fuer TETRA-Telegramme existiert nicht!

Werde die Default-Datei verwenden...").arg(filename)); + filename = defString; + } + + LogViewTelegram::tetraParser()->parseX_File(filename); + + INFO_LOG(m_logger) << "Browse telegram-log-file"; + newTelegramFile(); +} + + + +void LogViewGui::newTelegramFile() +{ + if (m_TailTimer) m_TailTimer->stop(); + + m_participantModel->clearParticipants(); + m_telegramModel->clearTelegrams(); + m_participantListTelCount.clear(); + m_participantListIssi.clear(); + m_ParticipantStatus->setText(tr("0 Teilnehmer")); + + loadTelegramFile(); +} + + + +void LogViewGui::loadTelegramFile() +{ + const QLatin1String DIR("Dir"); + QSettings settings; + settings.beginGroup(QLatin1String("LogFiles")); + + QString filename = QFileDialog::getOpenFileName(this, tr("Bitte eine Log-Datei auswaehlen"), settings.value(DIR).toString(), LogViewOptionDialog::KRLOG_FILES); + if (filename.isEmpty()) + return; + + QDir dir; + settings.setValue(DIR, dir.filePath(filename)); + + readTelegramsFromLogFile(filename); + showTelegramTable(); + startInjectionThread(); + m_logTelegramView->resizeColumnsToContents(); + m_ParticipantTableView->resizeColumnsToContents(); + + + if (!m_TailTimer) + m_TailTimer = new QTimer(this); + connect(m_TailTimer, &QTimer::timeout, this, &LogViewGui::updateLogfile, Qt::QueuedConnection); + m_TailTimer->setInterval(1000); + m_TailTimer->start(); +} + + + + + + + +void LogViewGui::updateLogfile() +{ + if(!m_DoReload) + return; + m_TailTimer->stop(); + QFileInfo fileInfo = QFileInfo(m_ActualLogfile); + if (fileInfo.exists()) + { + if (fileInfo.size() > m_LogfileSize) + { + try + { + readTelegramsFromLogFile(m_ActualLogfile, m_LogfileSize); + } + catch (const std::exception& e) + { + WARNING_LOG(m_logger) << "Error: " << e.what(); + + } + } + else + { + + QString dateFromFile; + const QString format = QStringLiteral("yyMMdd_hh"); + for (int iterator = fileInfo.baseName().size() - format.size(); iterator < fileInfo.baseName().size(); ++iterator) + dateFromFile.append(fileInfo.baseName().at(iterator)); + + QDateTime nextDateCalc = QDateTime::fromString(dateFromFile, format); + nextDateCalc = nextDateCalc.addYears(100); + nextDateCalc = nextDateCalc.addSecs(3600); + QString nextDate = nextDateCalc.toString(format); + nextDateCalc = nextDateCalc.addSecs(3600); + QString checkDate = nextDateCalc.toString(format); + + QString filePath(fileInfo.absolutePath() + QLatin1Char('/')); + const QString baseName = fileInfo.baseName(); + const QVector parts = baseName.splitRef(QLatin1Char('_')); + + for (int iterator = 0; iterator < parts.size() - 2; ++iterator) + filePath += parts.at(iterator).toString() + QLatin1Char('_'); + + QString nextFile(filePath + nextDate + QLatin1Char('.') + fileInfo.completeSuffix()); + QString checkFile(filePath + checkDate + QLatin1Char('.') + fileInfo.completeSuffix()); + + QFileInfo infoNextFile(nextFile); + QFileInfo infoCheckFile(checkFile); + if (infoNextFile.exists() && infoNextFile.isFile() && !infoCheckFile.exists()) + { + m_LogfileSize = 0; + readTelegramsFromLogFile(nextFile, m_LogfileSize); + } + } + } + m_TailTimer->start(); +} + + + +void LogViewGui::readTelegramsFromLogFile(const QString& a_fileName, const qint64 a_filePos) +{ + + QFile telegramFile(a_fileName); + if (telegramFile.open(QIODevice::ReadOnly)) + { + m_ActualLogfile = a_fileName; + telegramFile.seek(a_filePos); + setWindowTitle(QFileInfo(m_ActualLogfile).baseName()); + m_logTelegramView->blockSignals(true); + m_logTelegramView->setUpdatesEnabled(false); + QVector > newTelegrams; + + N_CoPrtCnv::CoPrtCnvLogHeader lh; + while (true) + { + if (sizeof(lh) == telegramFile.read((char*)&lh, sizeof(lh))) + { + if (lh.m_Version == 3 || lh.m_Version == 4) + { + + qint64 telegramLength = lh.m_Length - sizeof(lh); + QByteArray buf(telegramLength, Qt::Uninitialized); + if (telegramLength == telegramFile.read(buf.data(), telegramLength)) + { + m_LogfileSize = telegramFile.pos(); + + if (lh.m_Version == 4) + buf = qUncompress(buf); + + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol protocol = + static_cast(lh.m_Protocol); + QSharedPointer telegram(new LogViewTelegram(protocol, lh.m_Time, buf)); + + if (!telegram->isValid()) + { + ERROR_LOG(m_logger) << "Trying to read/parse unknown data from logfile '" << a_fileName + << "' at position " << telegramFile.pos() - (telegramLength + sizeof(lh)); + continue; + } + newTelegrams.push_back(telegram); + + + addToParticipantList(telegram); + } + } + else + { + QMessageBox::warning(this, tr("Falsche Version"), tr("LogViewer kann Telegramm-Logs der Version %1 nicht einlesen").arg(lh.m_Version)); + ERROR_LOG(m_logger) << "Trying to read/parse unknown data from logfile '" << a_fileName + << "' at position " << telegramFile.pos() - sizeof(lh); + } + } + else + { + break; + } + } + syncParticipantList(); + + m_telegramModel->appendTelegrams(newTelegrams); + m_ParticipantStatus->setText(tr("%1 Teilnehmer").arg(m_participantModel->rowCount())); + m_logTelegramView->setUpdatesEnabled(true); + m_logTelegramView->blockSignals(false); + + statusBar()->showMessage(tr("%1 Telegramme eingelesen").arg(m_telegramModel->rowCount())); + } + else + { + QMessageBox::warning(this, tr("Dateifehler"), tr("Konnte die Datei %1 nicht oeffnen").arg(a_fileName)); + } + telegramFile.close(); +} + + + +void LogViewGui::selectedParticipantChanged() +{ + std::set selectedParticipantIds; + + const QModelIndexList selectedParticipants = m_ParticipantTableView->selectionModel()->selectedRows(0); + for (const QModelIndex &participantIdx : selectedParticipants) + { + + const QModelIndex idx = m_participantProxyModel->mapToSource(participantIdx); + selectedParticipantIds.insert(m_participantModel->data(idx).toInt()); + } + m_telegramProxyModel->setAllowedEquipmentIds(selectedParticipantIds); + showTelegramTable(); +} + +static void updateFilteredPosTelegramIds(std::set &teleIds, bool bEnable) +{ + if (bEnable) + { + teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG); + teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_LFZ); + teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_MIT_TEILNEHMER); + teleIds.erase(TrainingAreaBase::TetraIcd::IPS_POSITIONSDATEN); + } + else + { + teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG); + teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_LFZ); + teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_MIT_TEILNEHMER); + teleIds.insert(TrainingAreaBase::TetraIcd::IPS_POSITIONSDATEN); + } +} + + +void LogViewGui::showTelegramTable() +{ + updateFilteredPosTelegramIds(m_CentralTelegramFilterList, m_PosCentralTelCheckBox->isChecked()); + updateFilteredPosTelegramIds(m_TetraTelegramFilterList, m_PosTetraTelCheckBox->isChecked()); + updateFilteredPosTelegramIds(m_WlsTelegramFilterList, m_PosWlsTelCheckBox->isChecked()); + if (m_ackCentralTelCheckBox->isChecked()) + m_CentralTelegramFilterList.erase(TrainingAreaBase::TetraIcd::BESTAETIGUNG); + else + m_CentralTelegramFilterList.insert(TrainingAreaBase::TetraIcd::BESTAETIGUNG); + m_telegramProxyModel->setFilteredCentralTelegramIds(m_CentralTelegramFilterList); + m_telegramProxyModel->setFilteredTetraTelegramIds(m_TetraTelegramFilterList); + m_telegramProxyModel->setFilteredWlsTelegramIds(m_WlsTelegramFilterList); + + m_telegramProxyModel->setFilterByEquipmentIds(m_ParticipantSelectionGroup->isChecked()); + + m_PosCentralTelCheckBox->setEnabled(m_SentCentralTelCheckBox->isChecked() && m_CentralSelectionGroup->isChecked()); + m_PosTetraTelCheckBox->setEnabled(m_SentTetraTelCheckBox->isChecked() && m_TetraSelectionGroup->isChecked()); + m_PosWlsTelCheckBox->setEnabled(m_ReceivedWlsTelCheckBox->isChecked() && m_WlsSelectionGroup->isChecked()); + + const bool bShowCentralTelegrams = m_CentralSelectionGroup->isChecked(); + m_telegramProxyModel->setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, + !m_SentCentralTelCheckBox->isChecked() || !bShowCentralTelegrams); + m_telegramProxyModel->setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, + !m_ReceivedCentralTelCheckBox->isChecked() || !bShowCentralTelegrams); + + const bool bShowTetraTelegrams = m_TetraSelectionGroup->isChecked(); + m_telegramProxyModel->setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, + !m_SentTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, + !m_ReceivedTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd, + !m_RegisterTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp, + !m_RegisterTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq, + !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq, + !m_ReportTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq, + !m_AirInterfaceLoadTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirLoadHyterra, + !m_AirInterfaceLoadTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraLogin(!m_LoginTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + m_telegramProxyModel->setFilterTetraFragmented(!m_FragmentedTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); + + const bool bShowWlsTelegrams = m_WlsSelectionGroup->isChecked(); + m_telegramProxyModel->setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, + !m_SentWlsTelCheckBox->isChecked() || !bShowWlsTelegrams); + m_telegramProxyModel->setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, + !m_ReceivedWlsTelCheckBox->isChecked() || !bShowWlsTelegrams); + + m_TelegramStatus->setText(tr("%1 telegrams (unfiltered: %2)") + .arg(m_telegramProxyModel->rowCount()) + .arg(m_telegramModel->rowCount())); +} + + +void LogViewGui::addToParticipantList(const QSharedPointer &a_telegram) +{ + int partId = a_telegram->getParticipantId(); + m_participantListTelCount[partId]++; + auto &issi = m_participantListIssi[partId]; + if (issi == 0) + issi = a_telegram->getISSI(); +} + +void LogViewGui::syncParticipantList() +{ + QVector eqIds; + QVector issis; + QVector numberOfTelegrams; + eqIds.reserve(m_participantListTelCount.size()); + issis.reserve(m_participantListTelCount.size()); + numberOfTelegrams.reserve(m_participantListTelCount.size()); + for (auto it = m_participantListTelCount.constBegin(); it != m_participantListTelCount.constEnd(); ++it) + { + eqIds.push_back(it.key()); + issis.push_back(m_participantListIssi.value(it.key())); + numberOfTelegrams.push_back(it.value()); + } + m_participantModel->addUpdateParticipants(eqIds, issis, numberOfTelegrams); +} + + +void LogViewGui::changeSettings() +{ + LogViewOptionDialog optionDialog(this); + + connect(&optionDialog, &LogViewOptionDialog::settingsChanged, this, &LogViewGui::onSettingsChanged); + + optionDialog.exec(); +} + + + +QCheckBox* LogViewGui::createRadioButton(const QString& a_buttonName, const QString& a_iconName) +{ + QCheckBox* checkBox = new QCheckBox(a_buttonName, this); + checkBox->setIcon(QIcon(a_iconName)); + checkBox->setIconSize(RADIO_BUTTON_ICON_SIZE); + connect(checkBox, &QCheckBox::toggled, this, &LogViewGui::showTelegramTable); + return checkBox; +} + + + + + + +void LogViewGui::startInjectionThread() +{ + if (m_InjectionThread) + { + m_InjectionThread->quit(); + m_InjectionThread->wait(); + delete m_InjectionThread; + } + + m_InjectionThread = new LogViewInjectionThread(); + + QSettings settings; + settings.beginGroup(QLatin1String("LogFiles")); + QString filePath = settings.value(QLatin1String("Dir")).toString(); + QString exerciseName; + QVector parts = filePath.splitRef(QLatin1Char('/')); + if (parts.size() >= 2) + exerciseName = QLatin1Char('_') + parts.at(parts.size() - 2).toString(); + + QString portFilePath = QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("PrtCnv") + exerciseName + QLatin1String(".dat"); + QFileInfo checkPortFile(portFilePath); + if(checkPortFile.exists() && checkPortFile.isFile()) + { + QSettings portSetting(portFilePath, QSettings::IniFormat); + m_InjectionThread->setPort(portSetting.value(QLatin1String("Injection/Port")).toInt()); + } + + m_EditTelegramController->setInjectionThread(m_InjectionThread); + connect(m_InjectionThread, &LogViewInjectionThread::updateStatus, + this, &LogViewGui::updateInjectionStatus); + + m_InjectionThread->start(); +} + + + + + + +void LogViewGui::reloadOnOff() +{ + m_DoReload = !m_DoReload; +} + + + +void LogViewGui::closeEvent(QCloseEvent* a_closeEvent) +{ + QSettings settings; + settings.beginGroup(WINDOW_GROUP); + + + settings.setValue(TOOLBOXINDEX, m_ToolBox->currentIndex()); + + + settings.setValue(SIZE, size()); + QPoint position = pos(); + settings.setValue(POS, position); +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) + int screenNbr = QApplication::desktop()->screenNumber(position); +#else + QScreen *scr = QGuiApplication::screenAt(position); + int screenNbr = QGuiApplication::screens().indexOf(scr); +#endif + settings.setValue(SCREEN, screenNbr); + + + const QList splitterSizes = m_Splitter->sizes(); + QList splitterSizesAsVariant; + splitterSizesAsVariant.reserve(splitterSizes.size()); + for (int item : splitterSizes) + splitterSizesAsVariant << QVariant(item); + + settings.setValue(SPLITTPOS, splitterSizesAsVariant); + + settings.endGroup(); + + QMainWindow::closeEvent(a_closeEvent); +} + + +void LogViewGui::updateInjectionStatus(const QString& a_picName, const QString& a_toopTipText) +{ + m_InjectionStatus->setPixmap(QPixmap(a_picName)); + m_InjectionStatus->setToolTip(a_toopTipText); +} + + +void LogViewGui::onLogTelegramViewDoubleClicked(const QModelIndex &index) +{ + if (!m_telegramProxyModel || !m_telegramModel) + return; + QModelIndex idx = m_telegramProxyModel->mapToSource(index); + if (!idx.isValid()) + return; + QSharedPointer telegram = m_telegramModel->telegram(idx.row()); + if (!telegram) + return; + LogViewTelegramDialog* showTelegramDialog = new LogViewTelegramDialog(this, true); + showTelegramDialog->showDialog(telegram); +} + +void LogViewGui::onSettingsChanged(uint32_t changedFlags) +{ + if ((changedFlags & LogViewOptionDialog::SpecFilesGroup) == LogViewOptionDialog::SpecFilesGroup) + loadSpecificationFiles(); + + if ((changedFlags & LogViewOptionDialog::InjectionGroup) == LogViewOptionDialog::InjectionGroup) + startInjectionThread(); +} + +} diff --git a/TetraIF/LogView/LogViewGui.hpp b/TetraIF/LogView/LogViewGui.hpp new file mode 100644 index 000000000..e1ad0a9f3 --- /dev/null +++ b/TetraIF/LogView/LogViewGui.hpp @@ -0,0 +1,189 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include "LogViewModels.hpp" +#include "LogViewTelegramEditModel.hpp" +#include +#include +#include "logger.h" + +namespace N_LogView +{ +class LogViewTelegram; +} +class QTableView; + +class QGroupBox; +class QCheckBox; +class QLabel; +class QLineEdit; +class QPushButton; +class QSplitter; +class QToolBox; + + +namespace N_LogView +{ +class LogViewInjectionThread; +class TelegramEdit; + + + +class LogViewGui : public QMainWindow +{ + Q_OBJECT +public: + + explicit LogViewGui(QWidget* a_parent); + + static const QLatin1String WINDOW_GROUP; + static const QLatin1String SCREEN; + +protected: + + const QSize RADIO_BUTTON_ICON_SIZE; + static const QLatin1String SIZE; + static const QLatin1String POS; + static const QLatin1String SPLITTPOS; + static const QLatin1String TOOLBOXINDEX; + + QGroupBox *m_CentralSelectionGroup; + std::set m_CentralTelegramFilterList; + QCheckBox* m_SentCentralTelCheckBox; + QCheckBox* m_ReceivedCentralTelCheckBox; + QCheckBox* m_PosCentralTelCheckBox; + QCheckBox* m_ackCentralTelCheckBox; + + QGroupBox *m_TetraSelectionGroup; + std::set m_TetraTelegramFilterList; + QCheckBox* m_SentTetraTelCheckBox; + QCheckBox* m_ReceivedTetraTelCheckBox; + QCheckBox* m_PosTetraTelCheckBox; + QCheckBox* m_LoginTetraTelCheckBox; + QCheckBox* m_RegisterTetraTelCheckBox; + QCheckBox* m_ReportTetraTelCheckBox; + QCheckBox* m_FragmentedTetraTelCheckBox; + QCheckBox* m_AirInterfaceLoadTetraTelCheckBox; + + QGroupBox *m_WlsSelectionGroup; + std::set m_WlsTelegramFilterList; + QCheckBox* m_SentWlsTelCheckBox; + QCheckBox* m_ReceivedWlsTelCheckBox; + QCheckBox* m_PosWlsTelCheckBox; + QCheckBox* m_ackWlsTelCheckBox; + + QString m_ActualLogfile; + qint64 m_LogfileSize; + bool m_DoReload; + QToolBox* m_ToolBox; + QTableView *m_ParticipantTableView; + ParticipantModel *m_participantModel; + QSortFilterProxyModel *m_participantProxyModel; + + QTableView *m_logTelegramView; + TelegramModel *m_telegramModel; + TelegramProxyModel *m_telegramProxyModel; + + QLabel *m_TelegramStatus; + + QLabel *m_ParticipantStatus; + + QGroupBox *m_ParticipantSelectionGroup; + + TelegramEdit *m_EditTelegramController; + + QTimer *m_TailTimer; + + QSplitter *m_Splitter; + + LogViewInjectionThread *m_InjectionThread; + + QLabel *m_InjectionStatus; + + + QHash m_participantListTelCount; + + QHash m_participantListIssi; + + QAction *m_reloadAction; + QTimer *m_replayTimer; + int m_currentReplayRow; + NGL::INGLLogger &m_logger; + +protected: + void readTelegramsFromLogFile(const QString& a_fileName, const qint64 a_filePos = 0); + + + + void addToParticipantList(const QSharedPointer &a_telegram); + void syncParticipantList(); + QCheckBox* createRadioButton(const QString& a_buttonName, const QString& a_iconName); + + + + void startInjectionThread(); + + void closeEvent(QCloseEvent* a_closeEvent) override; + + void createCentralSelectionWidget(); + void createTetraSelectionWidget(); + void createWlsSelectionWidget(); + +protected slots: + void addTelegramToEdit(); + void showHexData(); + void exportAsCsv(); + void exportAsJson(); + void onStartLogReplay(); + void onReplayTimerTimeout(); + + void loadSpecificationFiles(); + + + void newTelegramFile(); + + + void loadTelegramFile(); + + + + void updateLogfile(); + + void selectedParticipantChanged(); + + void showTelegramTable(); + + + void customMenuRequested(const QPoint &pos); + + void changeSettings(); + + + + void reloadOnOff(); + + + + void updateInjectionStatus(const QString& a_picName, const QString& a_toopTipText); + + void onLogTelegramViewDoubleClicked(const QModelIndex &index); + +private slots: + void onSettingsChanged(uint32_t changedFlags); +}; + +} diff --git a/TetraIF/LogView/LogViewInjectionThread.cpp b/TetraIF/LogView/LogViewInjectionThread.cpp new file mode 100644 index 000000000..faefb51b2 --- /dev/null +++ b/TetraIF/LogView/LogViewInjectionThread.cpp @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + +#include "LogViewInjectionThread.hpp" + +#include "LogViewTelegram.hpp" +#include "LogViewOptionDialog.hpp" +#include +#include +#include +#include + +namespace N_LogView +{ +LogViewInjectionThread::LogViewInjectionThread() + : m_DoStartConnection(false) + , m_SendingPossible(false) + , m_Socket(nullptr) + , m_Timer(nullptr) + , m_logger(getLogger("LogViewInjectionThread")) +{ + + QSettings settings; + settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP); + m_Hostname = settings.value(LogViewOptionDialog::INJECTION_HOSTNAME).toString(); + if (m_Hostname.isEmpty()) + { + + m_Hostname = QLatin1String("localhost"); + settings.setValue(LogViewOptionDialog::INJECTION_HOSTNAME, m_Hostname); + } + m_Port = settings.value(LogViewOptionDialog::INJECTION_PORT).toInt(); + if (0 == m_Port || m_Port > 65535) + { + m_Port = 46666; + settings.setValue(LogViewOptionDialog::INJECTION_PORT, m_Port); + } +} + + +void LogViewInjectionThread::run() +{ + emit updateStatus(QLatin1String(":/image/RedLamp.png"), + tr("LogView ist nicht mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port)); + QTimer::singleShot(100, this, &LogViewInjectionThread::tryToConnect); + + exec(); +} + + + +void LogViewInjectionThread::setPort(uint16_t port) +{ + m_Port = port; + QSettings settings; + settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP); + settings.setValue(LogViewOptionDialog::INJECTION_PORT, m_Port); +} + + + +bool LogViewInjectionThread::isSendingPossible() const +{ + return m_SendingPossible; +} + + + +void LogViewInjectionThread::tryToConnect() +{ + + if (!m_Socket) + { + m_Socket = new QTcpSocket(this); + connect(m_Socket, &QTcpSocket::connected, this, &LogViewInjectionThread::doConnect); + connect(m_Socket, &QTcpSocket::disconnected, this, &LogViewInjectionThread::doDisconnect); + } + + + if (!m_Timer) + { + m_Timer = new QTimer(this); + connect(m_Timer, &QTimer::timeout, this, &LogViewInjectionThread::tryToConnect); + } + m_Timer->setInterval(3000); + m_Timer->start(); + + INFO_LOG(m_logger) << "Try to connect to injection-server of TETRA-If (" << m_Hostname << ":" << m_Port << ")"; + m_Socket->connectToHost(m_Hostname, m_Port); +} + + + +void LogViewInjectionThread::doConnect() +{ + INFO_LOG(m_logger) << "LogView has successful connected to injection-server of TETRA-If"; + m_SendingPossible = true; + m_Timer->stop(); + emit updateStatus(QLatin1String(":/image/GreenLamp.png"), + tr("LogView ist mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port)); +} + + + +void LogViewInjectionThread::doDisconnect() +{ + INFO_LOG(m_logger) << "LogView was disconnected from injection-server of TETRA-If"; + m_SendingPossible = false; + emit updateStatus(QLatin1String(":/image/RedLamp.png"), + tr("LogView ist nicht mehr mit TETRA-If-Injection-Server (%1:%2) verbunden").arg(m_Hostname).arg(m_Port)); + tryToConnect(); +} + + + +void LogViewInjectionThread::sendTelegram(LogViewTelegram* a_telegram, const bool a_doSendAsCentralTelegram) +{ + INFO_LOG(m_logger) << "inject " << (a_doSendAsCentralTelegram ? "central" : "Tetra") << " telegram"; + if (!m_Socket || m_Socket->state() != QAbstractSocket::ConnectedState) + { + ERROR_LOG(m_logger) << "Try to write a telegramm but we are not connected"; + return; + } + N_CoPrtCnv::CoPrtCnvInjectionHeader injectionHeader; + injectionHeader.m_Kind = a_doSendAsCentralTelegram ? N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral : N_CoPrtCnv::CoPrtCnvInjectionHeader::eRadio; + const QByteArray &data = a_telegram->getData(); + injectionHeader.m_Size = data.size(); + m_Socket->write((char*)(&injectionHeader), sizeof(injectionHeader)); + m_Socket->write(data); +} + +} diff --git a/TetraIF/LogView/LogViewInjectionThread.hpp b/TetraIF/LogView/LogViewInjectionThread.hpp new file mode 100644 index 000000000..d2007ac46 --- /dev/null +++ b/TetraIF/LogView/LogViewInjectionThread.hpp @@ -0,0 +1,79 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +class QTcpSocket; +class QTimer; + + +namespace N_LogView +{ + class LogViewTelegram; + + + + class LogViewInjectionThread : public QThread + { + Q_OBJECT + public: + + LogViewInjectionThread(); + + void run(); + + void setPort(uint16_t port); + + bool isSendingPossible() const; + + + + void sendTelegram(LogViewTelegram* a_telegram, const bool a_doSendAsCentralTelegram); + + protected: + + bool m_DoStartConnection; + bool m_SendingPossible; + QString m_Hostname; + int m_Port; + QTcpSocket *m_Socket; + + QTimer *m_Timer; + + private: + + + NGL::INGLLogger &m_logger; + + protected: + protected slots: + void tryToConnect(); + + + void doConnect(); + + + void doDisconnect(); + + public: + signals: + + + void updateStatus(const QString& a_picName, const QString& a_toolTipText); + + }; + +} diff --git a/TetraIF/LogView/LogViewMain.cpp b/TetraIF/LogView/LogViewMain.cpp new file mode 100644 index 000000000..7bfeeae64 --- /dev/null +++ b/TetraIF/LogView/LogViewMain.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#ifndef WIN32 + #include +#endif +#include "LogViewGui.hpp" +#include "logger.h" + +int main(int argc, char *argv[]) +{ + std::string logConfigFileName; + std::string dir; + +#ifdef WIN32 + dir = argv[0]; +#else + std::stringstream s; + s << "/proc/" << getpid() << "/exe"; + char buf[1024]; + ssize_t len = readlink(s.str().c_str(), buf, 1024); + if(len > 0) { + buf[len] = '\0'; + dir = buf; + } else { + + dir = argv[0]; + } +#endif + + std::string::size_type pos = dir.find_last_of('/'); + if (std::string::npos != pos) + logConfigFileName += dir.substr(0, pos + 1);; + logConfigFileName += "LogView_log4cxx.props"; + + qputenv("TDS_DEVEL", QByteArray::number(1)); + NGLApplication app(argc, argv); + QNetworkProxy::setApplicationProxy(QNetworkProxy()); + app.createLogger("LogView", logConfigFileName.c_str()); + + QCoreApplication::setOrganizationName(QLatin1String("RME")); + QCoreApplication::setApplicationName(QLatin1String("LogView")); + + QSettings settings; + settings.beginGroup(N_LogView::LogViewGui::WINDOW_GROUP); + int screenNbr = settings.value(N_LogView::LogViewGui::SCREEN, 0).toInt(); + settings.endGroup(); + + N_LogView::LogViewGui* logViewGui = new N_LogView::LogViewGui(QApplication::desktop()->screen(screenNbr)); + logViewGui->show(); + int ret = app.exec(); + + delete logViewGui; + return ret; +} + diff --git a/TetraIF/LogView/LogViewModels.cpp b/TetraIF/LogView/LogViewModels.cpp new file mode 100644 index 000000000..26e266b31 --- /dev/null +++ b/TetraIF/LogView/LogViewModels.cpp @@ -0,0 +1,548 @@ + + + +#include "LogViewModels.hpp" + +#include +#include +#include + +namespace N_LogView +{ + + + +int ParticipantModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_particpants.size(); +} + + +int ParticipantModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 3; +} + + +QVariant ParticipantModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && index.row() < m_particpants.size()) + { + const auto &p = m_particpants.at(index.row()); + if (role == Qt::DisplayRole) + { + switch (index.column()) + { + case 0: + return p.first; + case 1: + return p.second; + case 2: + return m_particpantMap.value(p.first); + default: + break; + } + } + if (role == Qt::ToolTipRole) + { + switch (index.column()) + { + case 0: + return tr("hex: 0x%1").arg(p.first, 4, 16, QLatin1Char('0')); + case 1: + return tr("hex: 0x%1").arg(p.second, 4, 16, QLatin1Char('0')); + default: + break; + } + } + if (role == Qt::BackgroundColorRole) + { + if (p.first == 0) + return QVariant(); + if (m_participantHeatmap.isEmpty()) + updateHeatMap(); + return m_participantHeatmap.value(p.first); + } + } + return QVariant(); +} + + +QVariant ParticipantModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) + { + switch (section) + { + case 0: + return tr("Equip. No."); + case 1: + return tr("ISSI"); + case 2: + return tr("#"); + default: + break; + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + + +void ParticipantModel::clearParticipants() +{ + beginResetModel(); + m_particpantMap.clear(); + m_particpants.clear(); + m_participantHeatmap.clear(); + endResetModel(); +} + + +bool ParticipantModel::addUpdateParticipants(const QVector &eqIds, + const QVector &issis, + const QVector &numberOfTelegrams) +{ + QVector > newParticpants; + for (int i = 0; i < eqIds.size(); ++i) + { + const int eqId = eqIds.at(i); + const int issi = issis.at(i); + const int cntTelegrams = numberOfTelegrams.at(i); + auto it = m_particpantMap.find(eqId); + if (it != m_particpantMap.end()) + { + it.value() = cntTelegrams; + continue; + } + newParticpants.push_back(qMakePair(eqId, issi)); + m_particpantMap[eqId] = cntTelegrams; + } + + if (!newParticpants.isEmpty()) + { + beginInsertRows(QModelIndex(), m_particpants.size(), m_particpants.size() + newParticpants.size() - 1); + m_particpants.append(newParticpants); + endInsertRows(); + } + m_participantHeatmap.clear(); + return true; +} + + +void ParticipantModel::updateHeatMap() const +{ + int maxNumberOfTelegrams = 0; + for (auto it = m_particpantMap.begin(); it != m_particpantMap.end(); ++it) + { + if (it.key() == 0) + continue; + maxNumberOfTelegrams = std::max(it.value(), maxNumberOfTelegrams); + } + + const QColor backgroundColor = QGuiApplication::palette().base().color(); + const QColor redColor = Qt::red; + for (auto it = m_particpantMap.begin(); it != m_particpantMap.end(); ++it) + { + const int eqId = it.key(); + if (eqId == 0) + continue; + + const int nbrTelegrams = it.value(); + QColor curColor; + double percent = static_cast(nbrTelegrams) / maxNumberOfTelegrams; + curColor.setRed(backgroundColor.red() - ((backgroundColor.red() - redColor.red()) * percent)); + curColor.setGreen(backgroundColor.green() - ((backgroundColor.green() - redColor.green()) * percent)); + curColor.setBlue(backgroundColor.blue() - ((backgroundColor.blue() - redColor.blue()) * percent)); + m_participantHeatmap[eqId] = curColor; + } +} + + + +int TelegramModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_telegrams.size(); +} + + +int TelegramModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 6; +} + + +QVariant TelegramModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && index.row() < m_telegrams.size()) + { + if (role == Qt::DisplayRole) + { + const QSharedPointer &telegram = m_telegrams.at(index.row()); + switch (index.column()) + { + case 0: + return telegram->getDestinationText(); + case 1: + return telegram->getName(); + case 2: + return telegram->getParticipantId(); + case 3: + return telegram->getLogTimeText(); + case 4: + return telegram->getGpsTimeText(); + case 5: + return telegram->getDelay(); + } + } + if (role == Qt::DecorationRole) + { + const QSharedPointer telegram = m_telegrams.at(index.row()); + switch (index.column()) + { + case 0: + return telegram->getIcon(); + default: + break; + } + } + if (role == Qt::ToolTipRole) + { + const QSharedPointer telegram = m_telegrams.at(index.row()); + switch (index.column()) + { + case 1: + return telegram->getToolTipText(LogViewTelegram::e_ColName); + case 3: + return telegram->getToolTipText(LogViewTelegram::e_ColLogTime); + case 4: + return telegram->getToolTipText(LogViewTelegram::e_ColGpsTime); + default: + break; + } + } + } + return QVariant(); +} + + +QVariant TelegramModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal) + { + if (role == Qt::DisplayRole) + { + switch (section) + { + case 0: + return tr("Dest."); + case 1: + return tr("Description"); + case 2: + return tr("Equip. No."); + case 3: + return tr("Send/Recieve time"); + case 4: + return tr("GPS time"); + case 5: + return tr("Delay"); + default: + break; + } + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + + +void TelegramModel::clearTelegrams() +{ + beginResetModel(); + m_telegrams.clear(); + endResetModel(); +} + + +void TelegramModel::appendTelegrams(const QVector > &telegrams) +{ + if (telegrams.isEmpty()) + return; + beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size() + telegrams.size() - 1); + m_telegrams += telegrams; + endInsertRows(); +} + + +void TelegramModel::appendTelegram(const QSharedPointer &telegram) +{ + beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size()); + m_telegrams.push_back(telegram); + endInsertRows(); +} + + +QSharedPointer TelegramModel::telegram(int row) const +{ + if (row >= 0 && row < m_telegrams.size()) + return m_telegrams.at(row); + return QSharedPointer(); +} + + + +void TelegramProxyModel::setFilterByEquipmentIds(bool bFilterByEquipmentIds) +{ + if (m_bFilterByEquipmentIds == bFilterByEquipmentIds) + return; + m_bFilterByEquipmentIds = bFilterByEquipmentIds; + invalidateFilter(); +} + + +void TelegramProxyModel::setAllowedEquipmentIds(const std::set &allowedEquipmentIds) +{ + if (m_allowedEquipmentIds == allowedEquipmentIds) + return; + m_allowedEquipmentIds = allowedEquipmentIds; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilteredCentralTelegramIds(const std::set &filteredCentralTelegramIds) +{ + if (m_filteredCentralTelegramIds == filteredCentralTelegramIds) + return; + m_filteredCentralTelegramIds = filteredCentralTelegramIds; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilteredTetraTelegramIds(const std::set &filteredTetraTelegramIds) +{ + if (m_filteredTetraTelegramIds == filteredTetraTelegramIds) + return; + m_filteredTetraTelegramIds = filteredTetraTelegramIds; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilteredWlsTelegramIds(const std::set &filteredWlsTelegramIds) +{ + if (m_filteredWlsTelegramIds == filteredWlsTelegramIds) + return; + m_filteredWlsTelegramIds = filteredWlsTelegramIds; + invalidateFilter(); +} + + + +void TelegramProxyModel::setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, + bool bFilter) +{ + std::set curFilter = m_filterCentralTelegrams; + if (bFilter) + curFilter.insert(direction); + else + curFilter.erase(direction); + if (curFilter == m_filterCentralTelegrams) + return; + m_filterCentralTelegrams = curFilter; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, + bool bFilter) +{ + std::set curFilter = m_filterTetraTelegrams; + if (bFilter) + curFilter.insert(direction); + else + curFilter.erase(direction); + if (curFilter == m_filterTetraTelegrams) + return; + m_filterTetraTelegrams = curFilter; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType, + bool bFilter) +{ + std::set curFilter = m_filterTetraPDU; + if (bFilter) + curFilter.insert(pduType); + else + curFilter.erase(pduType); + if (curFilter == m_filterTetraPDU) + return; + m_filterTetraPDU = curFilter; + invalidateFilter(); +} + +void TelegramProxyModel::setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, + bool bFilter) +{ + std::set curFilter = m_filterWlsTelegrams; + if (bFilter) + curFilter.insert(direction); + else + curFilter.erase(direction); + if (curFilter == m_filterWlsTelegrams) + return; + m_filterWlsTelegrams = curFilter; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilterTetraLogin(bool bFilter) +{ + if (m_bFilterLoginTelegrams == bFilter) + return; + m_bFilterLoginTelegrams = bFilter; + invalidateFilter(); +} + + +void TelegramProxyModel::setFilterTetraFragmented(bool bFilter) +{ + if (m_bFilterFragmentedTelegrams == bFilter) + return; + m_bFilterFragmentedTelegrams = bFilter; + invalidateFilter(); +} + + +QSharedPointer TelegramProxyModel::telegram(int row) const +{ + const TelegramModel *tm = qobject_cast(sourceModel()); + if (!tm) + return {}; + const int srcRow = mapToSource(index(row, 0)).row(); + return tm->telegram(srcRow); +} + + +bool TelegramProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if (left.column() != right.column()) + return QSortFilterProxyModel::lessThan(left, right); + const TelegramModel *tm = qobject_cast(sourceModel()); + if (!tm) + return QSortFilterProxyModel::lessThan(left, right); + QSharedPointer teleLeft = tm->telegram(left.row()); + QSharedPointer teleRight = tm->telegram(right.row()); + if (!teleLeft || !teleRight) + return QSortFilterProxyModel::lessThan(left, right); + + switch (left.column()) + { + case 0: + return teleLeft->getDestination() < teleRight->getDestination(); + case 1: + return teleLeft->getName() < teleRight->getName(); + case 2: + return teleLeft->getParticipantId() < teleRight->getParticipantId(); + case 3: + return teleLeft->getLogTime() < teleRight->getLogTime(); + case 4: + return teleLeft->getGpsTime() < teleRight->getGpsTime(); + case 5: + return teleLeft->getDelay() < teleRight->getDelay(); + } + return QSortFilterProxyModel::lessThan(left, right); +} + + +bool TelegramProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + + const TelegramModel *tm = qobject_cast(sourceModel()); + if (!tm) + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + + QSharedPointer tele = tm->telegram(source_row); + if (!tele) + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + + if (m_bFilterByEquipmentIds) + { + int equipId = tele->getParticipantId(); + if (m_allowedEquipmentIds.find(equipId) == m_allowedEquipmentIds.end()) + return false; + } + switch (tele->getProtocol()) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + if (!m_filteredCentralTelegramIds.empty()) + { + const int telegramId = tele->getTelId(); + if (m_filteredCentralTelegramIds.find(telegramId) != m_filteredCentralTelegramIds.end()) + return false; + } + if (!m_filterCentralTelegrams.empty()) + { + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection(); + if (m_filterCentralTelegrams.find(direction) != m_filterCentralTelegrams.end()) + return false; + } + break; + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + if (!m_filteredTetraTelegramIds.empty()) + { + const int telegramId = tele->getTelId(); + if (m_filteredTetraTelegramIds.find(telegramId) != m_filteredTetraTelegramIds.end()) + return false; + } + if (!m_filterTetraTelegrams.empty()) + { + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection(); + if (m_filterTetraTelegrams.find(direction) != m_filterTetraTelegrams.end()) + return false; + } + const N_CoPrtCnv::CoPrtCnvRadioTelegram *tetraTelegram = tele->getTetraTelegram(); + if (tetraTelegram) + { + if (!m_filterTetraPDU.empty()) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType = tetraTelegram->getPDU_Type(); + if (m_filterTetraPDU.find(pduType) != m_filterTetraPDU.end()) + return false; + } + if (m_bFilterLoginTelegrams) + { + if (tetraTelegram->isLoginTelegram()) + return false; + } + if (m_bFilterFragmentedTelegrams) + { + if (!tetraTelegram->isLoginTelegram() && !tetraTelegram->isNormalTelegram()) + return false; + } + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: + if (!m_filteredWlsTelegramIds.empty()) + { + const int telegramId = tele->getTelId(); + if (m_filteredWlsTelegramIds.find(telegramId) != m_filteredWlsTelegramIds.end()) + return false; + } + if (!m_filterWlsTelegrams.empty()) + { + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction = tele->getDirection(); + if (m_filterWlsTelegrams.find(direction) != m_filterWlsTelegrams.end()) + return false; + } + break; + default: + break; + } + return true; +} +} diff --git a/TetraIF/LogView/LogViewModels.hpp b/TetraIF/LogView/LogViewModels.hpp new file mode 100644 index 000000000..77f861126 --- /dev/null +++ b/TetraIF/LogView/LogViewModels.hpp @@ -0,0 +1,109 @@ + + + +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + +class ParticipantModel final : public QAbstractTableModel +{ + Q_OBJECT +public: + using QAbstractTableModel::QAbstractTableModel; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + + void clearParticipants(); + bool addUpdateParticipants(const QVector &eqIds, + const QVector &issis, + const QVector &numberOfTelegrams); +protected: + void updateHeatMap() const; +protected: + + QVector > m_particpants; + + QHash m_particpantMap; + + mutable QHash m_participantHeatmap; +}; + +class TelegramModel final : public QAbstractTableModel +{ + Q_OBJECT +public: + using QAbstractTableModel::QAbstractTableModel; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + + void clearTelegrams(); + void appendTelegrams(const QVector > &telegrams); + void appendTelegram(const QSharedPointer &telegram); + QSharedPointer telegram(int row) const; +protected: + QVector > m_telegrams; +}; + +class TelegramProxyModel final : public QSortFilterProxyModel +{ + Q_OBJECT +public: + using QSortFilterProxyModel::QSortFilterProxyModel; + + void setFilterByEquipmentIds(bool bFilterByEquipmentIds); + void setAllowedEquipmentIds(const std::set &allowedEquipmentIds); + + void setFilteredCentralTelegramIds(const std::set &filteredCentralTelegramIds); + void setFilteredTetraTelegramIds(const std::set &filteredTetraTelegramIds); + void setFilteredWlsTelegramIds(const std::set &filteredWlsTelegramIds); + + void setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter); + void setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter); + void setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type pduType, bool bFilter); + void setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol direction, bool bFilter); + + void setFilterTetraLogin(bool bFilter); + void setFilterTetraFragmented(bool bFilter); + + QSharedPointer telegram(int row) const; +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +protected: + std::set m_allowedEquipmentIds; + std::set m_filteredCentralTelegramIds; + std::set m_filteredTetraTelegramIds; + std::set m_filteredWlsTelegramIds; + bool m_bFilterByEquipmentIds = false; + bool m_bFilterLoginTelegrams = false; + bool m_bFilterFragmentedTelegrams = false; + std::set m_filterCentralTelegrams; + std::set m_filterTetraTelegrams; + std::set m_filterWlsTelegrams; + std::set m_filterTetraPDU; +}; + +} diff --git a/TetraIF/LogView/LogViewOptionDialog.cpp b/TetraIF/LogView/LogViewOptionDialog.cpp new file mode 100644 index 000000000..d159ea971 --- /dev/null +++ b/TetraIF/LogView/LogViewOptionDialog.cpp @@ -0,0 +1,182 @@ + + + + + + + + + + + + + +#include "LogViewOptionDialog.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace N_LogView +{ + + +const QString LogViewOptionDialog::SPEC_FILES = tr("Spezifikations-Dateien (*.x)"); +const QString LogViewOptionDialog::KRLOG_FILES = tr("Log-Dateien (*.krlog)"); +const QLatin1String LogViewOptionDialog::SPEC_FILES_GROUP("SpecFiles"); +const QLatin1String LogViewOptionDialog::DIR("Dir"); +const QLatin1String LogViewOptionDialog::P0_FILENAME("Central2PrtCnv"); +const QLatin1String LogViewOptionDialog::P5_FILENAME("PrtCnv2TETRA"); +const QLatin1String LogViewOptionDialog::SERVER_GROUP("ServerPorts"); +const QLatin1String LogViewOptionDialog::CENTRAL_PORT("Central"); +const QLatin1String LogViewOptionDialog::TETRA_PORT("Tetra"); +const QLatin1String LogViewOptionDialog::LOG_FILENAME("LogFilename"); +const QLatin1String LogViewOptionDialog::INJECTION_GROUP("InjectionServer"); +const QLatin1String LogViewOptionDialog::INJECTION_HOSTNAME("InjectionHostname"); +const QLatin1String LogViewOptionDialog::INJECTION_PORT("InjectionPort"); + + + +LogViewOptionDialog::LogViewOptionDialog(QWidget* a_parent) + : QDialog(a_parent) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + + m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + QGroupBox* groupBox = new QGroupBox(tr("Telegramm-Spezifikations-Dateien"), this); + layout->addWidget(groupBox); + + QGridLayout* groupLayout = new QGridLayout(); + + QLabel* p0Label = new QLabel(tr("&Zentrale - Protokollkonverter"), this); + groupLayout->addWidget(p0Label, 0, 0, 1, 2); + QString defString = QCoreApplication::applicationDirPath() + QLatin1String("/training_area_telegrams.h"); + m_P0Edit = new QLineEdit(m_Settings.value(P0_FILENAME, defString).toString(), this); + m_P0Edit->setMinimumWidth(400); + groupLayout->addWidget(m_P0Edit); + QPushButton* p0Browse = new QPushButton(tr("Browse"), this); + p0Label->setBuddy(p0Browse); + connect(p0Browse, &QPushButton::clicked, this, &LogViewOptionDialog::browseP0File); + groupLayout->addWidget(p0Browse, 1, 1); + + QLabel* p5Label = new QLabel(tr("Protokollkonverter - &TETRA"), this); + groupLayout->addWidget(p5Label, 2, 0, 1, 2); + defString = QCoreApplication::applicationDirPath() + QLatin1String("/zsksxd_tetraForLogView.x"); + m_P5Edit = new QLineEdit(m_Settings.value(P5_FILENAME, defString).toString(), this); + groupLayout->addWidget(m_P5Edit); + QPushButton* p5Browse = new QPushButton(tr("Browse"), this); + p5Label->setBuddy(p5Browse); + connect(p5Browse, &QPushButton::clicked, this, &LogViewOptionDialog::browseP5File); + groupLayout->addWidget(p5Browse, 3, 1); + + groupBox->setLayout(groupLayout); + m_Settings.endGroup(); + + + m_Settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP); + groupBox = new QGroupBox(tr("Telegram Injection Server"), this); + layout->addWidget(groupBox); + QGridLayout* injectLayout = new QGridLayout(); + + QLabel* injectPortLabel = new QLabel(tr("Port"), this); + injectLayout->addWidget(injectPortLabel, 1, 0); + m_InjectPortEdit = new QLineEdit(m_Settings.value(INJECTION_PORT).toString(), this); + QIntValidator* validator = new QIntValidator(1024, 65535, this); + m_InjectPortEdit->setValidator(validator); + injectLayout->addWidget(m_InjectPortEdit, 1, 1); + + QLabel* injectHostnameLabel = new QLabel(tr("Hostname"), this); + injectLayout->addWidget(injectHostnameLabel, 0, 0); + m_InjectHostnameEdit = new QLineEdit(m_Settings.value(INJECTION_HOSTNAME).toString(), this); + injectLayout->addWidget(m_InjectHostnameEdit, 0, 1); + + groupBox->setLayout(injectLayout); + m_Settings.endGroup(); + + + layout->addStretch(); + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &LogViewOptionDialog::save); + connect(buttonBox, &QDialogButtonBox::rejected, this, &LogViewOptionDialog::reject); + layout->addWidget(buttonBox); + + +} + + + +void LogViewOptionDialog::browseP0File() +{ + QString newFilename = QFileDialog::getOpenFileName(this, + tr("Zentrale - Protokollkonverter Spezifikations-Datei"), + m_Settings.value(DIR).toString(), + tr("TrainingArea Telegram Headerdatei (training_area_telegrams.h)")); + if (!newFilename.isEmpty()) + { + m_P0Edit->setText(newFilename); + QDir dir; + m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + m_Settings.setValue(DIR, dir.filePath(newFilename)); + m_Settings.endGroup(); + } +} + + + +void LogViewOptionDialog::browseP5File() +{ + QString newFilename = QFileDialog::getOpenFileName(this, tr("Protokollkonverter - TETRA Spezifikations-Datei"), m_Settings.value(DIR).toString(), SPEC_FILES); + if (!newFilename.isEmpty()) + { + m_P5Edit->setText(newFilename); + QDir dir; + m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + m_Settings.setValue(DIR, dir.filePath(newFilename)); + m_Settings.endGroup(); + } +} + + +void LogViewOptionDialog::save() +{ + uint32_t changedFlags = 0; + + + + m_Settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); + QString string = m_Settings.value(P0_FILENAME).toString(); + if ((string != m_P0Edit->text()) || + (m_Settings.value(P5_FILENAME).toString() != m_P5Edit->text())) + { + m_Settings.setValue(P0_FILENAME, m_P0Edit->text()); + m_Settings.setValue(P5_FILENAME, m_P5Edit->text()); + changedFlags |= SpecFilesGroup; + } + m_Settings.endGroup(); + + + m_Settings.beginGroup(LogViewOptionDialog::INJECTION_GROUP); + if ((m_Settings.value(INJECTION_HOSTNAME).toString() != m_InjectHostnameEdit->text()) || + (m_Settings.value(INJECTION_PORT).toString() != m_InjectPortEdit->text())) + { + m_Settings.setValue(INJECTION_HOSTNAME, m_InjectHostnameEdit->text()); + m_Settings.setValue(INJECTION_PORT, m_InjectPortEdit->text()); + changedFlags |= InjectionGroup; + } + m_Settings.endGroup(); + + emit settingsChanged(changedFlags); + + accept(); +} + +} diff --git a/TetraIF/LogView/LogViewOptionDialog.hpp b/TetraIF/LogView/LogViewOptionDialog.hpp new file mode 100644 index 000000000..c655d0a2a --- /dev/null +++ b/TetraIF/LogView/LogViewOptionDialog.hpp @@ -0,0 +1,77 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include + +class QLineEdit; + +namespace N_LogView +{ + + +class LogViewOptionDialog : public QDialog +{ + Q_OBJECT +public: + + enum SettingsChangedFlag { + SpecFilesGroup = 0x01, + ServerGroup = 0x02, + InjectionGroup = 0x04 + }; + + static const QString KRLOG_FILES; + static const QLatin1String SPEC_FILES_GROUP; + static const QLatin1String P0_FILENAME; + static const QLatin1String P5_FILENAME; + static const QLatin1String SERVER_GROUP; + static const QLatin1String CENTRAL_PORT; + static const QLatin1String TETRA_PORT; + static const QLatin1String SIZE; + static const QLatin1String POS; + static const QLatin1String CENTRAL_IS_SERVER; + static const QLatin1String CENTRAL_HOSTNAME; + static const QLatin1String LOG_FILENAME; + static const QLatin1String INJECTION_GROUP; + static const QLatin1String INJECTION_HOSTNAME; + static const QLatin1String INJECTION_PORT; + + + + + explicit LogViewOptionDialog(QWidget* a_parent); + +signals: + void settingsChanged(uint32_t changed); + +protected: + + static const QString SPEC_FILES; + static const QLatin1String DIR; + bool m_IsServer; + QLineEdit *m_P0Edit; + QLineEdit *m_P5Edit; + QSettings m_Settings; + QLineEdit *m_InjectHostnameEdit; + QLineEdit *m_InjectPortEdit; + +protected slots: + void browseP0File(); + void browseP5File(); + void save(); +}; + +} diff --git a/TetraIF/LogView/LogViewResources.qrc b/TetraIF/LogView/LogViewResources.qrc new file mode 100644 index 000000000..4407b4f20 --- /dev/null +++ b/TetraIF/LogView/LogViewResources.qrc @@ -0,0 +1,18 @@ + + + image/P2C.png + image/C2P.png + image/P2W.png + image/W2P.png + image/P2T.png + image/T2P.png + image/Central.png + image/Tetra.png + image/TNE.png + image/GreenLamp.png + image/RedLamp.png + image/YellowLamp.png + image/ShowSend.png + image/Wls.png + + diff --git a/TetraIF/LogView/LogViewSpinBox.cpp b/TetraIF/LogView/LogViewSpinBox.cpp new file mode 100644 index 000000000..904caa08c --- /dev/null +++ b/TetraIF/LogView/LogViewSpinBox.cpp @@ -0,0 +1,59 @@ + + + + + + + + + + + + + +#include "LogViewSpinBox.hpp" +#include "LogViewField.hpp" + +namespace N_LogView +{ + + +LogViewSpinBox::LogViewSpinBox(LogViewField* a_field, QWidget* a_parent, const int a_value) + : QSpinBox(a_parent) + , LogViewWidget(a_field, this, a_parent, false) +{ + + uint16_t maxArraySize = a_field->maxArraySize(); + setRange(0, maxArraySize); + + + setValue(a_value); + + + setToolTip(tr("Wertebereich: 0..%1").arg(maxArraySize)); + + + connect(this, &LogViewSpinBox::editingFinished, + this, &LogViewSpinBox::finishEditing); +} + + + +void LogViewSpinBox::finishEditing() +{ + emit valueEditingFinished(text().toInt()); +} + + + + + + +bool LogViewSpinBox::saveContent(LogViewTelegram* a_telegram) +{ + Q_UNUSED(a_telegram); + + return false; +} + +} diff --git a/TetraIF/LogView/LogViewSpinBox.hpp b/TetraIF/LogView/LogViewSpinBox.hpp new file mode 100644 index 000000000..40e9489f6 --- /dev/null +++ b/TetraIF/LogView/LogViewSpinBox.hpp @@ -0,0 +1,45 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "LogViewWidget.hpp" + +namespace N_LogView +{ + + + class LogViewSpinBox : public QSpinBox, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewSpinBox(LogViewField* a_field, QWidget* a_parent, const int a_value); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + protected slots: + void finishEditing(); + + signals: + + + void valueEditingFinished(int a_newValue); + + }; + +} diff --git a/TetraIF/LogView/LogViewTabWidget.cpp b/TetraIF/LogView/LogViewTabWidget.cpp new file mode 100644 index 000000000..fe1b5f289 --- /dev/null +++ b/TetraIF/LogView/LogViewTabWidget.cpp @@ -0,0 +1,139 @@ + + + + + + + + + + + + + +#include "LogViewTabWidget.hpp" +#include +#include +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" +#include "LogViewTelegramDialog.hpp" +#include "LogViewSpinBox.hpp" +#include "LogViewTelegram.hpp" +#include "LogViewTetraTelegramsParser.hpp" + +namespace N_LogView +{ + + +LogViewTabWidget::LogViewTabWidget(LogViewField* a_field, LogViewTelegramDialog* a_parent, LogViewSpinBox* a_spinBox) + : QTabWidget(a_parent) + , LogViewWidget(a_field, this, a_parent, false) + , m_TelegramDialog(a_parent) + , m_SpinBox(a_spinBox) +{ + setVisible(false); +} + + + +void LogViewTabWidget::changeSize(const int a_newSize) +{ + + for (int i = count(); i < a_newSize; i++) + addTab(m_Field, true, i); + + + while (count() > a_newSize) + { + QStringList path = m_Field->jsonPath(); + path += QStringLiteral("index: %1").arg(count() - 1); + m_TelegramDialog->removeItemsFromEditInfoList(path); + removeTab(count() - 1); + } + while (m_Field->childCount() > a_newSize) + m_Field->removeLastChild(); + + + setVisible(a_newSize > 0); + m_TelegramDialog->makePretty(); +} + + + + + + +bool LogViewTabWidget::saveContent(LogViewTelegram* a_telegram) +{ + if (a_telegram->isJsonTelegram()) + return true; + + if (m_SpinBox) + { + if (!isValid()) + return false; + a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, count()); + } + return true; +} + + + +void LogViewTabWidget::addTab(LogViewField* a_field, const bool a_isEmpty, int arrayIdx) +{ + if (arrayIdx < 0) + { + WARNING_LOG(m_logger) << "Invalid array index given: " << arrayIdx; + return; + } + + QFrame *frame = new QFrame; + QGridLayout *box = new QGridLayout(frame); + QTabWidget::addTab(frame, QStringLiteral("%1 %2").arg(a_field->cleanName()).arg(count()+1)); + if (a_isEmpty) + a_field->setHasContent(false); + auto *childTree = a_field->child(arrayIdx); + while (!childTree) + { + const auto *first = a_field->child(0); + if (first) + { + LogViewField *fNew = first->clone(arrayIdx); + a_field->addChild(fNew); + childTree = a_field->child(arrayIdx); + } + else + { + LogViewTetraTelegramsParser *p = LogViewTelegram::jsonParser(); + const StructInformation si = p->structFromType(a_field->type()); + if (si.type != a_field->type()) + { + WARNING_LOG(m_logger) << "Could not find type '" << a_field->type() << "' - can not add substructure"; + return; + } + LogViewField *tc = new LogViewField(a_field->name() + QStringLiteral("TabChild"), LogViewField::e_FieldKindTabChild, a_field->xdrElement()); + tc->setJsonPath(a_field->jsonPath()); + a_field->addChild(tc); + const QString path(QStringLiteral("index: %1")); + LogViewTelegram::addFieldTreeStruct(QJsonObject(), tc, si, path.arg(arrayIdx), m_logger); + childTree = a_field->child(arrayIdx); + } + } + m_TelegramDialog->showTree(childTree, box); + + + + + + + if (m_SpinBox) + { + int spinValue = m_SpinBox->value(); + if (spinValue < count()) + m_SpinBox->setValue(count()); + } + + setVisible(true); +} + +} diff --git a/TetraIF/LogView/LogViewTabWidget.hpp b/TetraIF/LogView/LogViewTabWidget.hpp new file mode 100644 index 000000000..fae2554ff --- /dev/null +++ b/TetraIF/LogView/LogViewTabWidget.hpp @@ -0,0 +1,49 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "LogViewWidget.hpp" + + +namespace N_LogView +{ + class LogViewTelegramDialog; + class LogViewSpinBox; + + + + class LogViewTabWidget : public QTabWidget, public LogViewWidget + { + Q_OBJECT + public: + + LogViewTabWidget(LogViewField* a_field, LogViewTelegramDialog* a_parent, LogViewSpinBox* a_spinBox); + + bool saveContent(LogViewTelegram* a_telegram) override; + void addTab(LogViewField* a_field, const bool a_isEmpty, int arrayIdx); + + public slots: + + + void changeSize(const int a_newSize); + + protected: + + LogViewTelegramDialog* m_TelegramDialog; + LogViewSpinBox* m_SpinBox; + + }; + +} diff --git a/TetraIF/LogView/LogViewTableWidget.cpp b/TetraIF/LogView/LogViewTableWidget.cpp new file mode 100644 index 000000000..26625de34 --- /dev/null +++ b/TetraIF/LogView/LogViewTableWidget.cpp @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + +#include "LogViewTableWidget.hpp" +#include "LogViewField.hpp" +#include +#include +#include "LogViewXdrStandardType.hpp" +#include "LogViewTelegram.hpp" +#include "LogViewEnumEdit.hpp" + +namespace N_LogView +{ + + +LogViewTableWidget::LogViewTableWidget(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QTableWidget(0, 2, a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) + , m_IsFloat(false) + , m_IsEnum(false) +{ + switch (m_Field->xdrElement()->getKind()) + { + case LogViewXdrElement::e_KindEnum: + m_IsEnum = true; + break; + default: + m_IsFloat = LogViewXdrStandardType::e_Float == static_cast(m_Field->xdrElement())->getValueKind(); + } + if (!m_IsFloat) + setColumnCount(3); + if (m_IsEnum) + setColumnCount(1); + + setHorizontalHeaderItem(0, new QTableWidgetItem(m_IsEnum ? tr("Enum") : tr("Dez"))); + if (!m_IsEnum) + { + setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Hex"))); + if (!m_IsFloat) + { + setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Bin"))); + } + } + setAlternatingRowColors(true); + + + + + updateToolTip(); + + + + + + + + + int nbrOfRows = a_field->valueListSize(); + setRowCount(nbrOfRows); + for (int i = 0; i < nbrOfRows; i++) + changeRow(i, a_field->value(i)); + + makePretty(); + + + connect(this, &LogViewTableWidget::itemChanged, + this, &LogViewTableWidget::checkAndOvertakeContent); +} + + + +void LogViewTableWidget::changeSize(const int a_newSize) +{ + setRowCount(a_newSize); + + disconnect(this, &LogViewTableWidget::itemChanged, + this, &LogViewTableWidget::checkAndOvertakeContent); + + for (int i = 0; i < a_newSize; i++) + changeRow(i, QLatin1String("0")); + + connect(this, &LogViewTableWidget::itemChanged, + this, &LogViewTableWidget::checkAndOvertakeContent); + + makePretty(); + + m_Valid = true; +} + + + +void LogViewTableWidget::changeRow(const int a_rowIndex, const QString& a_value) +{ + + + if (m_IsEnum) + { + + QWidget* enumItem = cellWidget(a_rowIndex, 0); + if (!enumItem) + setCellWidget(a_rowIndex, 0, new LogViewEnumEdit(m_Field, this, m_Readonly, a_rowIndex)); + } + else + { + QFont font; + font.setStyleHint(QFont::TypeWriter); + font.setFamily(QString()); + + QTableWidgetItem* decItem = item(a_rowIndex, 0); + if (!decItem) + { + decItem = new QTableWidgetItem(); + + decItem->setText(a_value); + decItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + if (!m_Readonly) + { + decItem->setFlags(decItem->flags() | Qt::ItemIsEditable); + } + decItem->setFont(font); + decItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); + setItem(a_rowIndex, 0, decItem); + } + + + QTableWidgetItem* hexItem = item(a_rowIndex, 1); + if (!hexItem) + { + hexItem = new QTableWidgetItem(); + hexItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + hexItem->setFont(font); + hexItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); + setItem(a_rowIndex, 1, hexItem); + } + + + if (!m_IsFloat) + { + QTableWidgetItem* binItem = item(a_rowIndex, 2); + if (!binItem) + { + binItem = new QTableWidgetItem(); + binItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + binItem->setFont(font); + binItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); + setItem(a_rowIndex, 2, binItem); + } + } + + + checkAndOvertakeContent(decItem); + makePretty(); + } +} + + + +void LogViewTableWidget::checkAndOvertakeContent(QTableWidgetItem* a_changedItem) +{ + if (a_changedItem->column() != 0) return; + + int row = a_changedItem->row(); + QString text = a_changedItem->text(); + + + bool ok; + int64_t intValue = 0; + double floatValue = 0.0; + + + if (m_IsFloat) + floatValue = getFloat(text, (uint64_t&)intValue, ok, true); + else + intValue = getInteger(text, ok); + + + if (!ok) + { + setFocus(); + + setCurrentCell(row, 0); + return; + } + + + QTableWidgetItem* decField = item(row, 0); + if (decField) decField->setText(QString::number(m_IsFloat ? floatValue : intValue)); + + + QTableWidgetItem* hexField = item(row, 1); + if (hexField) hexField->setText(toHex(intValue)); + + + if (!m_IsFloat) + { + QTableWidgetItem* binField = item(row, 2); + if (binField) binField->setText(toBin(intValue)); + } +} + + + +void LogViewTableWidget::makePretty() +{ + + resizeColumnsToContents(); + resizeRowsToContents(); + + + + + + + + + + + + + + +} + + + + + + +bool LogViewTableWidget::saveContent(LogViewTelegram* a_telegram) +{ + if (!isValid()) + return false; + + if (a_telegram->isJsonTelegram()) + { + if (m_Field->kind() == LogViewField::e_FieldKindPodArray) + { + QJsonArray arr; + for (int i = 0; i < rowCount(); ++i) + arr += item(i, 0)->text().toInt(); + a_telegram->setJsonValue(m_Field->jsonPath(), arr); + } + else + { + QString value; + value.reserve(rowCount() * 2); + for (int i = 0; i < rowCount(); ++i) + { + int val = item(i, 0)->text().toInt(); + value += QStringLiteral("%1").arg(val, 2, 16, QLatin1Char('0')); + } + a_telegram->setJsonValue(m_Field->jsonPath(), value); + } + return true; + } + + uint16_t arraySize; + if (m_Field->isDynamicArray()) + { + arraySize = rowCount(); + a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, arraySize); + + } + else + { + + arraySize = m_Field->maxArraySize(); + } + + INFO_LOG(m_logger) << "arraySize=" << arraySize; + for (int i = 0; i < arraySize; i++) + { + if (m_IsEnum) + { + LogViewEnumEdit *enumEdit = dynamic_cast(cellWidget(i,0)); + enumEdit->saveContent(a_telegram); + } + else + { + uint16_t size = getSize(); + QString text = item(i, 0)->text(); + if (!m_IsFloat) + { + a_telegram->setUIntX(size, text.toULong()); + } + else + { + const LogViewXdrStandardType *stdType = static_cast(m_Field->xdrElement()); + LogViewXdrStandardType::E_ByteOrder byteOrder = stdType->getByteOrder(); + uint64_t hex; + getFloat(text, hex, m_Valid); + a_telegram->setUIntX(size, hex, byteOrder); + } + } + } + + return true; +} + +} diff --git a/TetraIF/LogView/LogViewTableWidget.hpp b/TetraIF/LogView/LogViewTableWidget.hpp new file mode 100644 index 000000000..9b48f3045 --- /dev/null +++ b/TetraIF/LogView/LogViewTableWidget.hpp @@ -0,0 +1,46 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "LogViewWidget.hpp" + +namespace N_LogView +{ + + + class LogViewTableWidget : public QTableWidget, public LogViewWidget + { + Q_OBJECT + public: + LogViewTableWidget(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + public slots: + void changeSize(const int a_newSize); + + protected: + void changeRow(const int a_rowIndex, const QString& a_value); + void makePretty(); + protected slots: + void checkAndOvertakeContent(QTableWidgetItem* a_changedItem); + + private: + bool m_IsFloat; + bool m_IsEnum; + }; +} diff --git a/TetraIF/LogView/LogViewTelegram.cpp b/TetraIF/LogView/LogViewTelegram.cpp new file mode 100644 index 000000000..1ee9284f8 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegram.cpp @@ -0,0 +1,1768 @@ + + + + + + + + + + + + + +#include "LogViewTelegram.hpp" + +#include +#include +#include +#include +#include "LogViewXdrParser.hpp" +#include "LogViewXdrStruct.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewXdrType.hpp" +#include "LogViewTetraTelegramsParser.hpp" + +#include "LogViewField.hpp" +#include +#include +#include +#include +#include +#include + + +namespace N_LogView +{ + + +const LogViewXdrParser* LogViewTelegram::m_Parser = nullptr; +const uint16_t LogViewTelegram::START_OFFSET_CENTRAL = 12; +const uint16_t LogViewTelegram::POS_CENTRAL_COUNTER = 4; +const uint16_t LogViewTelegram::POS_CENTRAL_TELID = 8; +const uint16_t LogViewTelegram::POS_CENTRAL_PARTICIPANTID = 12; +const uint16_t LogViewTelegram::START_OFFSET_TETRA_REGISTER = 5; +const uint16_t LogViewTelegram::START_OFFSET_TETRA_AIRLOAD = 5; +const uint16_t LogViewTelegram::START_OFFSET_TETRA_DATA = 28; +const uint16_t LogViewTelegram::START_OFFSET_TETRA_LOGIN = 27; +const uint16_t LogViewTelegram::START_OFFSET_TETRA_FRAGMENT = 26; +const uint16_t LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE = 4; + + + + +LogViewTelegram::LogViewTelegram(const LogViewTelegram &o) + : m_Name(o.m_Name) + , m_ToolTipText(o.m_ToolTipText) + , m_WaitTime(o.m_WaitTime) + , m_ParticipantId(o.m_ParticipantId) + , m_ISSI(o.m_ISSI) + , m_AllocatedSize(o.m_AllocatedSize) + , m_ActOffset(o.m_ActOffset) + , m_GpsFieldOffset(o.m_GpsFieldOffset) + , m_TelId(o.m_TelId) + , m_LastUnsignedValue(o.m_LastUnsignedValue) + , m_MaxArraySize(o.m_MaxArraySize) + , m_DynArraySizeMethod(o.m_DynArraySizeMethod) + , m_Destination(o.m_Destination) + , m_Validity(o.m_Validity) + , m_Protocol(o.m_Protocol) + , m_LogTime(o.m_LogTime) + , m_logTimeText(o.m_logTimeText) + , m_GpsTime(o.m_GpsTime) + , m_data(o.m_data) + , m_json(o.m_json) + , m_TetraTelegram(nullptr) + , m_logger(getLogger("LogViewTelegram")) +{ + if (!m_data.isEmpty()) + m_TetraTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(m_data); +} + + + + + +LogViewTelegram::LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, + int telegramId) + : m_WaitTime(1000) + , m_ParticipantId(0) + , m_ISSI(0) + , m_AllocatedSize(0) + , m_ActOffset(0) + , m_GpsFieldOffset(QVector()) + , m_TelId(telegramId) + , m_LastUnsignedValue(0) + , m_MaxArraySize(0) + , m_DynArraySizeMethod(LogViewXdrStandardType::e_DynArrayMsgLength) + , m_Destination(a_destination) + , m_Validity(e_NotYetEvaluated) + , m_Protocol(static_cast(a_destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask)) + , m_LogTime(0) + , m_GpsTime(0) + , m_TetraTelegram(nullptr) + , m_logger(getLogger("LogViewTelegram")) +{ + const uint32_t &waitTime = qgetenv("LogViewWaitTime").toUInt(); + if (waitTime > 0) + m_WaitTime = waitTime; + m_ToolTipText.resize(e_ColMax); + switch (m_Protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + { + m_Name = jsonParser()->nameFromTelegramId(m_TelId); + m_json[QStringLiteral("type")] = m_Name; + m_json[QStringLiteral("typeId")] = m_TelId; + break; + } + default: + showMessageBox(QObject::tr("Nur Zentral-Telegramme sind erlaubt")); + } +} + + + + + +LogViewTelegram::LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, + const quint64 a_unixTime, + const QByteArray &a_telegramData) + : m_WaitTime(1000) + , m_ParticipantId(0) + , m_ISSI(0) + , m_AllocatedSize(0) + , m_ActOffset(0) + , m_GpsFieldOffset(QVector()) + , m_TelId(0) + , m_LastUnsignedValue(0) + , m_MaxArraySize(0) + , m_DynArraySizeMethod(LogViewXdrStandardType::e_DynArrayMsgLength) + , m_Destination(a_destination) + , m_Validity(e_NotYetEvaluated) + , m_Protocol(static_cast(a_destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask)) + , m_LogTime(a_unixTime) + , m_GpsTime(0) + , m_data(a_telegramData) + , m_TetraTelegram(nullptr) + , m_logger(getLogger("LogViewTelegram")) +{ + const uint32_t &waitTime = qgetenv("LogViewWaitTime").toUInt(); + if (waitTime > 0) + m_WaitTime = waitTime; + m_ToolTipText.resize(e_ColMax); + + switch (m_Protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: + { + m_json = QJsonDocument::fromJson(a_telegramData).object(); + m_TelId = m_json.value(QLatin1String("typeId")).toInt(); + + + m_Name = m_json.value(QLatin1String("type")).toString(); + switch (getTelId()) + { + case TrainingAreaBase::TetraIcd::BESTAETIGUNG: + break; + default: + + + + m_ParticipantId = m_json.value(QLatin1String("data")) + .toObject().value(QLatin1String("header")) + .toObject().value(QLatin1String("equipmentNumber")).toInt(); + break; + } + break; + } + + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + m_TetraTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(m_data); + + switch (m_TetraTelegram->getPDU_Type()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: + m_Name = QObject::tr("TETRA-Register-Indication"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + m_Name = QObject::tr("TETRA-Register-Response"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: { + if (m_TetraTelegram->isLoginTelegram()) + { + m_Name = QObject::tr("TETRA-Login-Telegramm"); + m_ParticipantId = m_TetraTelegram->getIdentity(); + } + else if (m_TetraTelegram->isNormalTelegram()) + { + + m_TelId = m_TetraTelegram->getTelID(); + m_Name = tetraParser()->getTelegramName(m_TelId); + m_ParticipantId = m_TetraTelegram->getIdentity(); + + if (getDirection() == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend) + { + + uint16_t gpsTimeOffset = 2; + switch (m_TelId) + { + case GEF_DEAKTIVIERUNG_EINZELMINE: + gpsTimeOffset = 4; + break; + default: + gpsTimeOffset = 2; + } + m_GpsTime = getUInt32(START_OFFSET_TETRA_DATA+gpsTimeOffset); + } + } + else + { + + switch (m_TetraTelegram->getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + m_Name = QObject::tr("1. Fragment eines TETRA-Telegrammes"); + m_ParticipantId = m_TetraTelegram->getIdentity(); + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + m_Name = QObject::tr("%1.-letztes Fragment eines TETRA-Telegrammes").arg(m_TetraTelegram->getFragmentCounter()+1); + + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + m_Name = QObject::tr("Letztes Fragment eines TETRA-Telegrammes"); + + break; + default: + m_Name = QObject::tr("TETRA-Telegramm mit Fragment-Status=%1 ist nicht implementiert").arg(m_TetraTelegram->getFragmentStatus()); + break; + } + } + + if ((m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask) == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive) + { + m_ISSI = m_TetraTelegram->getDestISSI(); + } + else + { + m_ISSI = m_TetraTelegram->getSrcISSI(); + } + break; + } + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + m_Name = QObject::tr("Report-Indication/Request"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_GroupMonitorReq: + m_Name = QObject::tr("Group monitoring Request"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: + m_Name = QObject::tr("Status Indication/Request"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + m_Name = QObject::tr("AirInterfaceLoad-Request"); + break; + + default: + + + + m_Name = QObject::tr("PDU-Type=%1").arg(m_TetraTelegram->getPDU_Type()); + break; + } + } + break; + + default: + showMessageBox(QObject::tr("Unknown protocol %1!").arg(m_Protocol), QObject::tr("Unknown protocol")); + m_Validity = e_Invalid; + break; + + } +} + +LogViewTelegram::~LogViewTelegram() +{ + delete m_TetraTelegram; +} + + + + + + + + +void LogViewTelegram::setUIntX(const uint8_t a_size, quint64 a_value, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) +{ + + if (m_ActOffset + a_size > m_data.size()) + m_data.resize(m_ActOffset + a_size); + + + if (a_byteOrder == LogViewXdrStandardType::e_ByteOrderBigEndian) + { + for (int i = a_size - 1; i >= 0; i--) + { + setData(m_ActOffset+i, a_value & 0x000000FF); + a_value = a_value >> 8; + } + } + else + { + for (int i = 0; i < a_size; i++) + { + setData(m_ActOffset + i, a_value & 0x000000FF); + a_value = a_value >> 8; + } + } + m_ActOffset += a_size; +} + + + + + + + +bool LogViewTelegram::setData(const uint16_t a_offset, const uint8_t a_data) +{ + if (a_offset < m_data.size()) + { + m_data[a_offset] = a_data; + return true; + } + + return false; +} + +quint64 LogViewTelegram::getLogTimeMsec() const +{ + const quint64 logTimeSec = m_LogTime >> 32; + const quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; + return (logTimeSec * 1000 + logTimeMicroSec / 1000); +} + + + + + +QString LogViewTelegram::getLogTimeText() const +{ + if (m_logTimeText.isEmpty()) + { + const QDateTime dt(QDateTime::fromMSecsSinceEpoch(getLogTimeMsec())); + m_logTimeText = dt.toString(QLatin1String("ddd, MMM dd, yyyy hh:mm:ss.zzz")); + } + return m_logTimeText; +} + + +QString LogViewTelegram::getDestinationText() const +{ + auto protocol = static_cast + (m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); + auto dest = static_cast + (m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); + switch (protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return QLatin1String("C > P"); + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return QLatin1String("P > C"); + default: + break; + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return QLatin1String("W > C"); + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return QLatin1String("C > W"); + default: + break; + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return QLatin1String("P > T"); + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return QLatin1String("T > P"); + default: + break; + } + break; + } + default: + break; + } + return QStringLiteral("<%1>").arg(m_Destination); +} + + + + + + + +QString LogViewTelegram::getGpsTimeText() const +{ + if (m_GpsTime != 0) + return QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL).toString(QLatin1String("hh:mm:ss")); + + return QString(); +} + + + + + + + + + +int32_t LogViewTelegram::getDelay() const +{ + if (m_GpsTime != 0) + { + quint64 logTimeSec = m_LogTime >> 32; + return logTimeSec - m_GpsTime; + } + return 0; +} + + + + + + + +QString LogViewTelegram::getToolTipText(const E_Column a_col) +{ + if (a_col < e_ColMax) + { + if(a_col == e_ColName && m_ToolTipText[e_ColName].isNull()) + createToolTipTextForColName(); + if(a_col == e_ColLogTime && m_ToolTipText[e_ColLogTime].isNull()) { + quint64 logTimeSec = m_LogTime >> 32; + quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; + m_ToolTipText[e_ColLogTime] = QStringLiteral("%1.%2 s") + .arg(logTimeSec) + .arg(logTimeMicroSec); + } + if(a_col == e_ColGpsTime && m_ToolTipText[e_ColGpsTime].isNull()) { + if(m_GpsTime == 0) { + m_ToolTipText[e_ColGpsTime] = QLatin1String(""); + } else { + const QDateTime dtGpsTime(QDateTime::fromMSecsSinceEpoch(m_GpsTime * 1000LL)); + m_ToolTipText[e_ColGpsTime] = QStringLiteral("%1
Unixzeit: %2 0x%3") + .arg(dtGpsTime.toString(QLatin1String("ddd, MMM dd, yyyy hh:mm:ss"))) + .arg(m_GpsTime) + .arg(m_GpsTime, 8, 16, QLatin1Char('0')); + } + } + return m_ToolTipText[a_col]; + } + return QString(); +} + + + +void LogViewTelegram::createToolTipTextForColName() +{ + switch (m_Protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: + { + const QString jsonStr = QString::fromUtf8(QJsonDocument(m_json).toJson(QJsonDocument::JsonFormat::Indented)); + + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Telegram Id"), getTelId()) + + formatToolTipLine(QObject::tr("Counter"), getUInt32(POS_CENTRAL_COUNTER)) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + formatToolTipLine(QObject::tr("Json Data"), jsonStr, jsonStr.size()) + + QLatin1String("
"); + break; + } + + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + switch (m_TetraTelegram->getPDU_Type()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: + + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Host ISSI"), m_TetraTelegram->getSrcISSI()) + + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + QLatin1String("
"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Registration Status"), m_TetraTelegram->getRegistrationStatusAsText(), m_TetraTelegram->getRegistrationStatus()) + + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + QLatin1String("
"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: { + int frameSize = 1; + if(m_TetraTelegram->getWithCrc()) + frameSize += 2; + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Source ISSI"), m_TetraTelegram->getSrcISSI()) + + formatToolTipLine(QObject::tr("Destination ISSI"), m_TetraTelegram->getDestISSI()) + + formatToolTipLine(QObject::tr("Protocol Identifier"), m_TetraTelegram->getProtocolIdentifierAsText(), m_TetraTelegram->getProtocolIdentifier()) + + formatToolTipLine(QObject::tr("Message Reference"), m_TetraTelegram->getMessageReference()) + + formatToolTipLine(QObject::tr("Area Selection"), m_TetraTelegram->getAreaSelection()) + + formatToolTipLine(QObject::tr("Validity Period"), m_TetraTelegram->getValidityPeriod()) + + formatToolTipLine(QObject::tr("Forward Address"), m_TetraTelegram->getForwardAddress()) + + formatToolTipLine(QObject::tr("Flags"), m_TetraTelegram->getFlagsAsText(), m_TetraTelegram->getFlags()) + + formatToolTipLine(QObject::tr("Complete Payload in Bits"), m_TetraTelegram->getLengthInBits()) + + formatToolTipLine(QObject::tr("Real Payload in Bytes"), m_TetraTelegram->getLengthInBytes() - frameSize) + + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + QLatin1String("
"); + break; + } + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Source ISSI"), m_TetraTelegram->getSrcISSI()) + + formatToolTipLine(QObject::tr("Destination ISSI"), m_TetraTelegram->getDestISSI()) + + formatToolTipLine(QObject::tr("Protocol Identifier"), m_TetraTelegram->getProtocolIdentifierAsText(), m_TetraTelegram->getProtocolIdentifier()) + + formatToolTipLine(QObject::tr("Message Reference"), m_TetraTelegram->getMessageReference()) + + formatToolTipLine(QObject::tr("Area Selection"), m_TetraTelegram->getAreaSelection()) + + formatToolTipLine(QObject::tr("Delivery"), m_TetraTelegram->getDeliveryAsText(), m_TetraTelegram->getDelivery()) + + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + QLatin1String("
"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + default: + m_ToolTipText[e_ColName] = QLatin1String("") + + formatToolTipLine(QObject::tr("Counter"), m_TetraTelegram->zaehler()) + + formatToolTipLine(QObject::tr("Size"), m_data.size()) + + QLatin1String("
"); + break; + } + break; + } + + default: + break; + } +} + +union convertHackDouble +{ + quint64 i; + double d; +}; + +union convertHackFloat +{ + uint32_t i; + float f; +}; + +double LogViewTelegram::xdrToDouble(quint64 in) +{ + convertHackDouble c; + c.i = in; + return c.d; +} + +float LogViewTelegram::xdrToFloat(uint32_t in) +{ + convertHackFloat c; + c.i = in; + return c.f; +} + +quint64 LogViewTelegram::doubleToXdr(double in) +{ + convertHackDouble c; + c.d = in; + return c.i; +} + +uint32_t LogViewTelegram::floatToXdr(float in) +{ + convertHackFloat c; + c.f = in; + return c.i; +} + + + +void LogViewTelegram::resetOffset() +{ + switch (m_Protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + m_ActOffset = START_OFFSET_CENTRAL; + break; + default: + ERROR_LOG(m_logger) << "resetOffset is only for Central-Protocol implemented"; + } +} + + + +LogViewField* LogViewTelegram::getFieldTree() +{ + + switch (m_Protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: + { + resetOffset(); + const QString type = m_json.value(QStringLiteral("type")).toString(); + QStringList objPath = {QStringLiteral("data")}; + return getFieldTreeJson(m_json.value(QStringLiteral("data")), + type, jsonParser()->structFromType(type), objPath); + } + + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: + { + QString structName; + switch (m_TetraTelegram->getPDU_Type()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: + m_ActOffset = START_OFFSET_TETRA_REGISTER; + structName = QLatin1String("TETRA_register_indication_rt"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + m_ActOffset = START_OFFSET_TETRA_REGISTER; + structName = QLatin1String("TETRA_register_response_rt"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + if (m_TetraTelegram->isLoginTelegram()) + { + m_ActOffset = START_OFFSET_TETRA_LOGIN; + structName = QLatin1String("TETRA_login_telegram_rt"); + } + else if (m_TetraTelegram->isNormalTelegram()) + { + structName = getStructName(); + if (structName == QLatin1String("gef_automatic_conversion_rt")) + { + + auto centralTelegram = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(m_TetraTelegram); + if (centralTelegram) + { + + LogViewTelegram* tmpCentralTelegram = new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, + m_LogTime, + centralTelegram->data()); + LogViewField* fieldTree = tmpCentralTelegram->getFieldTree(); + delete tmpCentralTelegram; + delete centralTelegram; + return fieldTree; + } + } + else + { + + m_ActOffset = START_OFFSET_TETRA_DATA; + structName = getStructName(); + } + } + else + { + + switch (m_TetraTelegram->getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + m_ActOffset = START_OFFSET_TETRA_FRAGMENT; + structName = QLatin1String("TETRA_first_fragment_rt"); + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + m_ActOffset = START_OFFSET_TETRA_FRAGMENT; + structName = QLatin1String("TETRA_middle_fragment_rt"); + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + m_ActOffset = START_OFFSET_TETRA_FRAGMENT; + structName = QLatin1String("TETRA_last_fragment_rt"); + break; + default: + break; + } + } + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_GroupMonitorReq: + m_ActOffset = START_OFFSET_TETRA_REGISTER; + structName = QLatin1String("TETRA_group_monitoring_ind_rt"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: + m_ActOffset = START_OFFSET_TETRA_REGISTER; + structName = QLatin1String("TETRA_status_ind_req_rt"); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + m_ActOffset = START_OFFSET_TETRA_AIRLOAD; + structName = QLatin1String("TETRA_air_interface_load_req_rt"); + break; + + default: + m_ActOffset = 0; + structName = QLatin1String("TETRA_unknown_PDU_rt"); + break; + } + return getFieldTree(structName, structName, 1); + } + default: + break; + } + return nullptr; +} + +static inline QStringList objectPath(const LogViewField *parent, const QString &name, const QString &nameOverride) +{ + auto ret = parent->jsonPath(); + if (!nameOverride.isEmpty()) + ret += nameOverride; + if (!name.isEmpty()) + ret += name; + return ret; +} + +LogViewField *LogViewTelegram::getFieldTreeJson(const QJsonValue &data, + const QString &name, + const StructInformation &si, + const QStringList &objectPathBase) +{ + auto xdr = new LogViewXdrStruct(name, LogViewXdrElement::e_KindStructElement); + LogViewField *f = new LogViewField(name, LogViewField::e_FieldKindBorder, xdr); + f->setJsonPath(objectPathBase); + f->setDeleteXdr(true); + addFieldTreeStruct(data.toObject(), f, si, QString(), m_logger); + return f; +} + +void LogViewTelegram::addFieldTreeStruct(const QJsonObject &parentObject, + LogViewField *parent, + const StructInformation &si, + const QString &objectNameArrayHint, + NGL::INGLLogger &logger) +{ + DEBUG_LOG(logger) << "getFieldTreeJson for struct " << si.type << " with #members: " << si.member.size(); + auto parser = jsonParser(); + + for (const MemberInformation &mi : si.member) + { + if (!mi.isVisible) + continue; + const QJsonValue val = parentObject.value(mi.name); + if (mi.isString || mi.isBinary) + { + addFieldTreeJsonString(val, parent, mi.name, mi.isBinary, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); + continue; + } + if (mi.isPod) + { + addFieldTreeJsonPod(val, parent, mi.name, mi.type, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); + continue; + } + if (mi.isEnum) + { + addFieldTreeJsonEnum(val, parent, mi.name, mi.type, objectNameArrayHint, LogViewField::e_FieldKindEdit, logger); + continue; + } + if (mi.isStruct) + { + const StructInformation si = parser->structFromType(mi.type); + auto xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindStructElement); + LogViewField *f = new LogViewField(mi.name, LogViewField::e_FieldKindBorder, xdr); + f->setJsonPath(objectPath(parent, mi.name, objectNameArrayHint)); + f->setDeleteXdr(true); + addFieldTreeStruct(val.toObject(), f, si, objectNameArrayHint, logger); + parent->addChild(f); + continue; + } + if (mi.isArray) + { + const QString innerType = LogViewTetraTelegramsParser::getInnerType(mi.type); + const bool isPod = parser->isPod(innerType); + const bool isEnum = isPod ? false : parser->isEnum(innerType); + const bool isStruct = (isPod || isEnum) ? false : (parser->isStruct(mi.type) || parser->isStruct(innerType)); + + LogViewXdrElement *xdr; + if (isStruct) + { + xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindStruct); + } + else if (isEnum) + { + xdr = new LogViewXdrStruct(mi.name, LogViewXdrElement::e_KindEnum, 16); + } + else + { + const PodInformation pod = jsonParser()->podFromType(innerType); + + auto stdType = LogViewXdrStandardType::e_Float; + if (pod.isBoolean) + stdType = LogViewXdrStandardType::e_Boolean; + else if (pod.isIntegral) + stdType = pod.isSigned ? LogViewXdrStandardType::e_Signed : LogViewXdrStandardType::e_Unsigned; + + xdr = new LogViewXdrStandardType(mi.name, + pod.byteLen, + pod.byteLen, + stdType, + LogViewXdrStandardType::e_DynArrayMsgLength, + LogViewXdrStandardType::e_ByteOrderLittleEndian); + } + + LogViewField *f = new LogViewField(mi.name, isStruct ? LogViewField::e_FieldKindTab : LogViewField::e_FieldKindPodArray, xdr); + const QString fieldName = isStruct ? QStringLiteral("array: ") + mi.name : mi.name; + f->setJsonPath(objectPath(parent, fieldName, objectNameArrayHint)); + f->setDeleteXdr(true); + f->setMaxArraySize(200, true); + f->setType(LogViewTetraTelegramsParser::getInnerType(mi.type)); + + const QJsonArray arr = val.toArray(); + const QString path(QStringLiteral("index: %1")); + if (isStruct) + { + auto si = parser->structFromType(mi.type); + if (si.type.isEmpty()) + si = parser->structFromType(innerType); + for (int i = 0; i < arr.size(); ++i) + { + LogViewField *tc = new LogViewField(mi.name + QStringLiteral("TabChild"), LogViewField::e_FieldKindTabChild, xdr); + tc->setJsonPath(f->jsonPath()); + f->addChild(tc); + addFieldTreeStruct(arr.at(i).toObject(), tc, si, path.arg(i), logger); + } + } + else if (isPod) + { + for (const auto &ele : arr) + f->addValue(QString::number(ele.toInt())); + } + else if (isEnum) + { + for (const auto &ele : arr) + addFieldTreeJsonEnum(ele, f, QString(), innerType, objectNameArrayHint, LogViewField::e_FieldKindPodArrayChild, logger); + } + else + { + + for (int i = 0; i < arr.size(); ++i) + addFieldTreeJsonString(arr.at(i), f, QString(), false, path.arg(i), LogViewField::e_FieldKindPodArrayChild, logger); + } + parent->addChild(f); + } + } +} + + +void LogViewTelegram::addFieldTreeJsonString(const QJsonValue &val, + LogViewField *parent, + const QString &name, + bool isBinary, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger) +{ + DEBUG_LOG(logger) << "addFieldTreeJsonString for " << name << " and value: " << val.toString(); + auto xdr = new LogViewXdrStandardType(name, + 1, + 1, + isBinary ? LogViewXdrStandardType::e_Data : LogViewXdrStandardType::e_Character, + LogViewXdrStandardType::e_DynArrayMsgLength, + LogViewXdrStandardType::e_ByteOrderLittleEndian); + LogViewField *f = new LogViewField(name, fieldKind, xdr); + f->setMaxArraySize(std::numeric_limits::max(), true); + if (isBinary) + f->addValueBinaryHex(val.toString()); + else + f->addValue(val.toString()); + f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); + f->setDeleteXdr(true); + parent->addChild(f); +} + + +void LogViewTelegram::addFieldTreeJsonPod(const QJsonValue &val, + LogViewField *parent, + const QString &name, + const QString &type, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger) +{ + DEBUG_LOG(logger) << "addFieldTreeJsonPod for " << name << " and value: " << val.toDouble() << ", type: " << type; + const PodInformation pod = jsonParser()->podFromType(type); + + auto stdType = LogViewXdrStandardType::e_Float; + if (pod.isBoolean) + stdType = LogViewXdrStandardType::e_Boolean; + else if (pod.isIntegral) + stdType = pod.isSigned ? LogViewXdrStandardType::e_Signed : LogViewXdrStandardType::e_Unsigned; + + auto xdr = new LogViewXdrStandardType(name, + pod.byteLen, + pod.byteLen, + stdType, + LogViewXdrStandardType::e_DynArrayMsgLength, + LogViewXdrStandardType::e_ByteOrderLittleEndian); + LogViewField *f = new LogViewField(name, fieldKind, xdr); + if (pod.isBoolean) + f->addValue(QString::number(val.toBool())); + else if (pod.isIntegral) + f->addValue(QString::number(qRound64(val.toDouble()))); + else + f->addValue(QStringLiteral("%1").arg(val.toDouble(), 0, 'f', 10)); + f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); + f->setDeleteXdr(true); + parent->addChild(f); +} + + +void LogViewTelegram::addFieldTreeJsonEnum(const QJsonValue &val, + LogViewField *parent, + const QString &name, + const QString &type, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger) +{ + DEBUG_LOG(logger) << "addFieldTreeJsonEnum for " << name << " and value: " << val.toDouble(); + const EnumInformation ei = jsonParser()->enumFromType(type); + if (ei.type.isEmpty()) + { + WARNING_LOG(logger) << "Can not find enum information for " << type; + return; + } + + const int enumVal = val.toInt(); + auto xdr = new LogViewXdrStruct(name, LogViewXdrElement::e_KindEnum, 16); + LogViewField *f = new LogViewField(name, fieldKind, xdr); + + bool bAddedDefault = false; + for (const EnumValue &ev : ei.values) + { + xdr->addElement(ev.key, ev.value, LogViewXdrElement::e_KindEnumElement); + if (ev.value == enumVal) + { + bAddedDefault = true; + f->addValue(ev.key); + } + } + if (!bAddedDefault) + f->addValue(QStringLiteral("Unknown (%1)").arg(enumVal)); + + f->setMaxArraySize(0, false); + f->setJsonPath(objectPath(parent, name, objectNameArrayHint)); + f->setDeleteXdr(true); + parent->addChild(f); +} + + + +QString LogViewTelegram::typeFromStructInformation(const StructInformation &si, const QString &name) +{ + return memberFromStructInformation(si, name).type; +} + + +MemberInformation LogViewTelegram::memberFromStructInformation(const StructInformation &si, const QString &name) +{ + for(const MemberInformation &mi : si.member) + { + if (mi.name == name) + return mi; + } + return {}; +} + + +LogViewField* LogViewTelegram::getFieldTree(const QString& a_type, const QString& a_name, uint16_t a_arraySize, const LogViewXdrType* a_parentElement, const bool a_hasContent) +{ + DEBUG_LOG(m_logger) << "a_type=" << a_type << " a_name=" << a_name << " a_arraySize=" << a_arraySize; + const LogViewXdrElement* xdrElement = tetraParser()->getElement(a_type); + if (!xdrElement) + return nullptr; + + + + uint16_t maxArraySize = 0; + LogViewField* fieldTree = nullptr; + switch (xdrElement->getKind()) + { + case LogViewXdrElement::e_KindStruct: + { + + if (a_arraySize == 1) + { + + fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindBorder, xdrElement); + } + else + { + + fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindTab, xdrElement); + if (0 != a_arraySize) + { + + fieldTree->setMaxArraySize(0, false); + } + } + + + uint32_t i = 0; + while (LogViewXdrType* child = static_cast(xdrElement)->getChildAsType(i++)) + { + bool isDynArray = false; + int arraySize = child->getArraySize(); + if (0 == arraySize && !isScalar(child)) + { + INFO_LOG(m_logger) << "dyn. array of struc"; + arraySize = getDynArraySize(m_ActOffset); + isDynArray = true; + } + else + { + + if (isScalar(child)) + { + arraySize = 1; + } + m_MaxArraySize = child->getMaxArraySize(); + } + + + + if (0 == arraySize) + { + LogViewField* field = getFieldTree(child->getType(), child->getName(), child->getArraySize(), child); + field->setHasContent(false); + if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true); + fieldTree->addChild(field); + } + + for (int k=0; kgetType(), child->getName(), child->getArraySize(), child); + if (isDynArray) field->setMaxArraySize(child->getMaxArraySize(), true); + fieldTree->addChild(field); + } + } + break; + } + + case LogViewXdrElement::e_KindTypedef: + + if (a_arraySize != 0) + { + + a_arraySize = static_cast(xdrElement)->getArraySize(); + } + else + { + + INFO_LOG(m_logger) << "typedef dynamisch"; + } + maxArraySize = static_cast(xdrElement)->getMaxArraySize(); + while (xdrElement->getKind() != LogViewXdrElement::e_KindStandardType) + { + xdrElement = tetraParser()->getElement(static_cast(xdrElement)->getType()); + + + if (LogViewXdrElement::e_KindEnum == xdrElement->getKind()) + { + return getFieldTree(xdrElement->getName(), a_name, a_arraySize); + } + } + Q_FALLTHROUGH(); + case LogViewXdrElement::e_KindStandardType: + { + + if (a_hasContent) + { + fieldTree = getContent(static_cast(xdrElement), m_ActOffset, a_arraySize); + fieldTree->setName(a_name); + } + else + { + fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement); + fieldTree->setHasContent(false); + + } + + if (0 == a_arraySize) + { + + fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true); + } + else + { + + fieldTree->setMaxArraySize(a_arraySize, false); + } + break; + } + + case LogViewXdrElement::e_KindEnum: + { + + uint16_t size = static_cast(xdrElement)->getEnumSize(); + uint16_t arraySize = a_arraySize; + if (0 == arraySize) + { + arraySize = getDynArraySize(m_ActOffset); + } + + QString tooltipText; + bool isLast = true; + if (1 == arraySize) + { + uint32_t enumValue = getUIntX(m_ActOffset, size); + tooltipText = QStringLiteral("%1 0x%2 0b%3").arg(enumValue) + .arg(enumValue, 2, 16, QLatin1Char('0')) + .arg(enumValue, 8, 2, QLatin1Char('0')); + + if (a_parentElement) + { + isLast = a_parentElement->maskValue(enumValue, size, tooltipText); + } + } + + + fieldTree = new LogViewField(a_name, LogViewField::e_FieldKindEdit, xdrElement); + fieldTree->setToolTipText(tooltipText); + + + for (int i=0; imaskValue(enumValue, size, tmp); + + QString enumText = QStringLiteral("<%1>").arg(enumValue); + int j=0; + while (LogViewXdrValue* child = (static_cast(xdrElement))->getChildAsValue(j++)) + { + + if (child->getValue() == enumValue) + { + enumText = LogViewField::makeClean(child->getName()); + break; + } + } + + fieldTree->addValue(enumText); + if (isLast) m_ActOffset += size; + } + + + + if (0 == a_arraySize) + { + + fieldTree->setMaxArraySize(0 == maxArraySize ? m_MaxArraySize : maxArraySize, true); + } + else + { + + fieldTree->setMaxArraySize(a_arraySize, false); + } + break; + } + default: + break; + } + return fieldTree; +} + + + +void LogViewTelegram::dump() const +{ + + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, m_data.data(), m_data.size()); +} + + + +QString LogViewTelegram::getStructName() const +{ + return isJsonTelegram() ? jsonParser()->nameFromTelegramId(getTelId()) + : tetraParser()->getStructName(getTelId());; +} + + + +uint16_t LogViewTelegram::getUInt16(const uint16_t a_offset) const +{ + return (uint16_t)getUIntX(a_offset, 2); +} + + + +uint32_t LogViewTelegram::getUInt32(const uint16_t a_offset) const +{ + return getUIntX(a_offset, 4); +} + + + +int32_t LogViewTelegram::getInt32(const uint16_t a_offset) const +{ + return getUInt32(a_offset); +} + + + +quint64 LogViewTelegram::getUIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) const +{ + quint64 factor = 1; + quint64 value = getData(a_offset); + for (int i=1; i(m_TetraTelegram->getData()[0]); + if (magicNumber != 0xA5) + { + showMessageBox(QObject::tr("TETRA-Magic-Number is 0x%1 but must be 0xA5").arg(magicNumber, 2, 16, QLatin1Char('0'))); + m_Validity = e_Invalid; + return false; + } + + int length = m_TetraTelegram->getSize(); + if (length != m_data.size()) + { + showMessageBox(QObject::tr("Telegram length is %1 but must be %2").arg(length+4).arg(m_data.size())); + m_Validity = e_Invalid; + return false; + } + m_Validity = e_Valid; + return true; + } + + default: + m_Validity = e_Invalid; + return false; + } + case e_Valid: + return true; + + case e_Invalid: + return false; + + } +} + + + +LogViewField* LogViewTelegram::getContent(const LogViewXdrStandardType* a_standardType, uint16_t& a_offset, const uint16_t a_arraySize) +{ + + + + LogViewField* field = new LogViewField(QString(), LogViewField::e_FieldKindEdit, a_standardType); + field->setIsRightAligned(false); + + + const int size = a_standardType->getValueSize(); + field->setSize(size); + uint16_t arraySize = a_arraySize; + if (0 == arraySize) + arraySize = getDynArraySize(a_offset); + + + switch (a_standardType->getValueKind()) + { + case LogViewXdrStandardType::e_Unsigned: + + { + const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); + uint32_t value = 0; + for (int i = 0; i < arraySize; i++) + { + value = getUIntX(i*size+a_offset, size, byteOrder); + field->addValue(QString::number(value)); + } + + if (arraySize <= 1) + { + if (a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndex + || a_standardType->getDynArraySizeMethod() == LogViewXdrStandardType::e_DynArrayIndexDiv8) + { + m_DynArraySizeMethod = a_standardType->getDynArraySizeMethod(); + m_LastUnsignedValue = value; + } + } + field->setIsRightAligned(true); + } + break; + + case LogViewXdrStandardType::e_Signed: + + { + const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); + for (int i = 0; i < arraySize; i++) + { + int32_t value = getSIntX(i*size+a_offset, size, byteOrder); + field->addValue(QString::number(value)); + } + field->setIsRightAligned(true); + } + break; + + case LogViewXdrStandardType::e_Float: + + { + const LogViewXdrStandardType::E_ByteOrder byteOrder = a_standardType->getByteOrder(); + for (int i = 0; i < arraySize; i++) + { + const quint64 value = getUIntX(i*size+a_offset, size, byteOrder); + if (8 == size) { + field->addValue(QString::number(xdrToDouble(value))); + INFO_LOG(m_logger) << "value=" << xdrToDouble(value); + } else { + field->addValue(QString::number(xdrToFloat(value))); + INFO_LOG(m_logger) << "value=" << xdrToFloat(value); + } + } + field->setIsRightAligned(true); + } + break; + + case LogViewXdrStandardType::e_Character: + + { + QByteArray text; + for (int i = 0; i < arraySize; i++) + { + char theChar = getChar(a_offset+(i*size), size); + if (0 == theChar) + break; + text += theChar; + } + field->addValue(QString::fromUtf8(text)); + } + break; + + case LogViewXdrStandardType::e_Data: + + for (int i = 0; i < arraySize; i++) + field->addValue(QString::number(getData(a_offset+i))); + break; + + default: + ERROR_LOG(m_logger) << "ValueKind " << a_standardType->getValueKind() << " not implemented!"; + break; + } + uint16_t sizeOfContent = arraySize * size; + a_offset += sizeOfContent; + + if (0 == a_arraySize) + { + uint16_t rest = sizeOfContent % 4; + if (0 != rest) + { + a_offset += (4 - rest); + + } + } + + return field; +} + + + +N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol LogViewTelegram::getDirection() const +{ + return static_cast(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); +} + + +void LogViewTelegram::setJsonValue(const QStringList &path, const QJsonValue &val) +{ + m_data.clear(); + updateJsonValue(path, val, m_json); + if (path.size() && path.last() == QLatin1String("equipmentNumber")) + m_ParticipantId = m_json.value(QLatin1String("data")) + .toObject().value(QLatin1String("header")) + .toObject().value(QLatin1String("equipmentNumber")).toInt(); +} + + +void LogViewTelegram::updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonObject &obj) +{ + if (path.isEmpty()) + return; + if (path.size() > 1) + { + QString key = path.first(); + static const QLatin1String arrayMarker(QLatin1String("array: ")); + const bool isArray = key.startsWith(arrayMarker); + if (isArray) + { + key = key.mid(arrayMarker.size()); + const QJsonValue val = obj.value(key); + QJsonArray arr = val.toArray(); + const QStringList subPath = path.mid(1); + updateJsonValue(subPath, newVal, arr); + obj[key] = arr; + } + else + { + const QJsonValue val = obj.value(key); + QJsonObject child = val.toObject(); + const QStringList subPath = path.mid(1); + updateJsonValue(subPath, newVal, child); + obj[key] = child; + } + } + else + { + obj[path.first()] = newVal; + } +} + + +void LogViewTelegram::updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonArray &arr) +{ + if (path.isEmpty()) + return; + + const QString &key = path.first(); + static const QLatin1String indexMarker(QLatin1String("index: ")); + if (!key.startsWith(indexMarker)) + return; + + const int arrayIdx = key.midRef(indexMarker.size()).toInt(); + while (arr.size() <= arrayIdx) + arr.append(QJsonValue()); + + QJsonValue childVal = arr.at(arrayIdx); + if (childVal.isObject() || path.size() > 1) + { + QJsonObject child = childVal.toObject(); + const QStringList subPath = path.mid(1); + updateJsonValue(subPath, newVal, child); + arr[arrayIdx] = child; + } + else + { + arr[arrayIdx] = newVal; + } +} + + +QIcon LogViewTelegram::getIcon() const +{ + static const QIcon c2p(QLatin1String(":/image/C2P.png")); + static const QIcon p2c(QLatin1String(":/image/P2C.png")); + static const QIcon w2p(QLatin1String(":/image/W2P.png")); + static const QIcon p2w(QLatin1String(":/image/P2W.png")); + static const QIcon t2p(QLatin1String(":/image/T2P.png")); + static const QIcon p2t(QLatin1String(":/image/P2T.png")); + static const QIcon unk(QLatin1String(":/image/Unknown.png")); + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol protocol, dest; + protocol =(N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol)(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolMask); + dest = (N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol)(m_Destination & N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask); + switch (protocol) + { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return c2p; + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return p2c; + default: + break; + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return w2p; + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return p2w; + default: + break; + } + break; + } + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra: { + switch (dest) { + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive: + return p2t; + case N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend: + return t2p; + default: + break; + } + break; + } + default: + break; + } + return unk; +} + + +bool LogViewTelegram::isScalar(const LogViewXdrType* a_xdrType) const +{ + const LogViewXdrElement* xdrElement = tetraParser()->getElement(a_xdrType->getType()); + if (xdrElement) + { + switch (xdrElement->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + case LogViewXdrElement::e_KindEnum: + return true; + case LogViewXdrElement::e_KindStruct: + return false; + case LogViewXdrElement::e_KindTypedef: + return isScalar(static_cast(xdrElement)); + + + default: + ERROR_LOG(m_logger) << "name=" << xdrElement->getName().toStdString() << " kind=" << xdrElement->getKind() << " case not implemented!"; + return false; + } + } + return false; +} + + + +void LogViewTelegram::showMessageBox(const QString& a_errorText, const QString& a_title) const +{ + quint64 logTimeSec = m_LogTime >> 32; + quint64 logTimeMicroSec = m_LogTime & 0x00FFFFFFFFULL; + const QDateTime dt(QDateTime::fromMSecsSinceEpoch(logTimeSec * 1000 + logTimeMicroSec/1000)); + const QString destStr((m_Destination&N_CoPrtCnv::CoPrtCnvLogHeader::e_DestDirectionMask)==N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend ? + QLatin1String("gesendete") : QLatin1String("gelesene")); + QMessageBox::warning(QApplication::topLevelWidgets()[0], a_title, + QString::fromUtf8("Das %5 Telegramm mit Protokoll %6 von %1 (Unix-Zeit: %2) und Länge %3 ist fehlerhaft:

%4") + .arg(dt.toString(Qt::SystemLocaleLongDate)).arg(logTimeSec).arg(m_data.size()).arg(a_errorText, destStr).arg(m_Protocol)); +} + + + +uint16_t LogViewTelegram::getDynArraySize(uint16_t& a_offset) const +{ + uint16_t arraySize; + if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra == m_Protocol) + { + switch (m_DynArraySizeMethod) { + case LogViewXdrStandardType::e_DynArrayMsgLength: + arraySize = m_data.size() - m_MaxArraySize; + break; + + case LogViewXdrStandardType::e_DynArrayIndexDiv8: + arraySize = (m_LastUnsignedValue+7)/8; + break; + + default: + arraySize = m_LastUnsignedValue; + break; + } + } + else + { + + arraySize = getUIntX(a_offset, SIZE_CENTRAL_DYN_ARRAY_SIZE); + a_offset += SIZE_CENTRAL_DYN_ARRAY_SIZE; + } + return arraySize; +} + + + +QString LogViewTelegram::formatToolTipLine(const QString& a_name, const QString& a_text, const uint32_t a_value) +{ + static const QString s1(QLatin1String("%1: %20x%30b%4")); + static const QString s2(QLatin1String("%1")); + QString num16 = s2.arg(a_value, 2, 16, QLatin1Char('0')); + QString num2 = s2.arg(a_value, 8, 2, QLatin1Char('0')); + QString ret = s1.arg(a_name, a_text, num16, num2); + ret = ret.replace(QLatin1Char('\n'), QLatin1String("
")); + return ret; +} + + + +const N_CoPrtCnv::CoPrtCnvRadioTelegram* LogViewTelegram::getTetraTelegram() const +{ + return m_TetraTelegram; +} + + + +LogViewTetraTelegramsParser *LogViewTelegram::jsonParser() +{ + static LogViewTetraTelegramsParser s_parser; + return &s_parser; +} + + +LogViewXdrParser *LogViewTelegram::tetraParser() +{ + static LogViewXdrParser s_parser; + return &s_parser; +} + + + + + +uint8_t LogViewTelegram::getData(const uint16_t a_offset) const +{ + if (a_offset < m_data.size()) + return m_data.at(a_offset); + + return 0; +} + + +QByteArray LogViewTelegram::getData(QJsonDocument::JsonFormat format) const +{ + if (m_data.isEmpty() && !m_json.isEmpty()) + return QJsonDocument(m_json).toJson(format); + + return m_data; +} + + + +void LogViewTelegram::setNextFieldAsGpsTimeField() +{ + m_GpsFieldOffset.append(m_ActOffset); +} + + +void LogViewTelegram::actualizeGpsTime() +{ + if (m_GpsFieldOffset.size() > 0) + { + if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Protocol) + { + uint16_t savedOffset = m_ActOffset; + for (QVector::const_iterator i = m_GpsFieldOffset.cbegin(); i < m_GpsFieldOffset.cend(); ++i) + { + m_ActOffset = *i; + setUIntX(4, ::time(nullptr)); + } + m_ActOffset = savedOffset; + } + } + + if (!m_json.isEmpty()) + { + static const QString dataKey = QStringLiteral("data"); + if (dataKey.contains(dataKey)) + { + auto data = m_json.value(dataKey).toObject(); + static const QString hdrKey = QStringLiteral("header"); + if (data.contains(hdrKey)) + { + auto hdr = data.value(hdrKey).toObject(); + hdr[QStringLiteral("timeStamp")] = QDateTime::currentMSecsSinceEpoch(); + data[hdrKey] = hdr; + } + m_json[dataKey] = data; + } + m_data.clear(); + } +} + +} diff --git a/TetraIF/LogView/LogViewTelegram.hpp b/TetraIF/LogView/LogViewTelegram.hpp new file mode 100644 index 000000000..f7b7442f8 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegram.hpp @@ -0,0 +1,372 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrStandardType.hpp" +#include "LogViewField.hpp" +#include +#include +#include +#include + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace N_LogView +{ + struct StructInformation; + struct MemberInformation; + class LogViewTetraTelegramsParser; + class LogViewXdrParser; + class LogViewXdrType; + + + class LogViewTelegram final + { + public: + + + + enum E_Validity + { + e_NotYetEvaluated, + e_Valid, + e_Invalid + }; + + + + enum E_Column + { + e_ColName, + e_ColGpsTime, + e_ColLogTime, + e_ColJsonData, + e_ColMax + }; + + + ~LogViewTelegram(); + + + + static const uint16_t SIZE_CENTRAL_DYN_ARRAY_SIZE; + + + + + LogViewTelegram(const LogViewTelegram &o); + + LogViewTelegram &operator=(const LogViewTelegram &o) = delete; + + + LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, + int telegramId); + + + + LogViewTelegram(const N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol a_destination, + const quint64 a_unixTime, + const QByteArray &a_telegramData); + + + + void setUIntX(const uint8_t a_size, + quint64 a_value, + const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian); + + + + bool setData(const uint16_t a_offset, const uint8_t a_data); + + + + quint64 getLogTime() const { return m_LogTime; } + quint64 getLogTimeMsec() const; + + + + QString getLogTimeText() const; + + + QString getDestinationText() const; + + + + quint64 getGpsTime() const { return m_GpsTime; } + + + + QString getGpsTimeText() const; + + + uint32_t getISSI() const { return m_ISSI; } + + + int getParticipantId() const { return m_ParticipantId; } + + + + int32_t getDelay() const; + + + + QString getToolTipText(const E_Column a_col); + + + void resetOffset(); + + + LogViewField* getFieldTree(); + + + void dump() const; + + + QString getStructName() const; + + + bool isValid(); + + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getDestination() const { return m_Destination; } + + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getDirection() const; + + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol getProtocol() const { return m_Protocol; } + + + int getTelId() const { return m_TelId; } + + + QIcon getIcon() const; + + bool isJsonTelegram() const { return N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Protocol; } + void clearJsonData() { m_json.remove(QStringLiteral("data")); } + void rebuildJsonString() { if (!m_json.isEmpty()) m_data.clear(); } + void setJsonValue(const QStringList &path, const QJsonValue &val); + QJsonObject jsonData() const { return m_json; } + void updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonObject &obj); + void updateJsonValue(const QStringList &path, const QJsonValue &newVal, QJsonArray &arr); + + + const N_CoPrtCnv::CoPrtCnvRadioTelegram* getTetraTelegram() const; + + static LogViewTetraTelegramsParser *jsonParser(); + static LogViewXdrParser *tetraParser(); + + QByteArray getData(QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Compact) const; + + + + uint32_t getWaitTime() const { return m_WaitTime; } + + + + void setWaitTime(uint32_t newVal) { m_WaitTime = newVal; } + + + + QString getName() const { return m_Name; } + + + + void setName(const QString &newVal) { m_Name = newVal; } + + + void setNextFieldAsGpsTimeField(); + + QVector getGpsTimeField() const { return m_GpsFieldOffset; } + + void setGpsTimeField(const QVector &gpsFieldOffset) { m_GpsFieldOffset = gpsFieldOffset; } + + void actualizeGpsTime(); + + + + void createToolTipTextForColName(); + + + static double xdrToDouble(quint64 in); + static float xdrToFloat(uint32_t in); + static quint64 doubleToXdr(double in); + static uint32_t floatToXdr(float in); + + protected: + + + + QString m_Name; + + + std::vector m_ToolTipText; + + + uint32_t m_WaitTime; + int m_ParticipantId; + + + uint32_t m_ISSI; + + + int m_AllocatedSize; + static const LogViewXdrParser* m_Parser; + uint16_t m_ActOffset; + QVector m_GpsFieldOffset; + int m_TelId; + + + uint32_t m_LastUnsignedValue; + + + uint16_t m_MaxArraySize; + static const uint16_t START_OFFSET_CENTRAL; + static const uint16_t POS_CENTRAL_COUNTER; + static const uint16_t POS_CENTRAL_TELID; + static const uint16_t POS_CENTRAL_PARTICIPANTID; + static const uint16_t START_OFFSET_TETRA_REGISTER; + static const uint16_t START_OFFSET_TETRA_AIRLOAD; + static const uint16_t START_OFFSET_TETRA_DATA; + static const uint16_t START_OFFSET_TETRA_LOGIN; + static const uint16_t START_OFFSET_TETRA_FRAGMENT; + LogViewXdrStandardType::E_DynArraySizeMethod m_DynArraySizeMethod; + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol m_Destination; + + E_Validity m_Validity; + + N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol m_Protocol; + + quint64 m_LogTime; + + mutable QString m_logTimeText; + + quint64 m_GpsTime; + + QByteArray m_data; + QJsonObject m_json; + + N_CoPrtCnv::CoPrtCnvRadioTelegram *m_TetraTelegram; + + LogViewField *getFieldTree(const QString& a_type, const QString& a_name, + uint16_t a_arraySize, const LogViewXdrType* a_parentElement = nullptr, + const bool a_hasContent = true); + LogViewField *getFieldTreeJson(const QJsonValue &data, + const QString &name, + const StructInformation &si, + const QStringList &objectPathBase); + + static void addFieldTreeStruct(const QJsonObject &parentObject, + LogViewField *parent, + const StructInformation &si, + const QString &objectNameArrayHint, + NGL::INGLLogger &logger); + static void addFieldTreeJsonString(const QJsonValue &val, + LogViewField *parent, + const QString &name, + bool isBinary, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger); + static void addFieldTreeJsonPod(const QJsonValue &val, + LogViewField *parent, + const QString &name, + const QString &type, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger); + static void addFieldTreeJsonEnum(const QJsonValue &val, + LogViewField *parent, + const QString &name, + const QString &type, + const QString &objectNameArrayHint, + LogViewField::E_FieldKind fieldKind, + NGL::INGLLogger &logger); + + static QString typeFromStructInformation(const StructInformation &si, const QString &name); + static MemberInformation memberFromStructInformation(const StructInformation &si, const QString &name); + + + + uint16_t getUInt16(const uint16_t a_offset) const; + + + + uint32_t getUInt32(const uint16_t a_offset) const; + + + + int32_t getInt32(const uint16_t a_offset) const; + + + + quint64 getUIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian) const; + + + + int32_t getSIntX(const uint16_t a_offset, const uint8_t a_size, const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian) const; + + + + char getChar(const uint16_t a_offset, const uint8_t a_size) const; + + + + LogViewField* getContent(const LogViewXdrStandardType* a_standardType, uint16_t& a_offset, const uint16_t a_arraySize); + + + + bool isScalar(const LogViewXdrType* a_xdrType) const; + + + + void showMessageBox(const QString& a_errorText, const QString& a_title = QObject::tr("Invalid telegram")) const; + + + + uint16_t getDynArraySize(uint16_t& a_offset) const; + + + + static QString formatToolTipLine(const QString& a_name, const uint32_t a_value) + { + return formatToolTipLine(a_name, QString::number(a_value), a_value); + } + + + + static QString formatToolTipLine(const QString& a_name, const QString& a_text, const uint32_t a_value); + + static QString formatToolTipLine(const QString& a_name, const std::string& a_text, const uint32_t a_value) + { + return formatToolTipLine(a_name, QString::fromStdString(a_text), a_value); + } + + + + uint8_t getData(const uint16_t a_offset) const; + + private: + + + NGL::INGLLogger &m_logger; + + friend class LogViewTabWidget; + + }; +} diff --git a/TetraIF/LogView/LogViewTelegramDialog.cpp b/TetraIF/LogView/LogViewTelegramDialog.cpp new file mode 100644 index 000000000..310add7c5 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramDialog.cpp @@ -0,0 +1,497 @@ + + + + + + + + + + + + + +#include "LogViewTelegramDialog.hpp" +#include "LogViewTelegram.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "LogViewXdrElement.hpp" +#include "LogViewField.hpp" +#include "IntegerCalculator.hpp" +#include "LogViewBooleanEdit.hpp" +#include "LogViewTextEdit.hpp" +#include "LogViewValueEdit.hpp" +#include "LogViewEnumEdit.hpp" +#include "LogViewDateTimeEdit.hpp" +#include "LogViewSpinBox.hpp" +#include "LogViewTableWidget.hpp" +#include "LogViewTabWidget.hpp" + +namespace N_LogView +{ + + + + + + +LogViewTelegramDialog::LogViewTelegramDialog(QWidget *a_parent, const bool a_readonly) + : QDialog(a_parent) + , m_ReadOnly(a_readonly) + , m_logger(getLogger("LogViewTelegramDialog")) +{ + setAttribute(Qt::WA_DeleteOnClose); +} + + +void LogViewTelegramDialog::showDialog(const QSharedPointer &a_telegram) +{ + delete layout(); + hide(); + + m_Telegram = a_telegram; + a_telegram->dump(); + + m_fieldTree.reset(a_telegram->getFieldTree()); + + if (m_fieldTree) + { + QGridLayout *dialogLayout = new QGridLayout; + if (!m_ReadOnly) + { + + QLabel *waitTimeLabel = new QLabel(tr("Wartezeit [ms]"), this); + dialogLayout->addWidget(waitTimeLabel, dialogLayout->rowCount(), 0); + m_WaitTimeEdit = new QLineEdit(QString::number(a_telegram->getWaitTime()), this); + dialogLayout->addWidget(m_WaitTimeEdit, dialogLayout->rowCount() - 1, 1); + + + QLabel *nameLabel = new QLabel(tr("Name"), this); + dialogLayout->addWidget(nameLabel, dialogLayout->rowCount(), 0); + m_NameEdit = new QLineEdit(a_telegram->getName(), this); + dialogLayout->addWidget(m_NameEdit, dialogLayout->rowCount() - 1, 1); + + QFrame *f = new QFrame(this); + f->setFrameShape(QFrame::HLine); + f->setFrameShadow(QFrame::Sunken); + dialogLayout->addWidget(f, dialogLayout->rowCount(), 0, 1, 2); + } + + + + showTree(m_fieldTree.data(), dialogLayout); + if (this->findChild() == nullptr) + dialogLayout->setRowStretch(dialogLayout->rowCount(), 1); + + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + + m_contentsWidget = new QWidget; + m_contentsWidget->setLayout(dialogLayout); + + m_ScrollArea = new QScrollArea(this); + m_ScrollArea->setWidget(m_contentsWidget); + m_ScrollArea->setWidgetResizable(true); + + mainLayout->addWidget(m_ScrollArea); + + + QHBoxLayout *btnLayout = new QHBoxLayout; + btnLayout->addStretch(); + showButtons(btnLayout); + + mainLayout->addLayout(btnLayout); + + setWindowTitle(m_fieldTree->cleanName() + QStringLiteral(" (%1)").arg(a_telegram->getTelId())); + + setModal(true); + show(); + + makePretty(); + } + else + showDataDump(a_telegram, true); +} + + + +void LogViewTelegramDialog::showDataDump(const QSharedPointer &a_telegram, bool showErrorMessage) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(new QLabel(tr("Telegramm-Dump"))); + + if (showErrorMessage) + + layout->addWidget(new QLabel(tr("Konnte Dialog basierend auf Struktur \'%1\' nicht generieren!").arg(a_telegram->getStructName()))); + else + layout->addWidget(new QLabel(tr("HexData from \'%1\' - telegram:").arg(a_telegram->getName()))); + + + QString theDump = QLatin1String(""); + const QByteArray &data = a_telegram->getData(); + for (int i = 0; i < data.size(); i++) + { + if (0 == (i % 8)) + theDump += QStringLiteral("%1:").arg(i, 4, 16, QLatin1Char('0')); + + theDump += QStringLiteral(" %1").arg(static_cast(data[i]), 2, 16, QLatin1Char('0')); + if (7 == (i % 8)) + theDump += QLatin1String("
"); + } + theDump += QLatin1String("
"); + + QTextEdit *telegramDump = new QTextEdit(theDump); + layout->addWidget(telegramDump); + QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen")); + QHBoxLayout *btnLayout = new QHBoxLayout; + btnLayout->addStretch(); + btnLayout->addWidget(btnClose); + layout->addLayout(btnLayout); + connect(btnClose, &QPushButton::clicked, + this, &LogViewTelegramDialog::reject); + setLayout(layout); + show(); +} + + + +void LogViewTelegramDialog::makePretty() +{ + return; + + int sbWidth = m_ScrollArea->width() - m_ScrollArea->viewport()->width(); + int wDiff = m_contentsWidget->width() - m_ScrollArea->width(); + int hDiff = m_contentsWidget->height() - m_ScrollArea->viewport()->height(); + const QRect screenSize = QApplication::desktop()->screenGeometry(this); + + int newWidth = std::min(width() + wDiff + sbWidth, screenSize.width() * 9 / 10); + int newHeight = std::min(height() + hDiff, screenSize.height() * 9 / 10); + + + resize(QSize(newWidth, newHeight)); + + +} + + + +void LogViewTelegramDialog::showTree(LogViewField *a_fieldTree, QGridLayout *a_box) +{ + int i = 0; + while (LogViewField *child = a_fieldTree->child(i++)) + { + if (!a_fieldTree->hasContent()) + child->setHasContent(false); + switch (child->kind()) + { + case LogViewField::e_FieldKindBorder: + { + QGroupBox *groupBox = new QGroupBox(child->cleanName()); + QGridLayout *actBox = new QGridLayout(groupBox); + a_box->addWidget(groupBox, a_box->rowCount(), 0, 1, 2); + showTree(child, actBox); + break; + } + case LogViewField::e_FieldKindTab: + showTab(child, a_box); + break; + case LogViewField::e_FieldKindTabChild: + { + QWidget *widget = new QWidget; + widget->setContentsMargins(QMargins()); + QGridLayout *actBox = new QGridLayout(widget); + a_box->addWidget(widget, a_box->rowCount(), 0, 1, 2); + showTree(child, actBox); + break; + } + case LogViewField::e_FieldKindEdit: + case LogViewField::e_FieldKindPodArray: + case LogViewField::e_FieldKindPodArrayChild: + showEditField(child, a_box); + break; + } + } +} + + + +void LogViewTelegramDialog::fillTelegram(LogViewTelegram *a_telegram) +{ + INFO_LOG(m_logger) << "******************************************"; + + + + for (const auto ptr : qAsConst(m_EditInfoList)) + { + if (!ptr->isValid()) + { + INFO_LOG(m_logger) << ptr->field()->name() << " is invalid"; + return; + } + } + + + + a_telegram->resetOffset(); + a_telegram->clearJsonData(); + for (auto ptr : qAsConst(m_EditInfoList)) + { + if (!ptr->saveContent(a_telegram)) + { + QMessageBox::warning(this, tr("Error while saving telegram"), + tr("Found an invalid value - the telegram may be not saved correctly")); + } + } +} + + + +void LogViewTelegramDialog::saveTelegram() +{ + fillTelegram(m_Telegram.data()); + + + N_SST::IntegerCalculator calculator; + N_SST::IntegerCalculator::E_Error error; + m_Telegram->setWaitTime(calculator.calc(m_WaitTimeEdit->text().toStdString(), error)); + m_Telegram->setName(m_NameEdit->text()); + + accept(); +} + + +void LogViewTelegramDialog::sendCurrentTelegram() +{ + emit sendTelegram(m_Telegram); +} + + +void LogViewTelegramDialog::showButtons(QLayout *a_layout) +{ + if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Telegram->getProtocol()) + { + QPushButton *btnSend = new QPushButton(QIcon(QLatin1String(":icons/16x16/mail-send.png")), tr("&Send")); + btnSend->setEnabled(true); + connect(btnSend, &QPushButton::clicked, this, &LogViewTelegramDialog::sendCurrentTelegram); + a_layout->addWidget(btnSend); + } + + if (m_ReadOnly) + { + QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen")); + connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject); + a_layout->addWidget(btnClose); + } + else + { + + QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Abbrechen")); + connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject); + a_layout->addWidget(btnClose); + + QPushButton *btnOk = new QPushButton(QIcon(QLatin1String(":icons/16x16/dialog-ok-apply.png")), tr("&OK")); + btnOk->setDefault(true); + + connect(btnOk, &QPushButton::clicked, this, &LogViewTelegramDialog::saveTelegram); + a_layout->addWidget(btnOk); + } +} + + + +void LogViewTelegramDialog::showEditField(LogViewField *a_logViewField, QGridLayout *a_box) +{ + + + + + + + switch (a_logViewField->valueListSize()) + { + case 1: + + if (m_ReadOnly || !a_logViewField->isDynamicArray() || (LogViewXdrStandardType::e_Character == static_cast(a_logViewField->xdrElement())->getValueKind())) + { + QLabel *label = new QLabel(a_logViewField->cleanName()); + a_box->addWidget(label, a_box->rowCount(), 0); + LogViewWidget *valueWidget = nullptr; + + + { + + + if (LogViewXdrElement::e_KindEnum == a_logViewField->xdrElement()->getKind()) + { + + + valueWidget = new LogViewEnumEdit(a_logViewField, this, m_ReadOnly, 0); + } + else + { + if (a_logViewField->isDateTimeField() || a_logViewField->isMSecsField()) + { + + + valueWidget = new LogViewDateTimeEdit(a_logViewField, this, m_ReadOnly); + } + else + { + switch (static_cast(a_logViewField->xdrElement())->getValueKind()) + { + case LogViewXdrStandardType::e_Boolean: + valueWidget = new LogViewBooleanEdit(a_logViewField, this, m_ReadOnly); + break; + case LogViewXdrStandardType::e_Signed: + case LogViewXdrStandardType::e_Unsigned: + case LogViewXdrStandardType::e_Float: + case LogViewXdrStandardType::e_Data: + valueWidget = new LogViewValueEdit(a_logViewField, this, m_ReadOnly); + break; + case LogViewXdrStandardType::e_Character: + valueWidget = new LogViewTextEdit(a_logViewField, this, m_ReadOnly); + break; + } + } + } + if (valueWidget) + m_EditInfoList.push_back(valueWidget); + } + + + + + + + + + + + + + + + + QWidget *w = dynamic_cast(valueWidget); + if (w) + a_box->addWidget(w, a_box->rowCount() - 1, 1); + else + WARNING_LOG(m_logger) << "Internal error - LogViewWidget is not derived from QWidget... !?"; + break; + } + + Q_FALLTHROUGH(); + case 0: + if (m_ReadOnly) + { + + a_box->addWidget(new QLabel(tr("Keine %1").arg(a_logViewField->cleanName()))); + break; + } + + Q_FALLTHROUGH(); + default: + { + + QLabel *label = new QLabel(a_logViewField->cleanName()); + a_box->addWidget(label, a_box->rowCount(), 0); + + + LogViewSpinBox *spinBox = nullptr; + if (!m_ReadOnly && a_logViewField->isDynamicArray()) + { + spinBox = new LogViewSpinBox(a_logViewField, this, a_logViewField->valueListSize()); + a_box->addWidget(spinBox, a_box->rowCount() - 1, 1); + } + + + LogViewTableWidget *tableWidget = new LogViewTableWidget(a_logViewField, this, m_ReadOnly); + m_EditInfoList.push_back(tableWidget); + a_box->addWidget(tableWidget, a_box->rowCount(), 0, 1, 2); + + + if (spinBox) + { + connect(spinBox, &LogViewSpinBox::valueEditingFinished, + tableWidget, &LogViewTableWidget::changeSize); + } + } + break; + } +} + + + +void LogViewTelegramDialog::showTab(LogViewField *a_logViewField, QGridLayout *a_box) +{ + LogViewSpinBox *spinBox = nullptr; + if (!m_ReadOnly && a_logViewField->isDynamicArray()) + { + + QLabel *label = new QLabel(a_logViewField->cleanName()); + a_box->addWidget(label, a_box->rowCount(), 0); + spinBox = new LogViewSpinBox(a_logViewField, this, 0); + a_box->addWidget(spinBox, a_box->rowCount() - 1, 1); + } + + LogViewTabWidget *a_tabWidget = new LogViewTabWidget(a_logViewField, this, spinBox); + m_EditInfoList.push_back(dynamic_cast(a_tabWidget)); + a_box->addWidget(a_tabWidget, a_box->rowCount(), 0, 1, 2); + + + if (spinBox) + { + connect(spinBox, &LogViewSpinBox::valueEditingFinished, + a_tabWidget, &LogViewTabWidget::changeSize); + } + + + if (a_logViewField->hasContent()) + { + for (int i = 0; i < a_logViewField->childCount(); ++i) + a_tabWidget->addTab(a_logViewField, false, i); + } +} + + +bool LogViewTelegramDialog::removeItemsFromEditInfoList(const QStringList &jsonPath) +{ + if (m_EditInfoList.empty()) + return false; + for (int i = m_EditInfoList.size() - 1; i >= 0; --i) + { + LogViewWidget *lvw = m_EditInfoList.at(i); + const QStringList jsonPathChild = lvw->field()->jsonPath(); + if (jsonPathChild.size() < jsonPath.size()) + continue; + bool bIsChild = true; + for (int j = 0; j < jsonPath.size(); ++j) + { + if (jsonPath.at(j) != jsonPathChild.at(j)) + { + bIsChild = false; + break; + } + } + if (!bIsChild) + continue; + delete m_EditInfoList.at(i); + m_EditInfoList.removeAt(i); + } + m_EditInfoList.resize(m_EditInfoList.size() - 1); + return true; +} + + +} diff --git a/TetraIF/LogView/LogViewTelegramDialog.hpp b/TetraIF/LogView/LogViewTelegramDialog.hpp new file mode 100644 index 000000000..a39d02518 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramDialog.hpp @@ -0,0 +1,77 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +class QGridLayout; +class QTabWidget; +class QFrame; +class QScrollArea; +class QLineEdit; + + +namespace N_LogView +{ +class LogViewWidget; +class LogViewTelegram; +class LogViewField; + + + +class LogViewTelegramDialog : public QDialog +{ + Q_OBJECT +public: + explicit LogViewTelegramDialog(QWidget *a_parent = nullptr, const bool a_readonly = true); + + void showDialog(const QSharedPointer &a_telegram); + void showDataDump(const QSharedPointer &a_telegram, bool showErrorMessage); + void makePretty(); + void showTree(LogViewField *a_fieldTree, QGridLayout *a_box); + + + + bool removeItemsFromEditInfoList(const QStringList &jsonPath); + +Q_SIGNALS: + void sendTelegram(const QSharedPointer &telegramToSend); +protected slots: + void saveTelegram(); + + void sendCurrentTelegram(); + +protected: + + void fillTelegram(LogViewTelegram *a_telegram); + void showButtons(QLayout *a_layout); + void showEditField(LogViewField *a_logViewField, QGridLayout *a_box); + void showTab(LogViewField *a_logViewField, QGridLayout *a_box); + +private: + QSharedPointer m_Telegram; + QVector m_EditInfoList; + QScopedPointer m_fieldTree; + QWidget *m_contentsWidget = nullptr; + QScrollArea *m_ScrollArea = nullptr; + QLineEdit *m_NameEdit = nullptr; + QLineEdit *m_WaitTimeEdit = nullptr; + bool m_ReadOnly = false; + + NGL::INGLLogger &m_logger; + +}; + +} diff --git a/TetraIF/LogView/LogViewTelegramEdit.cpp b/TetraIF/LogView/LogViewTelegramEdit.cpp new file mode 100644 index 000000000..952d3bfc4 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramEdit.cpp @@ -0,0 +1,586 @@ + + + +#include "LogViewTelegramEdit.hpp" + +#include "LogViewInjectionThread.hpp" +#include "LogViewTelegramDialog.hpp" +#include "LogViewTelegramEditModel.hpp" +#include "LogViewTelegramSelectionDialog.hpp" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace N_LogView +{ + +QString TelegramEdit::s_DIR() +{ + return QStringLiteral("Dir"); +} +QString TelegramEdit::s_EDIT_TELEGRAM_GROUP() +{ + return QStringLiteral("EditTelegrams"); +} +QString TelegramEdit::s_TELEGRAMLIST_FILE_ID() +{ + return QStringLiteral("RDETGL"); +} +QString TelegramEdit::s_TELEGRAMLIST_FILES() +{ + return tr("Telegrammliste-Dateien (*.tgl);;Alle Dateien (*)"); +} + +TelegramEdit::TelegramEdit(QWidget *parent) + : QObject(parent) + , m_addTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/list-add.png")), tr("Add Telegram"), this)) + , m_editTeleAction(new QAction(QIcon(QLatin1String(":/image/Edit.png")), tr("Edit Telegram"), this)) + , m_copyTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/edit-copy.png")), tr("Copy Telegram"), this)) + , m_pasteTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/edit-paste.png")), tr("Paste Telegram"), this)) + , m_deleteTeleAction(new QAction(QIcon(QLatin1String(":icons/16x16/list-remove.png")), tr("Delete Telegram"), this)) + , m_moveTeleUpAction(new QAction(QIcon(QLatin1String(":icons/16x16/go-up.png")), tr("Move up"), this)) + , m_moveTeleDownAction(new QAction(QIcon(QLatin1String(":icons/16x16/go-down.png")), tr("Move down"), this)) + , m_teleListLoad(new QAction(QIcon(QLatin1String(":icons/16x16/document-open-data.png")), tr("Load Telegram list"), this)) + , m_teleListAppend(new QAction(QIcon(), tr("Telegrammliste anhaengen"), this)) + , m_teleListSave(new QAction(QIcon(QLatin1String(":icons/16x16/document-save.png")), tr("Save Telegram list"), this)) + , m_tableView(new QTableView(parent)) + , m_DoLoop(false) + , m_InjectionThread(nullptr) + , m_EditModel(new TelegramEditModel(this)) + , m_logger(getLogger("LogViewTelegramEdit")) +{ + m_addTeleAction->setShortcut(tr("Ctrl+A")); + m_editTeleAction->setShortcut(tr("Ctrl+E")); + m_copyTeleAction->setShortcut(tr("Ctrl+C")); + m_pasteTeleAction->setShortcut(tr("Ctrl+V")); + m_deleteTeleAction->setShortcut(Qt::Key_Delete); + m_moveTeleUpAction->setShortcut(tr("Ctrl+U")); + m_moveTeleDownAction->setShortcut(tr("Ctrl+D")); + m_teleListLoad->setShortcut(tr("Ctrl+L")); + m_teleListAppend->setShortcut(tr("Ctrl+K")); + m_teleListSave->setShortcut(tr("Ctrl+S")); + m_addTeleAction->setEnabled(true); + m_copyTeleAction->setEnabled(false); + m_pasteTeleAction->setEnabled(false); + m_deleteTeleAction->setEnabled(false); + m_moveTeleUpAction->setEnabled(false); + m_moveTeleDownAction->setEnabled(false); + m_teleListLoad->setEnabled(true); + m_teleListAppend->setEnabled(true); + m_teleListSave->setEnabled(false); + + connect(m_addTeleAction, &QAction::triggered, this, &TelegramEdit::addTelegram); + connect(m_editTeleAction, &QAction::triggered, this, &TelegramEdit::editTelegram); + connect(m_copyTeleAction, &QAction::triggered, this, &TelegramEdit::copy); + connect(m_pasteTeleAction, &QAction::triggered, this, &TelegramEdit::paste); + connect(m_deleteTeleAction, &QAction::triggered, this, &TelegramEdit::deleteTelegram); + connect(m_moveTeleUpAction, &QAction::triggered, this, &TelegramEdit::moveUp); + connect(m_moveTeleDownAction, &QAction::triggered, this, &TelegramEdit::moveDown); + connect(m_teleListLoad, &QAction::triggered, this, &TelegramEdit::loadTelegramListReplace); + connect(m_teleListAppend, &QAction::triggered, this, &TelegramEdit::loadTelegramListAppend); + connect(m_teleListSave, &QAction::triggered, this, &TelegramEdit::saveTelegramList); + + m_tableView->setModel(m_EditModel); + m_tableView->verticalHeader()->hide(); + m_tableView->setContextMenuPolicy(Qt::CustomContextMenu); + m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_tableView->setSelectionMode(QAbstractItemView::SingleSelection); + connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &TelegramEdit::onSelectionChanged); + connect(m_tableView, &QTableView::doubleClicked, + this, &TelegramEdit::editTelegram); + connect(m_tableView, &QTableView::customContextMenuRequested, + this, &TelegramEdit::tableViewCustomContextMenu); + m_tableView->addAction(m_addTeleAction); + m_tableView->addAction(m_editTeleAction); + m_tableView->addAction(m_copyTeleAction); + m_tableView->addAction(m_pasteTeleAction); + m_tableView->addAction(m_deleteTeleAction); + m_tableView->addAction(m_moveTeleUpAction); + m_tableView->addAction(m_moveTeleDownAction); +} + +void TelegramEdit::setInjectionThread(LogViewInjectionThread *a_injectionThread) +{ + m_InjectionThread = a_injectionThread; +} + +void TelegramEdit::appendTelegram(const QSharedPointer &telegram) +{ + m_EditModel->appendTelegram(telegram); + m_teleListSave->setEnabled(true); +} + +void TelegramEdit::tableViewCustomContextMenu(const QPoint &pos) +{ + QMenu menu; + + + + menu.addAction(m_addTeleAction); + menu.addAction(m_editTeleAction); + menu.addAction(m_copyTeleAction); + menu.addAction(m_pasteTeleAction); + menu.addAction(m_deleteTeleAction); + + + + menu.addSeparator(); + menu.addAction(m_moveTeleUpAction); + menu.addAction(m_moveTeleDownAction); + + menu.addSeparator(); + + const bool itemSelected = m_tableView->currentIndex().isValid(); + + bool isCentral = false; + QSharedPointer tele = m_EditModel->telegram(m_tableView->currentIndex().row()); + if (tele) + isCentral = (tele->getProtocol() == N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral); + + + + if (isInjectionPossible()) + { + QAction *action = menu.addAction(QIcon(QLatin1String(":/image/InjectCentral.png")), tr("Injektiere Zentral-Telegramm")); + + action->setEnabled(itemSelected && isCentral); + connect(action, &QAction::triggered, this, &TelegramEdit::injectCentralTelegram); + + action = menu.addAction(QIcon(QLatin1String(":/image/InjectTetra.png")), tr("Injektiere Tetra-Telegramm")); + + action->setEnabled(itemSelected && isCentral); + connect(action, &QAction::triggered, this, &TelegramEdit::injectTetraTelegram); + + menu.addSeparator(); + + + + action = menu.addAction(QIcon(QLatin1String(":icons/16x16/mail-send.png")), tr("Sende Telegramm")); + + action->setEnabled(itemSelected && isCentral); + connect(action, &QAction::triggered, this, &TelegramEdit::sendCurrentTelegram); + + if (m_DoLoop) + action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-playback-stop.png")), tr("Stop Loopen")); + else + { + action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-playback-start.png")), tr("Loop Telegramme")); + action->setEnabled(itemSelected); + } + connect(action, &QAction::triggered, this, &TelegramEdit::loopTelegrams); + + action = menu.addAction(QIcon(QLatin1String(":icons/16x16/media-play-normal.png")), tr("Sende Sequenz")); + action->setEnabled(itemSelected); + connect(action, &QAction::triggered, this, &TelegramEdit::sequenceTelegrams); + + + + menu.addSeparator(); + } + + menu.addAction(m_teleListLoad); + menu.addAction(m_teleListAppend); + menu.addAction(m_teleListSave); + + menu.exec(m_tableView->viewport()->mapToGlobal(pos)); +} + + + + + + + + + +void TelegramEdit::addTelegram() +{ + + LogViewTelegramSelectionDialog telegramSelectionDialog(m_tableView); + if (QDialog::Accepted == telegramSelectionDialog.exec()) + { + QSharedPointer newTelegram = QSharedPointer(new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, + telegramSelectionDialog.getSelectedTelegramId())); + m_curEditTelegramRow = m_EditModel->appendTelegram(newTelegram); + + + LogViewTelegramDialog *editTelegramDialog = new LogViewTelegramDialog(m_tableView, false); + connect(editTelegramDialog, &LogViewTelegramDialog::finished, + this, &TelegramEdit::editTelegramDialogFinished); + connect(editTelegramDialog, &LogViewTelegramDialog::sendTelegram, + this, &TelegramEdit::sendTelegram); + editTelegramDialog->showDialog(newTelegram); + + m_teleListSave->setEnabled(true); + } +} + +QSharedPointer TelegramEdit::currentSelectedTelegram() const +{ + return m_EditModel->telegram(currentSelectedIndex().row()); +} + +QModelIndex TelegramEdit::currentSelectedIndex() const +{ + return m_tableView->currentIndex(); +} + +void TelegramEdit::editTelegramDialogFinished() +{ + + m_EditModel->emitDataChanged(m_curEditTelegramRow); +} + + + + +void TelegramEdit::editTelegram() +{ + m_curEditTelegramRow = currentSelectedIndex().row(); + if (m_curEditTelegramRow < 0) + return; + LogViewTelegramDialog *editTelegramDialog = new LogViewTelegramDialog(m_tableView, false); + connect(editTelegramDialog, &LogViewTelegramDialog::finished, this, &TelegramEdit::editTelegramDialogFinished); + editTelegramDialog->showDialog(currentSelectedTelegram()); +} + + + + +void TelegramEdit::showTelegram() +{ + LogViewTelegramDialog *showTelegramDialog = new LogViewTelegramDialog(m_tableView, true); + showTelegramDialog->showDialog(currentSelectedTelegram()); + + + + + +} + +void TelegramEdit::deleteTelegram() +{ + const QModelIndexList indexList = m_tableView->selectionModel()->selectedIndexes(); + QSet rows; + rows.reserve(indexList.size()); + for (const QModelIndex &index : indexList) + rows += index.row(); + + m_EditModel->removeTelegrams(rows); + m_teleListSave->setEnabled(m_EditModel->rowCount() > 0); +} + +void TelegramEdit::injectCentralTelegram() +{ + injectTelegram(true); +} + +void TelegramEdit::injectTetraTelegram() +{ + injectTelegram(false); +} + +void TelegramEdit::injectTelegram(bool a_bAsCentralTelegram) +{ + injectTelegram(currentSelectedTelegram(), a_bAsCentralTelegram); +} + +void TelegramEdit::injectTelegram(const QSharedPointer &a_telegram, bool a_bAsCentralTelegram) +{ + if (!isInjectionPossible()) + { + WARNING_LOG(m_logger) << "Try to inject a telegramm but the injection thread is not running"; + return; + } + if (a_telegram.isNull()) + { + WARNING_LOG(m_logger) << "Try to inject a telegramm but no telegramm selected"; + return; + } + a_telegram->actualizeGpsTime(); + m_InjectionThread->sendTelegram(a_telegram.data(), a_bAsCentralTelegram); +} + +void TelegramEdit::sendCurrentTelegram() +{ + sendTelegram(currentSelectedTelegram()); +} + +void TelegramEdit::sendTelegram(const QSharedPointer &a_telegram) +{ + injectTelegram(a_telegram, true); +} + +void TelegramEdit::loopTelegrams() +{ + + if (m_DoLoop) + { + m_DoLoop = false; + m_deleteTeleAction->setEnabled(m_tableView->currentIndex().isValid()); + } + else + { + m_DoLoop = true; + m_deleteTeleAction->setEnabled(false); + m_currentRowToSend = currentSelectedIndex().row(); + if (m_currentRowToSend < 0) + return; + QSharedPointer tele = currentSelectedTelegram(); + sendTelegram(tele); + QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::loopNextTelegram); + } +} + +void TelegramEdit::loopNextTelegram() +{ + if (!m_DoLoop) + return; + ++m_currentRowToSend; + + if (m_currentRowToSend >= m_tableView->model()->rowCount()) + m_currentRowToSend = 0; + + QSharedPointer tele = telegramAtRow(m_currentRowToSend); + if (!tele) + return; + + sendTelegram(tele); + QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::loopNextTelegram); +} + +void TelegramEdit::sequenceTelegrams() +{ + m_currentRowToSend = currentSelectedIndex().row(); + if (m_currentRowToSend < 0) + return; + QSharedPointer tele = currentSelectedTelegram(); + sendTelegram(tele); + QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::sequenceNextTelegram); +} + +void TelegramEdit::sequenceNextTelegram() +{ + ++m_currentRowToSend; + if (m_currentRowToSend >= m_tableView->model()->rowCount()) + return; + + QSharedPointer tele = telegramAtRow(m_currentRowToSend); + if (!tele) + return; + + sendTelegram(tele); + QTimer::singleShot(tele->getWaitTime(), this, &TelegramEdit::sequenceNextTelegram); +} + +QSharedPointer TelegramEdit::telegramAtRow(int row) +{ + return m_EditModel->telegram(row); +} + +void TelegramEdit::copy() +{ + m_copyTelegram = currentSelectedTelegram(); + m_pasteTeleAction->setEnabled(m_copyTelegram != nullptr); + if (!m_copyTelegram) + return; + m_copyTelegram = QSharedPointer(new LogViewTelegram(*m_copyTelegram.data())); +} + +void TelegramEdit::paste() +{ + if (!m_copyTelegram) + return; + int row = currentSelectedIndex().row() + 1; + m_EditModel->pasteRows(row, m_copyTelegram); +} + +void TelegramEdit::moveUp() +{ + const QModelIndex idx = currentSelectedIndex(); + if (m_EditModel->moveUp(idx.row())) + { + m_tableView->clearSelection(); + m_tableView->setCurrentIndex(m_EditModel->index(idx.row() - 1, idx.column(), idx.parent())); + m_moveTeleUpAction->setEnabled(idx.row() > 1); + m_moveTeleDownAction->setEnabled(true); + } +} + +void TelegramEdit::moveDown() +{ + const QModelIndex idx = currentSelectedIndex(); + if (m_EditModel->moveDown(idx.row())) + { + m_tableView->clearSelection(); + m_tableView->setCurrentIndex(m_EditModel->index(idx.row() + 1, idx.column(), idx.parent())); + m_moveTeleUpAction->setEnabled(true); + m_moveTeleDownAction->setEnabled(idx.row() < m_EditModel->rowCount() - 2); + } +} + +void TelegramEdit::saveTelegramList() +{ + + QSettings settings; + QString newFilename = QFileDialog::getSaveFileName(m_tableView, + tr("Dateiname der Telegrammliste"), + settings.value(s_DIR()).toString(), + s_TELEGRAMLIST_FILES()); + if (!newFilename.isEmpty()) + { + if (!newFilename.contains(QLatin1Char('.'))) + newFilename += QLatin1String(".tgl"); + + + QDir dir; + settings.beginGroup(s_EDIT_TELEGRAM_GROUP()); + settings.setValue(s_DIR(), dir.filePath(newFilename)); + settings.endGroup(); + + + QFile telegramFile(newFilename); + telegramFile.open(QIODevice::WriteOnly); + QDataStream stream(&telegramFile); + + + uint32_t version = 1; + stream << s_TELEGRAMLIST_FILE_ID() << version; + + + int rows = m_tableView->model()->rowCount(); + stream << rows; + for (int i = 0; i < rows; i++) + { + QSharedPointer telegram = telegramAtRow(i); + if (!telegram) + continue; + + const QByteArray &data = telegram->getData(); + const QString name = telegram->getName(); + const unsigned int waitTime = telegram->getWaitTime(); + + stream << waitTime + << name + << telegram->getGpsTimeField() + << data.size(); + stream.writeRawData(data.data(), data.size()); + } + telegramFile.close(); + } +} + +void TelegramEdit::loadTelegramListAppend() +{ + loadTelegramList(true); +} + +void TelegramEdit::loadTelegramListReplace() +{ + loadTelegramList(false); +} + +void TelegramEdit::loadTelegramList(bool checkAppend) +{ + + QSettings settings; + QString newFilename = QFileDialog::getOpenFileName(m_tableView, + tr("Dateiname der Telegrammliste"), + settings.value(s_DIR()).toString(), + s_TELEGRAMLIST_FILES()); + if (!newFilename.isEmpty()) + { + + QDir dir; + settings.beginGroup(s_EDIT_TELEGRAM_GROUP()); + settings.setValue(s_DIR(), dir.filePath(newFilename)); + settings.endGroup(); + + + { + if (!checkAppend) + m_EditModel->clearTelegrams(); + } + + + QFile telegramFile(newFilename); + telegramFile.open(QIODevice::ReadOnly); + QDataStream stream(&telegramFile); + + + QString id; + stream >> id; + if (id != s_TELEGRAMLIST_FILE_ID()) + { + QMessageBox::critical(m_tableView, tr("Error"), tr("%1 does not contain telegram data").arg(newFilename)); + return; + } + uint32_t version = 0; + stream >> version; + if (version != 1) + { + QMessageBox::critical(m_tableView, tr("Error"), tr("Wrong telegram list file version")); + return; + } + + + int rows = 0; + QVector gpsFieldOffset; + stream >> rows; + for (int i = 0; i < rows; i++) + { + uint32_t waitTime = 0; + QString name; + int telegramSize = 0; + stream >> waitTime >> name >> gpsFieldOffset >> telegramSize; + if (telegramSize > 0) + { + DEBUG_LOG(m_logger) << "telegramSize=" << telegramSize; + QByteArray buf(telegramSize, Qt::Uninitialized); + stream.readRawData(buf.data(), telegramSize); + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Debug, buf); + LogViewTelegram *telegram = new LogViewTelegram(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, + 0, + buf); + telegram->setWaitTime(waitTime); + telegram->setName(name); + telegram->setGpsTimeField(gpsFieldOffset); + m_EditModel->appendTelegram(QSharedPointer(telegram)); + } + } + telegramFile.close(); + + m_teleListSave->setEnabled(m_EditModel->rowCount() > 0); + } +} + + +bool TelegramEdit::isInjectionPossible() const +{ + return m_InjectionThread ? m_InjectionThread->isSendingPossible() : false; +} + + +void TelegramEdit::onSelectionChanged() +{ + const QModelIndex idx = currentSelectedIndex(); + + m_editTeleAction->setEnabled(idx.isValid()); + m_copyTeleAction->setEnabled(idx.isValid()); + m_deleteTeleAction->setEnabled(idx.isValid()); + m_moveTeleUpAction->setEnabled(idx.row() > 0); + m_moveTeleDownAction->setEnabled(idx.isValid() && idx.row() < m_EditModel->rowCount() - 1); +} + +} diff --git a/TetraIF/LogView/LogViewTelegramEdit.hpp b/TetraIF/LogView/LogViewTelegramEdit.hpp new file mode 100644 index 000000000..1be320794 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramEdit.hpp @@ -0,0 +1,121 @@ + + + +#pragma once + +#include "LogViewTelegram.hpp" +#include + +class QAction; +class QTableView; + +namespace N_LogView +{ +class LogViewInjectionThread; +class TelegramEditModel; + +class TelegramEdit :public QObject +{ + Q_OBJECT +public: + explicit TelegramEdit(QWidget *parent = nullptr); + + QTableView *tableView() { return m_tableView; } + + void appendTelegram(const QSharedPointer &telegram); + + void setInjectionThread(LogViewInjectionThread* a_injectionThread); + + bool isInjectionPossible() const; + +protected: + QSharedPointer m_copyTelegram; + + QSharedPointer currentSelectedTelegram() const; + + QModelIndex currentSelectedIndex() const; + + QSharedPointer telegramAtRow(int row); + + void loadTelegramList(bool checkAppend); + +protected: + QAction *m_addTeleAction; + QAction *m_editTeleAction; + QAction *m_copyTeleAction; + QAction *m_pasteTeleAction; + QAction *m_deleteTeleAction; + QAction *m_moveTeleUpAction; + QAction *m_moveTeleDownAction; + QAction *m_teleListLoad; + QAction *m_teleListAppend; + QAction *m_teleListSave; + QTableView *m_tableView; + bool m_DoLoop; + + LogViewInjectionThread *m_InjectionThread; + + int m_currentRowToSend; + + int m_curEditTelegramRow; + + TelegramEditModel *m_EditModel; + + NGL::INGLLogger &m_logger; + + static QString s_DIR(); + static QString s_EDIT_TELEGRAM_GROUP(); + static QString s_TELEGRAMLIST_FILE_ID(); + static QString s_TELEGRAMLIST_FILES(); + +protected Q_SLOTS: + + void addTelegram(); + + void injectTelegram(bool a_bAsCentralTelegram); + + void injectTelegram(const QSharedPointer &a_telegram, bool a_bAsCentralTelegram); + + void sendTelegram(const QSharedPointer &a_telegram); + + void sendCurrentTelegram(); + + void tableViewCustomContextMenu(const QPoint &pos); + + void editTelegram(); + + void showTelegram(); + + void deleteTelegram(); + + void injectCentralTelegram(); + + void injectTetraTelegram(); + + void loopTelegrams(); + + void loopNextTelegram(); + + void sequenceTelegrams(); + + void sequenceNextTelegram(); + + void copy(); + + void paste(); + + void moveUp(); + + void moveDown(); + + void saveTelegramList(); + + void loadTelegramListAppend(); + + void loadTelegramListReplace(); + + void editTelegramDialogFinished(); + + void onSelectionChanged(); +}; +} diff --git a/TetraIF/LogView/LogViewTelegramEditModel.cpp b/TetraIF/LogView/LogViewTelegramEditModel.cpp new file mode 100644 index 000000000..e6cba4fc5 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramEditModel.cpp @@ -0,0 +1,163 @@ + + + +#include "LogViewTelegramEditModel.hpp" +#include + +namespace N_LogView +{ + + +int TelegramEditModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_telegrams.size(); +} + + +int TelegramEditModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : 3; +} + + +QVariant TelegramEditModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && index.row() < m_telegrams.size()) + { + if (role == Qt::DisplayRole) + { + const QSharedPointer telegram = m_telegrams.at(index.row()); + switch (index.column()) + { + case 0: + return telegram->getName(); + case 1: + return telegram->getParticipantId(); + case 2: + return telegram->getWaitTime(); + } + } + else if (role == Qt::ToolTipRole) + { + const QSharedPointer telegram = m_telegrams.at(index.row()); + if (telegram->isJsonTelegram()) + return telegram->getData(QJsonDocument::JsonFormat::Indented); + } + } + return QVariant(); +} + + +QVariant TelegramEditModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + switch (section) + { + case 0: + return tr("Description"); + case 1: + return tr("Equip. No."); + case 2: + return tr("Wait Time"); + default: + break; + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + + +void TelegramEditModel::clearTelegrams() +{ + beginResetModel(); + m_telegrams.clear(); + endResetModel(); +} + + +void TelegramEditModel::appendTelegrams(const QVector > &telegrams) +{ + if (telegrams.isEmpty()) + return; + beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size() + telegrams.size() - 1); + m_telegrams += telegrams; + endInsertRows(); +} + + +int TelegramEditModel::appendTelegram(const QSharedPointer &telegram) +{ + beginInsertRows(QModelIndex(), m_telegrams.size(), m_telegrams.size()); + m_telegrams.push_back(telegram); + telegram->rebuildJsonString(); + endInsertRows(); + return m_telegrams.size() - 1; +} + + +QSharedPointer TelegramEditModel::telegram(int row) const +{ + if (row >= 0 && row < m_telegrams.size()) + return m_telegrams.at(row); + return QSharedPointer(); +} + + +bool TelegramEditModel::moveUp(int row) +{ + if (row <= 0 || row >= m_telegrams.size()) + return false; + beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1); + std::swap(m_telegrams[row], m_telegrams[row - 1]); + endMoveRows(); + return true; +} + + +bool TelegramEditModel::moveDown(int row) +{ + if (row >= (m_telegrams.size() - 1)) + return false; + beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 1); + std::swap(m_telegrams[row], m_telegrams[row + 1]); + endMoveRows(); + return true; +} + + +void TelegramEditModel::emitDataChanged(int row) +{ + QModelIndex top = createIndex(row, 0); + QModelIndex bottom = createIndex(row, columnCount() - 1); + emit dataChanged(top, bottom, {Qt::DisplayRole, Qt::ToolTipRole}); +} + + +void TelegramEditModel::removeTelegrams(const QSet &rows) +{ + QList rowList = rows.values(); + std::sort(rowList.begin(), rowList.end()); + + for (int i = rowList.size() - 1 ; i >= 0; --i) + { + int row = rowList.at(i); + beginRemoveRows(QModelIndex(), row, row); + m_telegrams.remove(row); + endRemoveRows(); + } +} + + +void TelegramEditModel::pasteRows(int row, const QSharedPointer &tele) +{ + if (row < 0 || row > m_telegrams.size()) + return; + beginInsertRows(QModelIndex(), row, row); + m_telegrams.insert(row, QSharedPointer(new LogViewTelegram(*tele.data()))); + endInsertRows(); +} + +} diff --git a/TetraIF/LogView/LogViewTelegramEditModel.hpp b/TetraIF/LogView/LogViewTelegramEditModel.hpp new file mode 100644 index 000000000..ce650385c --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramEditModel.hpp @@ -0,0 +1,44 @@ + + + +#pragma once + +#include +#include +#include +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ +class TelegramEditModel final : public QAbstractTableModel +{ + Q_OBJECT +public: + using QAbstractTableModel::QAbstractTableModel; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + + void clearTelegrams(); + void appendTelegrams(const QVector > &telegrams); + int appendTelegram(const QSharedPointer &telegram); + QSharedPointer telegram(int row) const; + + bool moveUp(int row); + bool moveDown(int row); + + void emitDataChanged(int row); + + void removeTelegrams(const QSet &rows); + + void pasteRows(int row, const QSharedPointer &tele); +protected: + QVector > m_telegrams; + +}; +} diff --git a/TetraIF/LogView/LogViewTelegramSelectionDialog.cpp b/TetraIF/LogView/LogViewTelegramSelectionDialog.cpp new file mode 100644 index 000000000..eb9c7e506 --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramSelectionDialog.cpp @@ -0,0 +1,62 @@ + + + + + + + + + + + + + +#include "LogViewTelegramSelectionDialog.hpp" +#include +#include +#include +#include "LogViewXdrType.hpp" +#include "LogViewXdrParser.hpp" +#include "LogViewTelegram.hpp" +#include "LogViewTetraTelegramsParser.hpp" + +namespace N_LogView +{ +static int s_currentRow = 0; + +LogViewTelegramSelectionDialog::LogViewTelegramSelectionDialog(QWidget* a_parent) + : QDialog(a_parent) +{ + setMinimumSize(QSize(600, 500)); + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget(new QLabel(tr("Select a telegram:"))); + m_TelegramList = new QListWidget(this); + const auto telegramMap = LogViewTelegram::jsonParser()->telegramsToCreate(); + for (auto it = telegramMap.cbegin(); it != telegramMap.cend(); ++it) + { + if (it.key() == 0) + continue; + auto lwi = new QListWidgetItem(it.value() + QStringLiteral(" (%1)").arg(it.key())); + lwi->setData(Qt::UserRole, it.key()); + m_TelegramList->addItem(lwi); + } + + m_TelegramList->sortItems(); + m_TelegramList->setCurrentRow(s_currentRow); + connect(m_TelegramList, &QListWidget::itemActivated, + this, &LogViewTelegramSelectionDialog::selectTelegram); + layout->addWidget(m_TelegramList); + + setLayout(layout); +} + + + +void LogViewTelegramSelectionDialog::selectTelegram(QListWidgetItem* a_telegramItem) +{ + s_currentRow = m_TelegramList->currentRow(); + m_SelectedTelegramId = a_telegramItem->data(Qt::UserRole).toInt(); + accept(); +} + +} diff --git a/TetraIF/LogView/LogViewTelegramSelectionDialog.hpp b/TetraIF/LogView/LogViewTelegramSelectionDialog.hpp new file mode 100644 index 000000000..5470ccc6d --- /dev/null +++ b/TetraIF/LogView/LogViewTelegramSelectionDialog.hpp @@ -0,0 +1,46 @@ + + + + + + + + + + + + + +#pragma once + +#include +class QListWidget; +class QListWidgetItem; + +namespace N_LogView +{ + + + class LogViewTelegramSelectionDialog : public QDialog + { + Q_OBJECT + public: + + + explicit LogViewTelegramSelectionDialog(QWidget* a_parent); + + + int getSelectedTelegramId() const { return m_SelectedTelegramId; } + + protected slots: + + + void selectTelegram(QListWidgetItem* a_telegramItem); + + protected: + + QListWidget *m_TelegramList; + int m_SelectedTelegramId; +}; + +} diff --git a/TetraIF/LogView/LogViewTetraTelegramsParser.cpp b/TetraIF/LogView/LogViewTetraTelegramsParser.cpp new file mode 100644 index 000000000..5825c72fc --- /dev/null +++ b/TetraIF/LogView/LogViewTetraTelegramsParser.cpp @@ -0,0 +1,516 @@ + + + +#include "LogViewTetraTelegramsParser.hpp" + +#include +#include + +namespace N_LogView +{ + +LogViewTetraTelegramsParser::LogViewTetraTelegramsParser() + : m_logger(getLogger("LogViewTetraTelegramsParser")) +{ + insertPod(QStringLiteral("bool"), 1, true, true, true); + insertPod(QStringLiteral("int"), 4, true, true); + insertPod(QStringLiteral("int32_t"), 4, true, true); + insertPod(QStringLiteral("qint64"), 8, true, true); + insertPod(QStringLiteral("float"), 4, true, false); + insertPod(QStringLiteral("double"), 8, true, false); +} + +EnumInformation LogViewTetraTelegramsParser::enumFromType(const QString &type) const +{ + for (const auto &ei : m_enums) + { + const QString fqType = ei.ns.isEmpty() ? ei.type : (ei.ns + QStringLiteral("::") + ei.type); + if (fqType == type) + return ei; + } + return EnumInformation(); +} + +StructInformation LogViewTetraTelegramsParser::structFromType(const QString &type) const +{ + return m_structs.value(type); +} + +PodInformation LogViewTetraTelegramsParser::podFromType(const QString &type) const +{ + return m_pods.value(type); +} + +bool LogViewTetraTelegramsParser::isEnum(const QString &type) const +{ + for (const auto &ei : m_enums) + if (ei.type == type) + return true; + return false; +} + +bool LogViewTetraTelegramsParser::isStruct(const QString &type) const +{ + return m_structs.contains(type); +} + +bool LogViewTetraTelegramsParser::isPod(const QString &type) const +{ + return m_pods.contains(type); +} + +static void fillBasemembers(StructInformation &si, const QHash &structs) +{ + if (si.baseStruct.isEmpty()) + return; + StructInformation base = structs.value(si.baseStruct); + fillBasemembers(base, structs); + si.member = (base.member + si.member); +} + +bool LogViewTetraTelegramsParser::parse(const QString &filename) +{ + m_telegramIdEnum = EnumInformation(); + m_enums.clear(); + m_structs.clear(); + + m_visibleTelegrams.clear(); + + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) + { + WARNING_LOG(m_logger) << "Can not open file " << filename << " for reading: " << f.errorString(); + return false; + } + + const QString content = QString::fromUtf8(f.readAll()); + f.close(); + + const QVector lines = content.splitRef(QLatin1Char('\n')); + QVector linesTrimmed; + linesTrimmed.reserve(lines.size()); + for (const QStringRef &line : lines) + linesTrimmed += line.trimmed(); + + int i = 0; + while (i < linesTrimmed.size()) + { + const QStringRef &line = linesTrimmed.at(i); + if (line.startsWith(QLatin1String("struct"))) + { + i = parseStruct(linesTrimmed, i); + if (i < 0) + return false; + } + else if (line.startsWith(QLatin1String("enum"))) + { + i = parseEnum(linesTrimmed, i, QString()); + if (i < 0) + return false; + } + else if (line.startsWith(QLatin1String("template <> struct Constraints"))) + { + i = parseConstraint(linesTrimmed, i); + if (i < 0) + return false; + } + ++i; + } + + const auto completeStructs = m_structs; + for (StructInformation &si : m_structs) + fillBasemembers(si, completeStructs); + return true; +} + +void LogViewTetraTelegramsParser::insertPod(const QString &type, int byteLen, bool isSigned, bool isIntegral, bool isBoolean) +{ + PodInformation pod; + pod.type = type; + pod.byteLen = byteLen; + pod.isBoolean = isBoolean; + pod.isIntegral = isIntegral; + pod.isSigned = isSigned; + m_pods[type] = pod; +} + + +int LogViewTetraTelegramsParser::parseStruct(const QVector &lines, int iStartPos) +{ + const QVector tokens = tokenize(lines.at(iStartPos)); + if (tokens.size() < 2) + return -1; + const QStringRef &structType = tokens.at(1); + if (structType.endsWith(QLatin1Char(';'))) + return iStartPos; + + StructInformation si; + si.type = structType.toString(); + if (tokens.size() > 2) + { + if (tokens.at(2) != QLatin1String(":")) + { + WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1; + return -1; + } + + for (int i = 3; i < tokens.size(); ++i) + { + if (!si.baseStruct.isEmpty()) + { + WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1; + return -1; + } + QStringRef base = tokens.at(i); + if (base == QLatin1String("public") || + base == QLatin1String("protected") || + base == QLatin1String("private")) + continue; + if (base.endsWith(QLatin1Char(','))) + base.chop(1); + if (base.endsWith(QLatin1Char('>'))) + { + si.isVisible = true; + continue; + } + si.baseStruct = tokens.at(i).toString(); + } + } + + int i = iStartPos + 1; + while (i < lines.size()) + { + const QVector tokens = tokenize(lines.at(i)); + if (!validStructTokens(tokens)) + { + ++i; + continue; + } + if (tokens.at(0) == QLatin1String("};")) + break; + if (tokens.at(0) == QLatin1String("enum")) + { + i = parseEnum(lines, i, si.type, &si); + if (i < 0) + return -1; + ++i; + continue; + } + + MemberInformation mi; + if (tokens.size() > 2) + { + const int parserCommentPos = tokens.at(2) == QLatin1String("=") ? 4 : 2; + if (tokens.size() > parserCommentPos) + { + const QStringRef &comment = tokens.at(parserCommentPos); + DEBUG_LOG(m_logger) << "comment: " << comment.toString(); + if (comment.startsWith(QLatin1String("//@array: "))) + { + const QStringRef hint = comment.mid(QLatin1String("//@array: ").size()); + QString structStr = QLatin1String("struct ") + si.type + QLatin1String("::") + tokens.at(0).toString() + QLatin1Char('\n') + hint.toString(); + structStr.replace(QLatin1Char(';'), QLatin1String(";\n")); + DEBUG_LOG(m_logger) << "structStr: " << structStr; + parseStruct(structStr.splitRef(QLatin1Char('\n')), 0); + + mi.type = si.type + QLatin1String("::") + tokens.at(0).toString(); + mi.isArray = true; + } + if (comment == QLatin1String("//@invisible")) + mi.isVisible = false; + } + } + + QStringRef name = tokens.at(1); + if (name.endsWith(QLatin1Char(';'))) + name.chop(1); + if (mi.type.isEmpty()) + mi.type += tokens.at(0).toString(); + categorizeMember(mi); + mi.name = name.toString(); + if (mi.isEnum && !mi.type.contains(QLatin1String("::"))) + { + + for (const auto &ei : qAsConst(m_enums)) + { + if (ei.type == mi.type) + { + if (!ei.ns.isEmpty()) + mi.type = ei.ns + QLatin1String("::") + mi.type; + break; + } + } + } + si.member.push_back(std::move(mi)); + + ++i; + } + + if (m_logger.isDebugEnabled()) + { + if (si.baseStruct.isEmpty()) + DEBUG_LOG(m_logger) << "Found Struct: " << si.type; + else + DEBUG_LOG(m_logger) << "Found Struct: " << si.type << ", base: " << si.baseStruct; + for (int j = 0; j < si.member.size(); ++j) + { + const MemberInformation &mi = si.member.at(j); + DEBUG_LOG(m_logger) << "Member[" << j << "]: " << mi.type << " - " << mi.name; + } + } + + m_structs[si.type] = si; + + return i; +} + +int LogViewTetraTelegramsParser::parseEnum(const QVector &lines, int iStartPos, const QString &ns, StructInformation *si) +{ + const QVector tokens = tokenize(lines.at(iStartPos)); + if (tokens.size() < 2) + return -1; + QStringRef enumName = tokens.at(1); + if (enumName == QLatin1String("class")) + { + if (tokens.size() < 3) + return -1; + enumName = tokens.at(2); + } + if (enumName.endsWith(QLatin1Char(';'))) + return iStartPos; + + EnumInformation ei; + ei.type = enumName.toString(); + ei.ns = ns; + + int i = iStartPos + 1; + while (i < lines.size()) + { + const QVector tokens = tokenize(lines.at(i).split(QStringLiteral("//")).first()); + if (tokens.isEmpty() || + (tokens.at(0) == QLatin1String("{"))) + { + ++i; + continue; + } + if (tokens.at(0) == QLatin1String("};")) + break; + if ((tokens.size() != 1 && tokens.size() != 3) || + (tokens.size() == 3 && tokens.at(1) != QLatin1String("="))) + { + if (tokens.size() == 4 && tokens.at(0) == QLatin1String("}") && tokens.at(3).endsWith(QLatin1Char(';')) && si) + { + + MemberInformation mi; + if (ns.isEmpty()) + mi.type = ei.type; + else + mi.type = ns + QStringLiteral("::") + ei.type; + mi.isEnum = true; + mi.name = tokens.at(1).toString(); + si->member.push_back(std::move(mi)); + break; + } + WARNING_LOG(m_logger) << "Could not parse enum: '" << lines.at(i).toString() << "', line: " << i + 1; + return -1; + } + + EnumValue ev; + ev.key = tokens.at(0).toString(); + if (tokens.size() == 3) + { + QStringRef value = tokens.at(2); + if (value.endsWith(QLatin1Char(','))) + value.chop(1); + ev.value = value.toInt(); + } + else + { + int val = ei.values.isEmpty() ? 0 : (ei.values.last().value + 1); + ev.value = val; + } + ei.values.push_back(std::move(ev)); + ++i; + } + + DEBUG_LOG(m_logger) << "Found Enum: " << ei.type; + for (const EnumValue &ev : qAsConst(ei.values)) + DEBUG_LOG(m_logger) << "Member[" << i << "]: " << ev.key << " = " << ev.value; + + if (ei.type == QLatin1String("TelegramId")) + m_telegramIdEnum = ei; + + m_enums.push_back(std::move(ei)); + + return i; +} + +int LogViewTetraTelegramsParser::parseConstraint(const QVector &lines, int iStartPos) +{ + const QVector tokens = tokenize(lines.at(iStartPos)); + if (tokens.size() != 4) + { + WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'"; + return -1; + } + const QStringRef &cs = tokens.at(3); + if (!cs.startsWith(QLatin1String("Constraints<")) || !cs.endsWith(QLatin1Char('>'))) + { + WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'"; + return -1; + } + QStringRef structName = cs.mid(QLatin1String("Constraints<").size()); + structName.chop(1); + DEBUG_LOG(m_logger) << "Constraint: " << structName.toString(); + + int i = iStartPos + 1; + while (i < lines.size()) + { + const QVector tokens = tokenize(lines.at(i)); + if (tokens.isEmpty() || + (tokens.at(0) == QLatin1String("{"))) + { + ++i; + continue; + } + if (tokens.at(0) == QLatin1String("};")) + break; + if (tokens.size() != 8 || tokens.at(2) != QLatin1String("TelegramId")) + { + ++i; + continue; + } + const QVector parts = tokens.at(6).split(QLatin1String("::")); + if (parts.size() != 2) + { + WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(i).toString() << "'"; + return -1; + } + + QStringRef enumKey = parts.at(1); + if (enumKey.endsWith(QLatin1Char(';'))) + enumKey.chop(1); + bool bFound = false; + for (const auto &v : qAsConst(m_telegramIdEnum.values)) + { + if (v.key == enumKey) + { + m_visibleTelegrams.insert(v.value, structName.toString()); + bFound = true; + break; + } + } + if (!bFound) + { + WARNING_LOG(m_logger) << "Could not find enum value '" << enumKey.toString() << "' in enum TelegramId"; + return -1; + } + ++i; + } + + return i; +} + +QString LogViewTetraTelegramsParser::getInnerType(const QString &type) +{ + int idxLt = type.lastIndexOf(QLatin1Char('>')); + if (idxLt < 0) + return QString(); + int idxGt = type.indexOf(QLatin1Char('<')); + if (idxGt < 0) + return QString(); + return type.mid(idxGt + 1, idxLt - idxGt - 1); +} + +void LogViewTetraTelegramsParser::categorizeMember(MemberInformation &mi) const +{ + mi.isPod = isPod(mi.type); + mi.isEnum = mi.isPod ? false : isEnum(mi.type); + if (mi.type.startsWith(QLatin1String("std::vector<"))) + mi.isArray = true; + mi.isStruct = mi.isArray ? false : isStruct(mi.type); + mi.isString = (mi.type == QLatin1String("std::string") || mi.type == QLatin1String("QString")); + mi.isBinary = (mi.type == QLatin1String("std::vector") || mi.type == QLatin1String("QByteArray")); +} + +static inline void bracketCount(const QStringRef &str, int &cntLt, int &cntGt) +{ + cntLt = 0; + cntGt = 0; + for (int i = 0; i < str.size(); ++i) + { + if (str.at(i) == QLatin1Char('<')) + cntLt++; + else if (str.at(i) == QLatin1Char('>')) + cntGt++; + } +} + +QVector LogViewTetraTelegramsParser::tokenize(const QStringRef &line) const +{ + QVector ret = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + int i = 0; + while (i < ret.size()) + { + const QStringRef &token = ret.at(i); + if (token.startsWith(QLatin1String("//"))) + { + + if (i == ret.size() - 1) + break; + const QStringRef &lastToken = ret.last(); + const QStringRef newToken = QStringRef(token.string(), token.position(), lastToken.position() - token.position() + lastToken.size()); + DEBUG_LOG(m_logger) << "New Token: " << newToken.toString(); + ret.resize(i + 1); + ret[i] = newToken; + break; + } + if (i == ret.size() - 1) + break; + int cntLt; + int cntGt; + bracketCount(token, cntLt, cntGt); + if (cntLt == cntGt) + { + ++i; + continue; + } + const QStringRef &nextToken = ret.at(i + 1); + const QStringRef newToken = QStringRef(token.string(), token.position(), nextToken.position() - token.position() + nextToken.size()); + DEBUG_LOG(m_logger) << "New Token: " << newToken.toString(); + ret.removeAt(i + 1); + ret[i] = newToken; + } + + return ret; +} + +bool LogViewTetraTelegramsParser::validStructTokens(const QVector &tokens) +{ + if (tokens.isEmpty() || + (tokens.at(0) == QLatin1String("{")) || + (tokens.at(0) == QLatin1String("{}")) || + (tokens.at(0) == QLatin1String("}")) || + (tokens.at(0) == QLatin1String(":")) || + (tokens.at(0) == QLatin1String(",")) || + (tokens.at(0) == QLatin1String("virtual"))) + return false; + + if (tokens.at(0) == QLatin1String("};") || tokens.at(0) == QLatin1String("enum")) + return true; + + const int len = tokens.last().startsWith(QLatin1String("//")) ? tokens.size() - 1 : tokens.size(); + + if (len == 2) + return true; + + if (len < 4) + return false; + + if (len >= 4 && tokens.at(2) == QLatin1String("=")) + return true; + + return false; +} + +} diff --git a/TetraIF/LogView/LogViewTetraTelegramsParser.hpp b/TetraIF/LogView/LogViewTetraTelegramsParser.hpp new file mode 100644 index 000000000..13fa23703 --- /dev/null +++ b/TetraIF/LogView/LogViewTetraTelegramsParser.hpp @@ -0,0 +1,89 @@ + + + +#pragma once + +#include +#include +#include +#include "logger.h" + +namespace N_LogView +{ +struct MemberInformation +{ + QString name; + QString type; + bool isArray = false; + bool isBinary = false; + bool isEnum = false; + bool isPod = false; + bool isString = false; + bool isStruct = false; + bool isVisible = true; +}; + +struct StructInformation +{ + QString type; + QString baseStruct; + + QVector member; + bool isVisible = false; +}; + +struct EnumValue +{ + QString key; + int value = 0; +}; + +struct EnumInformation +{ + QString ns; + QString type; + QVector values; +}; + +struct PodInformation +{ + QString type; + int byteLen = 0; + bool isBoolean = false; + bool isIntegral = false; + bool isSigned = false; +}; + +class LogViewTetraTelegramsParser +{ +public: + LogViewTetraTelegramsParser(); + + bool parse(const QString &filename); + + EnumInformation enumFromType(const QString &type) const; + StructInformation structFromType(const QString &type) const; + PodInformation podFromType(const QString &type) const; + bool isEnum(const QString &type) const; + bool isStruct(const QString &type) const; + bool isPod(const QString &type) const; + QHash telegramsToCreate() const { return m_visibleTelegrams; } + QString nameFromTelegramId(int telId) const { return m_visibleTelegrams.value(telId); } + static QString getInnerType(const QString &type); +private: + void insertPod(const QString &type, int byteLen, bool isSigned, bool isIntegral, bool isBoolean = false); + int parseStruct(const QVector &lines, int iStartPos); + int parseEnum(const QVector &lines, int iStartPos, const QString &ns, StructInformation *si = nullptr); + int parseConstraint(const QVector &lines, int iStartPos); + void categorizeMember(MemberInformation &mi) const; + QVector tokenize(const QStringRef &line) const; + static bool validStructTokens(const QVector &tokens); +private: + EnumInformation m_telegramIdEnum; + QVector m_enums; + QHash m_structs; + QHash m_pods; + QHash m_visibleTelegrams; + NGL::INGLLogger &m_logger; +}; +} diff --git a/TetraIF/LogView/LogViewTextEdit.cpp b/TetraIF/LogView/LogViewTextEdit.cpp new file mode 100644 index 000000000..e21dedb07 --- /dev/null +++ b/TetraIF/LogView/LogViewTextEdit.cpp @@ -0,0 +1,96 @@ + + + + + + + + + + + + + +#include "LogViewTextEdit.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewTextEdit::LogViewTextEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QLineEdit(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) +{ + const QString value = a_field->value(0); + setText(value); + + if (a_readonly) + { + setReadOnly(true); + setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft); + } + + + uint16_t maxArraySize = a_field->maxArraySize(); + setMaxLength(maxArraySize); + updateToolTip(value); + + + QFontMetrics fm(font()); +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + setMinimumWidth(fm.width(QLatin1Char(' ') + value + QLatin1Char(' '))); +#else + setMinimumWidth(fm.horizontalAdvance(QLatin1Char(' ') + value + QLatin1Char(' '))); +#endif + + + connect(this, &LogViewTextEdit::editingFinished, + this, &LogViewTextEdit::checkAndOvertakeContent); +} + + + +void LogViewTextEdit::checkAndOvertakeContent() +{ + updateToolTip(text()); + m_Valid = true; +} + + + + + +bool LogViewTextEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (!isValid()) + return false; + if (a_telegram->isJsonTelegram()) + { + a_telegram->setJsonValue(m_Field->jsonPath(), text()); + } + else + { + uint16_t size = getSize(); + QString content = text(); + uint16_t arraySize; + if (m_Field->isDynamicArray()) + { + arraySize = content.length(); + a_telegram->setUIntX(LogViewTelegram::SIZE_CENTRAL_DYN_ARRAY_SIZE, arraySize); + + } + else + { + arraySize = m_Field->maxArraySize(); + } + + + for (int i = 0; i < arraySize; i++) + a_telegram->setUIntX(size, i < content.length() ? content[i].toLatin1() : 0); + } + return true; +} + +} diff --git a/TetraIF/LogView/LogViewTextEdit.hpp b/TetraIF/LogView/LogViewTextEdit.hpp new file mode 100644 index 000000000..def3ffd03 --- /dev/null +++ b/TetraIF/LogView/LogViewTextEdit.hpp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewTextEdit : public QLineEdit, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewTextEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + protected slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewValueEdit.cpp b/TetraIF/LogView/LogViewValueEdit.cpp new file mode 100644 index 000000000..117211ef7 --- /dev/null +++ b/TetraIF/LogView/LogViewValueEdit.cpp @@ -0,0 +1,135 @@ + + + + + + + + + + + + + +#include "LogViewValueEdit.hpp" +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" + +namespace N_LogView +{ + + +LogViewValueEdit::LogViewValueEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly) + : QLineEdit(a_parent) + , LogViewWidget(a_field, this, a_parent, a_readonly) + , m_IsFloat(false) +{ + const LogViewXdrStandardType *stdType = static_cast(m_Field->xdrElement()); + m_IsFloat = (LogViewXdrStandardType::e_Float == stdType->getValueKind()); + + const QString valueText = a_field->value(0); + + setText(valueText); + + + updateToolTip(valueText); + + + QFontMetrics fm(font()); +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + setMinimumWidth(fm.width(QLatin1Char(' ') + valueText + QLatin1Char(' '))); +#else + setMinimumWidth(fm.horizontalAdvance(QLatin1Char(' ') + valueText + QLatin1Char(' '))); +#endif + + if (a_readonly) + { + setReadOnly(true); + setAlignment(a_field->isRightAligned() ? Qt::AlignRight : Qt::AlignLeft); + } + else + { + connect(this, &LogViewValueEdit::editingFinished, + this, &LogViewValueEdit::checkAndOvertakeContent); + } +} + + + +void LogViewValueEdit::checkAndOvertakeContent() +{ + bool ok; + int64_t intValue = 0; + double floatValue = 0.0; + + + if (m_IsFloat) + floatValue = getFloat(text(), (uint64_t&)intValue, ok); + else + intValue = getInteger(text(), ok); + + + if (!ok) + { + setFocus(); + selectAll(); + return; + } + + + if (m_IsFloat) + setText(QString::number(floatValue)); + else + setText(QString::number(intValue)); + + updateToolTip(text()); +} + + + + + + +bool LogViewValueEdit::saveContent(LogViewTelegram* a_telegram) +{ + if (m_Valid) + { + bool ok; + if (m_IsFloat) + { + + uint64_t valueAsUint64; + const double value = getFloat(text(), valueAsUint64, ok); + if (ok) + { + if (a_telegram->isJsonTelegram()) + { + a_telegram->setJsonValue(m_Field->jsonPath(), value); + } + else + { + const LogViewXdrStandardType *stdType = static_cast(m_Field->xdrElement()); + LogViewXdrStandardType::E_ByteOrder byteOrder = stdType->getByteOrder(); + a_telegram->setUIntX(getSize(), valueAsUint64, byteOrder); + } + return true; + } + } + else + { + + qint64 intValue = getInteger(text(), ok); + if (ok) + { + if (a_telegram->isJsonTelegram()) + a_telegram->setJsonValue(m_Field->jsonPath(), intValue); + else + a_telegram->setUIntX(getSize(), intValue); + return true; + } + } + } + return false; +} + +} diff --git a/TetraIF/LogView/LogViewValueEdit.hpp b/TetraIF/LogView/LogViewValueEdit.hpp new file mode 100644 index 000000000..7fbd19792 --- /dev/null +++ b/TetraIF/LogView/LogViewValueEdit.hpp @@ -0,0 +1,44 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewWidget.hpp" +#include + +namespace N_LogView +{ + + + class LogViewValueEdit : public QLineEdit, public LogViewWidget + { + Q_OBJECT + public: + + + LogViewValueEdit(LogViewField* a_field, QWidget* a_parent, const bool a_readonly); + + + + bool saveContent(LogViewTelegram* a_telegram) override; + + protected: + + bool m_IsFloat; + + protected slots: + void checkAndOvertakeContent(); + + }; + +} diff --git a/TetraIF/LogView/LogViewWidget.cpp b/TetraIF/LogView/LogViewWidget.cpp new file mode 100644 index 000000000..6977ddb76 --- /dev/null +++ b/TetraIF/LogView/LogViewWidget.cpp @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + +#include "LogViewWidget.hpp" + +#include "LogViewField.hpp" +#include "LogViewTelegram.hpp" +#include "LogViewXdrStandardType.hpp" +#include "IntegerCalculator.hpp" +#include + +namespace N_LogView +{ + + +LogViewWidget::LogViewWidget(LogViewField* a_field, QWidget* a_widget, QWidget* a_parent, bool a_readonly) + : m_Readonly(a_readonly) + , m_Valid(true) + , m_Widget(a_widget) + , m_Field(a_field) + , m_Parent(a_parent) + , m_logger(getLogger("LogViewWidget")) +{ +} + + +uint16_t LogViewWidget::getSize() const +{ + + const LogViewXdrStandardType* xdrStandardType = static_cast(m_Field->xdrElement()); + return xdrStandardType->getValueSize(); +} + + +void LogViewWidget::showMessageBox(const QString &a_errorText) const +{ + QMessageBox::warning(m_Parent, QObject::tr("Fehler"), a_errorText); +} + + +void LogViewWidget::updateToolTip(const QString &a_text) +{ + bool isList = m_Field->valueListSize() > 1 || m_Field->isDynamicArray(); + switch (m_Field->xdrElement()->getKind()) + { + case LogViewXdrElement::e_KindStandardType: + switch (static_cast(m_Field->xdrElement())->getValueKind()) + { + case LogViewXdrStandardType::e_Character: + m_Widget->setToolTip(QObject::tr("%1 Zeichen").arg(a_text.length())); + if (!m_Readonly) + m_Widget->setToolTip(QObject::tr("%1
Maximal %2 Zeichen erlaubt").arg(m_Widget->toolTip()).arg(m_Field->maxArraySize())); + break; + case LogViewXdrStandardType::e_Data: + if (m_Readonly) + m_Widget->setToolTip(QObject::tr("%1 Bytes").arg(m_Field->valueListSize())); + break; + case LogViewXdrStandardType::e_Unsigned: + case LogViewXdrStandardType::e_Signed: + if (m_Readonly && isList) + { + m_Widget->setToolTip(QObject::tr("%1 Elemente").arg(m_Field->valueListSize())); + } + else + { + + if (m_Field->isDateTimeField()) + { + m_Widget->setToolTip(QObject::tr("Unixzeit: %1 ").arg(a_text)); + } + else + { + m_Widget->setToolTip(QString()); + } + + if (!isList) + { + int64_t value = a_text.toLong(); + m_Widget->setToolTip(QStringLiteral("%1%2 %3").arg(m_Widget->toolTip(), toHex(value), toBin(value))); + } + + if (!m_Field->isDateTimeField() && !m_Readonly) + { + const QString sep(isList ? QString() : QStringLiteral("
")); + m_Widget->setToolTip(QStringLiteral("%1%2Wertebereich: %3..%4").arg(m_Widget->toolTip(), sep).arg(m_Field->getLowestValue()).arg(m_Field->getHighestValue())); + } + } + break; + case LogViewXdrStandardType::e_Float: + if (4 == m_Field->size()) + m_Widget->setToolTip(QStringLiteral("Wertebereich: +/-3.4e+/-38")); + else + m_Widget->setToolTip(QStringLiteral("Wertebereich: +/-1.7e+/-308")); + break; + case LogViewXdrStandardType::e_Boolean: + m_Widget->setToolTip(QStringLiteral("true/false")); + + } + break; + case LogViewXdrElement::e_KindEnum: + { + uint64_t enumValue = a_text.toLong(); + m_Widget->setToolTip(QStringLiteral("%1 %2 %3").arg(enumValue).arg(toHex(enumValue), toBin(enumValue))); + break; + } + default: + ERROR_LOG(m_logger) << "Case not implemented"; + } +} + + + +double LogViewWidget::getFloat(const QString& a_text, uint64_t& a_FloatAsData, bool& a_ok, const bool a_reverse) +{ + + + + double value; + if (8 == getSize()) + { + value = a_text.toDouble(&a_ok); + a_FloatAsData = LogViewTelegram::doubleToXdr(value); + } else { + value = a_text.toFloat(&a_ok); + a_FloatAsData = LogViewTelegram::floatToXdr(value); + } + + + + if (!a_ok) + showMessageBox(QStringLiteral("Inalid real value: '%1'").arg(a_text)); + + m_Valid = a_ok; + + + if (a_reverse) + { + int j = getSize() - 1; + uint64_t* ptr = &a_FloatAsData; + for (int i = 0; i < getSize() / 2; i++) + { + uint8_t data = ((uint8_t*)ptr)[j]; + ((uint8_t*)&a_FloatAsData)[j] = ((uint8_t*)&a_FloatAsData)[i]; + ((uint8_t*)&a_FloatAsData)[i] = data; + j--; + } + } + + + if (4 == getSize()) + { + ((uint8_t*)&a_FloatAsData)[4] = 0; + ((uint8_t*)&a_FloatAsData)[5] = 0; + ((uint8_t*)&a_FloatAsData)[6] = 0; + ((uint8_t*)&a_FloatAsData)[7] = 0; + } + return value; +} + + + + + + + + + + +int64_t LogViewWidget::getInteger(const QString& a_text, bool& a_ok) +{ + + N_SST::IntegerCalculator calculator; + N_SST::IntegerCalculator::E_Error error; + int64_t value = calculator.calc(a_text.toStdString(), error); + m_Valid = false; + a_ok = true; + if (N_SST::IntegerCalculator::e_Ok != error) + { + + if (a_text != m_LastErrorValueText) + { + showMessageBox(QString::fromUtf8("Die Berechnung '%1' ist falsch").arg(a_text)); + m_LastErrorValueText = a_text; + } + a_ok = false; + } + else + { + + int64_t highest = m_Field->getHighestValue(); + if (value > highest) + { + a_ok = false; + + + if (a_text != m_LastErrorValueText) + { + showMessageBox(QString::fromUtf8("Der Wert '%1' ist zu hoch. Maximalwert: %2").arg(a_text).arg(highest)); + m_LastErrorValueText = a_text; + } + return value; + } + int64_t lowest = m_Field->getLowestValue(); + if (value < lowest) + { + a_ok = false; + if (a_text != m_LastErrorValueText) + { + showMessageBox(QString::fromUtf8("Der Wert '%1' ist zu tief. Minimalwert: %2").arg(a_text).arg(lowest)); + m_LastErrorValueText = a_text; + } + return value; + } + m_Valid = true; + } + return value; +} + +} diff --git a/TetraIF/LogView/LogViewWidget.hpp b/TetraIF/LogView/LogViewWidget.hpp new file mode 100644 index 000000000..57f6c2ddf --- /dev/null +++ b/TetraIF/LogView/LogViewWidget.hpp @@ -0,0 +1,84 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +class QWidget; +class QFont; + +namespace N_LogView +{ +template +inline QString toHex(T num) +{ + return QStringLiteral("0x%1").arg(num, 2, 16, QLatin1Char('0')); +} +template +inline QString toBin(T num) +{ + return QStringLiteral("0b%1").arg(num, 8, 2, QLatin1Char('0')); +} + +class LogViewField; +class LogViewTelegram; + + + +class LogViewWidget +{ +public: + LogViewWidget(LogViewField* a_field, QWidget* a_widget, QWidget* a_parent, bool a_readonly); + virtual ~LogViewWidget() = default; + + virtual uint16_t getSize() const; + LogViewField* field() const { return m_Field; } + bool isValid() const { return m_Valid; } + + + + QString getText() const { return m_Text; } + + + + virtual bool saveContent(LogViewTelegram* a_telegram) = 0; + +protected: + void showMessageBox(const QString &a_errorText) const; + void updateToolTip(const QString &a_text = QString()); + double getFloat(const QString& a_text, uint64_t& a_FloatAsData, bool& a_ok, const bool a_reverse = false); + + + + int64_t getInteger(const QString& a_text, bool& a_ok); + + +protected: + bool m_Readonly; + bool m_Valid; + + + QString m_Text; + QString m_LastErrorValueText; + QWidget *m_Widget; + + LogViewField *m_Field; + + QWidget *m_Parent; + NGL::INGLLogger &m_logger; + +}; + +} diff --git a/TetraIF/LogView/LogViewXdrElement.cpp b/TetraIF/LogView/LogViewXdrElement.cpp new file mode 100644 index 000000000..c2414c0fe --- /dev/null +++ b/TetraIF/LogView/LogViewXdrElement.cpp @@ -0,0 +1,61 @@ + + + + + + + + + + + + + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + + +LogViewXdrElement::LogViewXdrElement(const QString& a_name, const E_ElementKind a_kind, const char *loggerName) + : m_Name(a_name) + , m_Kind(a_kind) + , m_logger(getLogger(loggerName)) +{ + if (a_name.indexOf(QLatin1Char('<')) >= 0 || a_name.indexOf(QLatin1Char('[')) >= 0) + ERROR_LOG(m_logger) << "Element \'" << a_name.toStdString() << "\' has a problem"; +} + + +void LogViewXdrElement::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() << "]: kind=" << getKindName(); +} + + + +QString LogViewXdrElement::getKindName() const +{ + switch (getKind()) + { + case e_KindDefine: + return QLatin1String("Define"); + case e_KindEnum: + return QLatin1String("Enum"); + case e_KindEnumElement: + return QLatin1String("EnumElement"); + case e_KindStandardType: + return QLatin1String("StandardType"); + case e_KindStruct: + return QLatin1String("Struct"); + case e_KindStructElement: + return QLatin1String("StructElement"); + case e_KindTypedef: + return QLatin1String("Typedef"); + } + return QStringLiteral("Unknown (%1)").arg(getKind()); +} + +} diff --git a/TetraIF/LogView/LogViewXdrElement.hpp b/TetraIF/LogView/LogViewXdrElement.hpp new file mode 100644 index 000000000..4401be4e2 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrElement.hpp @@ -0,0 +1,62 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +namespace N_LogView +{ + + + class LogViewXdrElement + { + public: + + + + enum E_ElementKind + { + e_KindStandardType, + e_KindTypedef, + e_KindStruct, + e_KindStructElement, + e_KindEnum, + e_KindEnumElement, + e_KindDefine + }; + + virtual ~LogViewXdrElement() = default; + + protected: + + + LogViewXdrElement(const QString& a_name, const E_ElementKind a_kind, const char *loggerName); + + public: + const QString& getName() const { return m_Name; } + LogViewXdrElement::E_ElementKind getKind() const { return m_Kind; } + + virtual void dump() const; + + protected: + QString m_Name; + E_ElementKind m_Kind; + QString getKindName() const; + + NGL::INGLLogger &m_logger; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrParser.cpp b/TetraIF/LogView/LogViewXdrParser.cpp new file mode 100644 index 000000000..06b530817 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrParser.cpp @@ -0,0 +1,1016 @@ + + + + + + + + + + + + + + +#include "LogViewXdrParser.hpp" + + +#include "LogViewXdrElement.hpp" +#include +#include "LogViewXdrStruct.hpp" +#include "LogViewField.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewXdrType.hpp" + +#include +#include +#include + +namespace N_LogView +{ + +LogViewXdrParser::LogViewXdrParser() + : m_WithinComment(false) + , m_LineNbr(0) + , m_DoReadUntilSemicolon(false) + , m_WordListIndex(0) + , m_ActElement(nullptr) + , m_State(e_ParseMain) + , m_logger(getLogger("LogViewXdrParser")) +{} + +LogViewXdrParser::~LogViewXdrParser() +{ + for (const auto &elem : m_ElementMap) + delete elem.second; +} + + +void LogViewXdrParser::addStandardType(const QString& a_name, const uint16_t a_dataSize, const uint16_t a_realSize, const LogViewXdrStandardType::E_ValueKind a_kind, const LogViewXdrStandardType::E_DynArraySizeMethod a_dynArraySizeMethod, const LogViewXdrStandardType::E_ByteOrder a_byteOrder) +{ + QString name = a_name.trimmed(); + auto ptr = new LogViewXdrStandardType(name, a_dataSize, a_realSize, a_kind, a_dynArraySizeMethod, a_byteOrder); + if (!addToElementMap(name, ptr)) + delete ptr; + if ((a_dynArraySizeMethod == LogViewXdrStandardType::e_DynArrayIndex || a_dynArraySizeMethod == LogViewXdrStandardType::e_DynArrayIndexDiv8) + && a_kind != LogViewXdrStandardType::e_Unsigned) + showErrorMessage(QObject::tr("Standard-typ \'%1\': e_DynArrayIndex oder e_DynArrayIndexDiv darf nur mit e_Unsigned verwendet werden!")); +} + + + +void LogViewXdrParser::parseX_File(const QString& a_fileName) +{ + for (const auto &elem : m_ElementMap) + delete elem.second; + m_ElementMap.clear(); + m_DefinesMap.clear(); + m_TelegramMap.clear(); + m_LineNbr = 0; + m_WordListIndex = 0; + m_WithinComment = false; + m_ActElement = nullptr; + m_State = e_ParseMain; + + + addStandardType(QLatin1String("unsigned short"), 4, 2, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("unsigned int"), 4, 4, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("short"), 4, 2, LogViewXdrStandardType::e_Signed); + addStandardType(QLatin1String("int"), 4, 4, LogViewXdrStandardType::e_Signed); + addStandardType(QLatin1String("u_int"), 4, 4, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("char"), 4, 2, LogViewXdrStandardType::e_Character); + addStandardType(QLatin1String("unsigned char"), 4, 1, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("unsigned long"), 4, 4, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("u_long"), 4, 4, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("u_short"), 4, 2, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("float"), 4, 4, LogViewXdrStandardType::e_Float, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderBigEndian); + addStandardType(QLatin1String("double"), 8, 8, LogViewXdrStandardType::e_Float, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderBigEndian); + addStandardType(QLatin1String("opaque"), 1, 1, LogViewXdrStandardType::e_Data); + addStandardType(QLatin1String("string"), 1, 1, LogViewXdrStandardType::e_Character); + + + addStandardType(QLatin1String("alpha"), 1, 1, LogViewXdrStandardType::e_Character); + addStandardType(QLatin1String("UInt8"), 1, 1, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("UInt16"), 2, 2, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("UInt24"), 3, 3, LogViewXdrStandardType::e_Unsigned); + addStandardType(QLatin1String("SInt8"), 1, 1, LogViewXdrStandardType::e_Signed); + addStandardType(QLatin1String("SInt16"), 2, 2, LogViewXdrStandardType::e_Signed); + addStandardType(QLatin1String("SInt24"), 3, 3, LogViewXdrStandardType::e_Signed); + + addStandardType(QLatin1String("UInt16LE"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian); + addStandardType(QLatin1String("UInt32LE"), 4, 4, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian); + + addStandardType(QLatin1String("UInt8Idx"), 1, 1, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex); + addStandardType(QLatin1String("UInt16Idx"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex); + addStandardType(QLatin1String("UInt16LEIdx"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex, LogViewXdrStandardType::e_ByteOrderLittleEndian); + + addStandardType(QLatin1String("UInt8IdxDiv8"), 1, 1, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndexDiv8); + addStandardType(QLatin1String("UInt16IdxDiv8"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndexDiv8); + + const auto DEFINE_NAME = QLatin1String("%#define"); + + + m_Filename = a_fileName; + m_State = e_ParseMain; + QFile xFile(a_fileName); + if (xFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QString lastLines; + uint32_t lastLinesCount = 0; + QTextStream in(&xFile); + while (!in.atEnd()) + { + m_Line = lastLines + QLatin1Char(' ') + in.readLine(); + m_Line = m_Line.simplified(); + m_LineNbr++; + + + + if (m_Line.startsWith(QLatin1Char('%')) && !m_Line.startsWith(DEFINE_NAME)) + { + continue; + } + + + const QString cleanLine = removeComments(m_Line).simplified(); + + + if (cleanLine.isEmpty()) + { + continue; + } + + + + if (m_DoReadUntilSemicolon && !cleanLine.endsWith(QLatin1Char(';'))) + { + lastLines = cleanLine; + m_LineNbr--; + lastLinesCount++; + continue; + } + + lastLines.clear(); + + + if (e_ParseMain == m_State) + { + if (cleanLine.startsWith(QLatin1String("union "))) + { + m_State = e_ParseUnion; + } + else if (cleanLine.startsWith(QLatin1String("struct "))) + { + m_State = e_ParseStruct; + } + } + + + switch (m_State) + { + case e_ParseUnion: + parseUnion(cleanLine); + break; + case e_ParseStruct: + parseStruct(cleanLine); + break; + case e_ParseEnum: + parseEnum(cleanLine); + break; + default: + if (m_Line.startsWith(DEFINE_NAME)) + { + parseDefine(m_Line.mid(DEFINE_NAME.size())); + } + else if (cleanLine.startsWith(QLatin1String("typedef "))) + { + parseTypedef(cleanLine); + } + else if (cleanLine.startsWith(QLatin1String("enum "))) + { + parseEnum(cleanLine.mid(5)); + } + else if (cleanLine.startsWith(QLatin1String("enum8 "))) + { + parseEnum(cleanLine.mid(6), 1); + } + else if (cleanLine.startsWith(QLatin1String("enum16 "))) + { + parseEnum(cleanLine.mid(7), 2); + } + } + + if (lastLinesCount > 0) + { + m_LineNbr += lastLinesCount; + lastLinesCount = 0; + } + } + xFile.close(); + + m_LineNbr = 0; + m_Line.clear(); + } + else + { + QMessageBox::warning(nullptr, QLatin1String("Dateifehler"), QStringLiteral("Konnte die Datei %1 nicht öffnen").arg(a_fileName)); + } +} + + + +QString LogViewXdrParser::removeComments(const QString& a_line) +{ + static const QChar slash(QLatin1Char('/')); + static const QChar asterik(QLatin1Char('*')); + + QString cleanLine; cleanLine.reserve(a_line.size()); + QString::const_iterator iter = a_line.begin(); + QString::const_iterator end = a_line.end(); + while (iter != end) + { + if (!m_WithinComment) + { + + if (slash == *iter) + { + if (++iter != end) + { + if (asterik == *iter) + { + + m_WithinComment = true; + } + else + { + + cleanLine.append(slash); + cleanLine.append(*iter); + } + } + else + { + + cleanLine.append(slash); + } + } + else + { + + cleanLine.append(*iter); + } + } + else + { + + if (asterik == *iter) + { + if (++iter != end) + { + if (slash == *iter) + { + m_WithinComment = false; + } + } + } + } + if (iter != end) + ++iter; + } + return cleanLine; +} + + + +void LogViewXdrParser::parseTypedef(const QString &a_line) +{ + fillWordList(a_line); + + + + + if (isNextWord("typedef")) + { + + bool ok; + QString type = getNextType(ok); + + getElement(type); + + QString name = getNextWord("Name"); + if (name.isEmpty()) return; + if (!isNextWord(";")) return; + + uint16_t dynArrayOffset; + uint16_t arraySize = parseArray(name, dynArrayOffset); + LogViewXdrType* typedefElement = new LogViewXdrType(name, type, arraySize, dynArrayOffset, LogViewXdrElement::e_KindTypedef); + if (!addToElementMap(name, typedefElement)) + delete typedefElement; + } +} + + + +void LogViewXdrParser::parseDefine(const QString &a_line) +{ + const QString line = a_line.trimmed(); + int sepPos = line.indexOf(QLatin1Char(' ')); + if (sepPos >= 0) + { + const QString name = line.leftRef(sepPos).trimmed().toString(); + QStringRef substitution = line.midRef(sepPos).trimmed(); + sepPos = substitution.indexOf(QLatin1Char(' ')); + if (sepPos >= 0) + substitution = substitution.left(sepPos).trimmed(); + + + bool ok = false; + const int64_t value = calcValue(substitution.toString(), ok); + if (ok) + { + + m_DefinesMap.insert(std::make_pair(name, LogViewXdrValue(name, value, LogViewXdrElement::e_KindDefine))); + } + } + else + { + showErrorMessage(QObject::tr("Space zwischen define-name und substitution nicht gefunden")); + } +} + + + +void LogViewXdrParser::parseEnum(const QString &a_line, const uint16_t a_enumSize) +{ + if (QLatin1String("};") != a_line) + { + switch(m_State) + { + default: + + + if (a_line.endsWith(QLatin1String(" {"))) + { + m_State = e_ParseEnum; + const QString name = a_line.leftRef(a_line.length()-2).trimmed().toString(); + m_ActElement = new LogViewXdrStruct(name, LogViewXdrElement::e_KindEnum, a_enumSize); + if (!addToElementMap(name, m_ActElement)) + { + delete m_ActElement; + m_ActElement = nullptr; + return; + } + } + else + { + showErrorMessage(QObject::tr("Endet nicht mit {")); + } + break; + + case e_ParseEnum: + { + + + QString name; + QString valueText; + if (parseEnumLine(a_line, name, valueText)) + { + + bool error = true; + uint32_t enumValue = m_ActElement->getChildValue(valueText, &error); + if (!error) + { + valueText = QString::number(enumValue); + } + + bool ok; + int64_t value = calcValue(valueText, ok); + if (ok) + m_ActElement->addElement(name, value, LogViewXdrElement::e_KindEnumElement); + else + ERROR_LOG(m_logger) << "Problem with converting text to number: name=" << name.toStdString() << " valueText=" << valueText.toStdString(); + } + } + break; + } + } + else + { + + m_State = e_ParseMain; + + + } +} + + + +void LogViewXdrParser::parseStruct(const QString &a_line) +{ + fillWordList(a_line); + if (!m_DoReadUntilSemicolon) + { + + + + if (isNextWord("struct")) + { + + QString structName = getNextWord("Struktur-Name"); + if (structName.isEmpty()) return; + if (!isNextWord("{")) return; + + m_ActElement = new LogViewXdrStruct(structName, LogViewXdrElement::e_KindStruct); + if (!addToElementMap(structName, m_ActElement)) + { + delete m_ActElement; + m_ActElement = nullptr; + return; + } + m_State = e_ParseStruct; + m_DoReadUntilSemicolon = true; + } + } + else + { + if (!isNextWord("}", false)) + { + + + + bool ok; + QString type = getNextType(ok); + if (!ok) return; + + if (m_UnionType != type) getElement(type); + + int16_t firstBit = -1; + int16_t lastBit = -1; + bool isLast = true; + if (isNextWord(":", false)) + { + isNextWord(":"); + QString bitfield = getNextWord("Bitfield"); + isLast = parseBitfield(bitfield, firstBit, lastBit); + } + + QString name = getNextWord("Name"); + if (name.isEmpty()) return; + if (!isNextWord(";")) return; + + uint16_t dynArrayOffset; + uint16_t arraySize = parseArray(name, dynArrayOffset); + if(firstBit >= 0) + DEBUG_LOG(m_logger) << "Add Element " << name + << " with type " << type + << " array size: " << arraySize + << " first:last " << firstBit << ":" << lastBit + << " isLast: " << isLast; + m_ActElement->addElement(name, type, arraySize, dynArrayOffset, LogViewXdrElement::e_KindStructElement, firstBit, lastBit, isLast); + } + else + { + + if (!isNextWord("}")) return; + if (!isNextWord(";")) return; + m_State = e_ParseMain; + m_DoReadUntilSemicolon = false; + + + + + + } + } +} + + + +void LogViewXdrParser::parseUnion(const QString& a_line) +{ + + + static const LogViewXdrStruct* telegramIdType = nullptr; + + fillWordList(a_line); + if (!m_DoReadUntilSemicolon) + { + + + + if (isNextWord("union")) + { + + m_UnionType = getNextWord("Union-Typ"); + if (m_UnionType.isEmpty()) return; + + if (!isNextWord("switch")) return; + if (!isNextWord("(")) return; + + getNextEnum(telegramIdType); + if (telegramIdType == nullptr) return; + + QString name = getNextWord("Parameter-Name"); + if (name.isEmpty()) return; + if (!isNextWord(")")) return; + if (!isNextWord("{")) return; + + m_State = e_ParseUnion; + m_DoReadUntilSemicolon = true; + } + } + else + { + if (!isNextWord("}", false)) + { + QString keyword = getNextWord(); + if (keyword == QLatin1String("case")) + { + + + QStringList constExprList; + QString type; + do + { + + QString constExpression = getNextWord("Konstanten-Ausdruck"); + if (constExpression.isEmpty()) return; + constExprList << constExpression; + + if (!isNextWord(":")) return; + + type = getNextWord("Typ"); + if (type.isEmpty()) return; + } + while (type == QLatin1String("case")); + + getElement(type); + + QString name = getNextWord("Name"); + if (name.isEmpty()) return; + + if (!isNextWord(";")) return; + + for (const QString &constExpr : qAsConst(constExprList)) + { + bool error; + int32_t telegramId = static_cast(telegramIdType->getChildValue(constExpr, &error)); + if (!error) + { + m_TelegramMap.insert(std::make_pair(telegramId, LogViewXdrType(constExpr, type, 1, 0, LogViewXdrElement::e_KindEnumElement))); + } + else + { + showErrorMessage(QObject::tr("\'%1\' ist nicht definiert in \'%2\'").arg(constExpr, telegramIdType->getName())); + } + } + } + else if (keyword == QLatin1String("default")) + { + + if (isNextWord(":")) + { + QString defaultDefinition = getNextWord(); + if (defaultDefinition == QLatin1String("void")) + { + isNextWord(";"); + + } + else + { + showErrorMessage(QObject::tr("default: muss void; enthalten. Falls nicht, muss das richtige Verhalten implementiert werden...")); + } + } + } + else + { + showErrorMessage(QObject::tr("Erwarte Keyword case oder default statt \'%1\'").arg(keyword)); + } + } + else + { + + if (!isNextWord("}")) return; + if (!isNextWord(";")) return; + m_State = e_ParseMain; + m_DoReadUntilSemicolon = false; + + } + } +} + + + +bool LogViewXdrParser::parseEnumLine(const QString& a_line, QString& a_name, QString& a_value) const +{ + QString line; + if (a_line.endsWith(QLatin1Char(','))) + { + line = a_line.left(a_line.length()-1); + } + else + { + line = a_line; + } + line = line.trimmed(); + + int sepPos = line.lastIndexOf(QLatin1Char('=')); + if (-1 != sepPos) + { + a_name = line.leftRef(sepPos).trimmed().toString(); + a_value = line.midRef(sepPos+1).trimmed().toString(); + return true; + } + else + { + showErrorMessage(QObject::tr("konnte Trennzeichen \'=\' zwischen Name und Wert nicht finden!")); + } + return false; +} + + + + + + +void LogViewXdrParser::showErrorMessage(const QString& a_errorText) const +{ + const auto tlws = QApplication::topLevelWidgets(); + QMessageBox::warning(tlws.size() ? tlws.first() : nullptr, + QObject::tr("Telegram Structure Parser"), + QStringLiteral("%4:%1:
%2


%3").arg(m_LineNbr).arg(m_Line, a_errorText, m_Filename)); +} + + + +int64_t LogViewXdrParser::calcValue(const QString& a_calcText, bool& a_isOk) +{ + + a_isOk = false; + int64_t value = 0; + if (!a_calcText.startsWith(QLatin1Char('\"'))) + { + N_SST::IntegerCalculator::E_Error error; + std::string errorText; + value = calc(a_calcText.toStdString(), error, &errorText); + + + if (error != N_SST::IntegerCalculator::e_Ok) + { + switch (error) + { + case N_SST::IntegerCalculator::e_DivisionByZero: + showErrorMessage(QObject::tr("Division durch 0 nicht erlaubt!")); + break; + case N_SST::IntegerCalculator::e_InvalidOperand: + showErrorMessage(QObject::tr("Operand %1 ist fehlerhaft!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_MissingLeftParanthesis: + showErrorMessage(QObject::tr("Es fehlen Klammer Öffnungen (!")); + break; + case N_SST::IntegerCalculator::e_MissingRightParanthesis: + showErrorMessage(QObject::tr("Es fehlen Klammer Schliessungen )!")); + break; + case N_SST::IntegerCalculator::e_NoOperandBetweenOperators: + showErrorMessage(QObject::tr("Zwei Operationen (%1) nacheinander sind nicht erlaubt!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_UnknownOperationOrVariable: + showErrorMessage(QObject::tr("Operation oder Variable %1 unbekannt!").arg(QString::fromStdString(errorText))); + break; + case N_SST::IntegerCalculator::e_UnknownError: + showErrorMessage(QObject::tr("Unbekannter Fehler!")); + break; + default: + break; + } + ERROR_LOG(m_logger) << "Problem with converting '" << a_calcText << "' to integer"; + } + else + { + a_isOk = true; + } + } + return value; +} + + + +bool LogViewXdrParser::getVariableValue(const std::string& a_variableName, int64_t& a_value) const +{ + return getDefine(QString::fromStdString(a_variableName), a_value); +} + + + + + + + + + + +QString LogViewXdrParser::getTelegramName(int a_telegramId) const +{ + const auto iter = m_TelegramMap.find(a_telegramId); + if (m_TelegramMap.end() != iter) + return iter->second.getName(); + + return QObject::tr("").arg(a_telegramId); +} + + +QString LogViewXdrParser::getStructName(int a_telegramId) const +{ + const auto iter = m_TelegramMap.find(a_telegramId); + if (m_TelegramMap.end() != iter) + return iter->second.getType(); + + return QObject::tr("").arg(a_telegramId); +} + + +bool LogViewXdrParser::getDefine(const QString& a_name, int64_t& a_value) const +{ + const auto iter = m_DefinesMap.find(a_name); + if (iter != m_DefinesMap.end()) + { + a_value = iter->second.getValue(); + return true; + } + return false; +} + + + +const LogViewXdrElement* LogViewXdrParser::getElement(const QString& a_name) const +{ + const auto iter = m_ElementMap.find(a_name); + if (iter != m_ElementMap.end()) + return iter->second; + + showErrorMessage(QObject::tr("Typ \'%1\' nicht definiert!").arg(a_name)); + return nullptr; +} + + + +uint16_t LogViewXdrParser::parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const +{ + a_dynArrayMsgOffset = 0; + QString oldName = a_name; + + + + int pos = a_name.indexOf(QLatin1Char('[')); + if (pos >= 0) + { + int endPos = a_name.indexOf(QLatin1Char(']')); + if (endPos > pos) + { + + QString arraySizeText = a_name.mid(pos+1, endPos-pos-1); + + a_name = a_name.left(pos); + + int64_t arraySizeValue = 1; + + if (!getDefine(arraySizeText, arraySizeValue)) + { + bool ok = false; + arraySizeValue = arraySizeText.toInt(&ok); + if (!ok) + { + showErrorMessage(QObject::tr("%1: [%2] is not a number").arg(oldName, arraySizeText)); + } + } + + return arraySizeValue; + } + else + { + showErrorMessage(QObject::tr("%1: Did not found expected ']'").arg(oldName)); + } + } + else + { + + + + + pos = a_name.indexOf(QLatin1Char('<')); + if (pos >= 0) + { + int endPos = a_name.indexOf(QLatin1Char('>')); + if (endPos > pos) + { + + QString arraySizeText = a_name.mid(pos+1, endPos-pos-1); + + + a_name = a_name.left(pos); + + + int64_t arraySizeValue = 1; + if (!getDefine(arraySizeText, arraySizeValue)) + { + bool ok = false; + arraySizeValue = arraySizeText.toInt(&ok); + if (!ok) + { + showErrorMessage(QObject::tr("%1: \'%2\' is not a number").arg(a_name, arraySizeText)); + } + else + { + + } + } + a_dynArrayMsgOffset = arraySizeValue; + + return 0; + } + else + { + showErrorMessage(QObject::tr("%1: Did not found expected '>'").arg(a_name)); + } + } + } + return 1; +} + + + +bool LogViewXdrParser::isNextWord(const char *a_word, const bool a_doIncrement) +{ + const QString word = QString::fromUtf8(a_word); + bool ok = (m_WordListIndex < m_WordList.size() && + m_WordList.at(m_WordListIndex) == word); + + + if (!ok && a_doIncrement) + { + if (m_WordListIndex > 0) + showErrorMessage(QObject::tr("Erwarte %1 nach \'%2\'!").arg(word, m_WordList.at(m_WordListIndex-1))); + else + showErrorMessage(QObject::tr("Erwarte %1!").arg(word)); + } + + if (a_doIncrement) + m_WordListIndex++; + return ok; +} + + + +void LogViewXdrParser::fillWordList(const QString& a_line) +{ + QString line = a_line; + line.replace(QLatin1Char('('), QLatin1String(" ( ")); + line.replace(QLatin1Char(')'), QLatin1String(" ) ")); + line.replace(QLatin1Char('{'), QLatin1String(" { ")); + line.replace(QLatin1Char('}'), QLatin1String(" } ")); + line.replace(QLatin1Char(':'), QLatin1String(" : ")); + line.replace(QLatin1Char(';'), QLatin1String(" ; ")); + m_WordList = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + m_WordListIndex = 0; + + + + + +} + + + +QString LogViewXdrParser::getNextWord(const char *a_errorText) +{ + QString word; + if (m_WordListIndex < m_WordList.size()) + word = m_WordList.at(m_WordListIndex); + + if (word.isEmpty() && a_errorText) + { + const QString errTxt(QString::fromUtf8(a_errorText)); + if (m_WordListIndex > 0) + showErrorMessage(QObject::tr("Erwarte %1 nach \'%2\'!").arg(errTxt, m_WordList.at(m_WordListIndex-1))); + else + showErrorMessage(QObject::tr("Erwarte %1!").arg(errTxt)); + } + m_WordListIndex++; + return word; +} + + + +QString LogViewXdrParser::getNextType(bool& a_ok) +{ + a_ok = true; + QString type = getNextWord("Typ"); + if (type.isEmpty()) a_ok = false; + if (type == QLatin1String("unsigned") || + type == QLatin1String("signed")) + { + QString type2 = getNextWord("Typ"); + if (type2.isEmpty()) a_ok = false; + type = QStringLiteral("%1 %2").arg(type, type2); + } + return type; +} + + + +QString LogViewXdrParser::getNextEnum(const LogViewXdrStruct*& a_enumStruct) +{ + QString type; + a_enumStruct = nullptr; + if (m_WordListIndex < m_WordList.size()) + { + type = m_WordList.at(m_WordListIndex); + a_enumStruct = static_cast(getElement(type)); + if (a_enumStruct) + { + if (LogViewXdrElement::e_KindEnum != a_enumStruct->getKind()) + { + showErrorMessage(QObject::tr("Typ \'%1\' muss ein Enum sein!").arg(type)); + a_enumStruct = nullptr; + } + } + else + showErrorMessage(QObject::tr("Enum \'%1\' nicht definiert!").arg(type)); + m_WordListIndex++; + } + return type; +} + + + +bool LogViewXdrParser::parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const +{ + + + a_firstBit = -1; + a_lastBit = -1; + bool isLast = true; + + int doublePointPos = a_fieldText.indexOf(QLatin1String("..")); + if (doublePointPos != -1) + { + QString bitText = a_fieldText.left(doublePointPos); + bool ok; + a_firstBit = bitText.toInt(&ok); + if (ok) + { + + bitText = a_fieldText.mid(doublePointPos+2); + + if (bitText.endsWith(QLatin1Char('!'))) + { + isLast = true; + bitText.chop(1); + } + else + { + isLast = false; + } + a_lastBit = bitText.toInt(&ok); + if (ok) + { + + + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Zweites Bit (%1) ist keine Zahl!").arg(bitText)); + } + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Erstes Bit (%1) ist keine Zahl!").arg(bitText)); + } + } + else + { + showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Habe .. nicht gefunden!")); + } + return isLast; +} + + + + + + + + +bool LogViewXdrParser::addToElementMap(const QString& a_name, LogViewXdrElement* a_element) +{ + if (m_ElementMap.find(a_name) == m_ElementMap.end()) + { + m_ElementMap.insert(std::make_pair(a_name, a_element)); + return true; + } + showErrorMessage(QObject::tr("Der Typ '%1' wurde bereits frueher definiert => Bitte ein einem Ort entfernen!").arg(a_name)); + return false; +} + +} + diff --git a/TetraIF/LogView/LogViewXdrParser.hpp b/TetraIF/LogView/LogViewXdrParser.hpp new file mode 100644 index 000000000..9f2472057 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrParser.hpp @@ -0,0 +1,183 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include + +#include "IntegerCalculator.hpp" +#include "logger.h" +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + class LogViewXdrElement; + class LogViewXdrStruct; + class LogViewField; + class LogViewXdrValue; + class LogViewXdrType; + + + + class LogViewXdrParser : public N_SST::IntegerCalculator + { + public: + + + + enum E_ParseState + { + e_ParseMain, + e_ParseStruct, + e_ParseEnum, + e_ParseUnion + }; + + + LogViewXdrParser(); + ~LogViewXdrParser(); + + + + + void parseX_File(const QString& a_fileName); + + + + QString getTelegramName(int a_telegramId) const; + + + + QString getStructName(int a_telegramId) const; + + + + bool getDefine(const QString& a_name, int64_t& a_value) const; + + + + const LogViewXdrElement* getElement(const QString& a_name) const; + + protected: + + QString m_MessageBoxTitle; + bool m_WithinComment; + QString m_Line; + uint32_t m_LineNbr; + QString m_Filename; + bool m_DoReadUntilSemicolon; + QStringList m_WordList; + int m_WordListIndex; + + + QString m_UnionType; + std::map m_ElementMap; + + LogViewXdrStruct *m_ActElement; + + E_ParseState m_State; + + std::map m_DefinesMap; + + std::map m_TelegramMap; + + + + void addStandardType(const QString& a_name, + const uint16_t a_dataSize, + const uint16_t a_realSize, + const LogViewXdrStandardType::E_ValueKind a_kind, + const LogViewXdrStandardType::E_DynArraySizeMethod a_dynArraySizeMethod = LogViewXdrStandardType::e_DynArrayMsgLength, + const LogViewXdrStandardType::E_ByteOrder a_byteOrder = LogViewXdrStandardType::e_ByteOrderBigEndian); + + + + QString removeComments(const QString& a_line); + + + + void parseTypedef(const QString &a_line); + + + + void parseDefine(const QString &a_line); + + + + void parseEnum(const QString &a_line, const uint16_t a_enumSize = 4); + + + + void parseStruct(const QString &a_line); + + + + void parseUnion(const QString& a_line); + + + + bool parseEnumLine(const QString& a_line, QString& a_name, QString& a_value) const; + + + + void showErrorMessage(const QString& a_errorText) const; + + + + int64_t calcValue(const QString& a_calcText, bool& a_isOk); + + + + bool getVariableValue(const std::string& a_variableName, int64_t& a_value) const override; + + + + uint16_t parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const; + + + + bool isNextWord(const char *a_word, const bool a_doIncrement = true); + + + + void fillWordList(const QString& a_line); + + + + QString getNextWord(const char *a_errorText = nullptr); + + + + QString getNextType(bool& a_ok); + + + + QString getNextEnum(const LogViewXdrStruct*& a_enumStruct); + + + + bool parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const; + + + + bool addToElementMap(const QString& a_name, LogViewXdrElement* a_element); + + private: + + + NGL::INGLLogger &m_logger; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrStandardType.cpp b/TetraIF/LogView/LogViewXdrStandardType.cpp new file mode 100644 index 000000000..b5dd4bb3f --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStandardType.cpp @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + +#include "LogViewXdrStandardType.hpp" + +namespace N_LogView +{ + + + + + +LogViewXdrStandardType::LogViewXdrStandardType(const QString& a_name, const int a_valueSize, + const int a_editSize, const E_ValueKind a_valueKind, + const E_DynArraySizeMethod a_dynArraySizeMethod, E_ByteOrder a_byteOrder) + : LogViewXdrElement(a_name, e_KindStandardType, "LogViewXdrStandardType") + , m_ValueSize(a_valueSize) + , m_EditSize(a_editSize) + , m_ValueKind(a_valueKind) + , m_ByteOrder(a_byteOrder) + , m_DynArraySizeMethod(a_dynArraySizeMethod) +{} + + + +uint16_t LogViewXdrStandardType::getValueSize() const +{ + return m_ValueSize; +} + + +LogViewXdrStandardType::E_ValueKind LogViewXdrStandardType::getValueKind() const +{ + return m_ValueKind; +} + + + +void LogViewXdrStandardType::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() + << "]: kind=" << getKindName() + << " valueKind=" << getValueKind() + << " valueSize=" << getValueSize() + << " editSize=" << getEditSize() + << " dynArrSizeMethod=" << getDynArraySizeMethod() + << " byteOrder=" << getByteOrder(); +} + + +LogViewXdrStandardType::E_DynArraySizeMethod LogViewXdrStandardType::getDynArraySizeMethod() const +{ + return m_DynArraySizeMethod; +} + + + +LogViewXdrStandardType::E_ByteOrder LogViewXdrStandardType::getByteOrder() const +{ + return m_ByteOrder; +} + + + + + + +uint16_t LogViewXdrStandardType::getEditSize() const +{ + return m_EditSize; +} + +} diff --git a/TetraIF/LogView/LogViewXdrStandardType.hpp b/TetraIF/LogView/LogViewXdrStandardType.hpp new file mode 100644 index 000000000..29a75ffa5 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStandardType.hpp @@ -0,0 +1,117 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrStandardType final : public LogViewXdrElement + { + public: + + + + enum E_ValueKind + { + + + e_Unsigned, + + + e_Signed, + + + e_Float, + + + e_Character, + + + e_Boolean, + + + e_Data + }; + + + + enum E_ByteOrder + { + e_ByteOrderBigEndian, + e_ByteOrderLittleEndian + }; + + + + enum E_DynArraySizeMethod + { + + + e_DynArrayMsgLength, + + + e_DynArrayIndex, + + + e_DynArrayIndexDiv8 + }; + + + + LogViewXdrStandardType(const QString &a_name, + const int a_valueSize, + const int a_editSize, + const E_ValueKind a_valueKind, + const E_DynArraySizeMethod a_dynArraySizeMethod, + E_ByteOrder a_byteOrder); + + + uint16_t getValueSize() const; + + + LogViewXdrStandardType::E_ValueKind getValueKind() const; + + + void dump() const override; + + + LogViewXdrStandardType::E_DynArraySizeMethod getDynArraySizeMethod() const; + + + LogViewXdrStandardType::E_ByteOrder getByteOrder() const; + + + + uint16_t getEditSize() const; + + protected: + + + + int m_ValueSize; + + + int m_EditSize; + E_ValueKind m_ValueKind; + + E_ByteOrder m_ByteOrder; + + E_DynArraySizeMethod m_DynArraySizeMethod; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrStruct.cpp b/TetraIF/LogView/LogViewXdrStruct.cpp new file mode 100644 index 000000000..b497f4222 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStruct.cpp @@ -0,0 +1,105 @@ + + + + + + + + + + + + + +#include "LogViewXdrStruct.hpp" +#include "LogViewXdrValue.hpp" +#include "LogViewXdrType.hpp" + +namespace N_LogView +{ + + +LogViewXdrStruct::LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrStruct") + , m_EnumSize(enumSize) +{ +} + +LogViewXdrStruct::~LogViewXdrStruct() +{ + for (auto ptr : m_ChildList) + delete ptr; +} + + + +void LogViewXdrStruct::addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast) +{ + m_ChildList.push_back(new LogViewXdrType(a_name, a_type, a_arraySize, a_dynArrayOffset, a_kind, a_firstBit, a_lastBit, a_isLast)); +} + + +void LogViewXdrStruct::addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind) +{ + m_ChildList.push_back(new LogViewXdrValue(a_name, a_value, a_kind)); +} + + + +LogViewXdrElement* LogViewXdrStruct::getChild(const uint32_t a_childIndex) const +{ + if (m_ChildList.size() > a_childIndex) + return m_ChildList[a_childIndex]; + + return nullptr; +} + + + +LogViewXdrType* LogViewXdrStruct::getChildAsType(const uint32_t a_childIndex) const +{ + return static_cast(getChild(a_childIndex)); +} + + + +LogViewXdrValue* LogViewXdrStruct::getChildAsValue(const uint32_t a_childIndex) const +{ + return static_cast(getChild(a_childIndex)); +} + + + +void LogViewXdrStruct::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName().toStdString() << "]: kind=" << getKindName().toStdString() << " enumSize=" << getEnumSize(); + INFO_LOG(m_logger) << "-------------- childs start -----------------"; + + std::vector::const_iterator iter = m_ChildList.begin(); + while (iter != m_ChildList.end()) + { + (*iter)->dump(); + ++iter; + } + INFO_LOG(m_logger) << "-------------- childs end -----------------"; +} + + +uint32_t LogViewXdrStruct::getChildValue(const QString& a_name, bool* a_error) const +{ + if (a_error) + *a_error = false; + std::vector::const_iterator iter = m_ChildList.begin(); + while (iter != m_ChildList.end()) + { + if ((*iter)->getName() == a_name) + return static_cast(*iter)->getValue(); + ++iter; + } + if (a_error) + *a_error = true; + return 0; +} + +} + diff --git a/TetraIF/LogView/LogViewXdrStruct.hpp b/TetraIF/LogView/LogViewXdrStruct.hpp new file mode 100644 index 000000000..8faa4ed14 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrStruct.hpp @@ -0,0 +1,60 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "LogViewXdrElement.hpp" +#include + + +namespace N_LogView +{ + class LogViewXdrValue; +} +namespace N_LogView +{ + class LogViewXdrType; +} + +namespace N_LogView +{ + + + class LogViewXdrStruct final : public LogViewXdrElement + { + public: + LogViewXdrStruct(const QString& a_name, const LogViewXdrElement::E_ElementKind a_kind, uint16_t enumSize = 0); + ~LogViewXdrStruct(); + + void addElement(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit = -1, const int16_t a_lastBit = -1, const bool a_isLast = true); + void addElement(const QString& a_name, const uint32_t a_value, const E_ElementKind a_kind); + + LogViewXdrElement* getChild(const uint32_t a_childIndex) const; + LogViewXdrType* getChildAsType(const uint32_t a_childIndex) const; + LogViewXdrValue* getChildAsValue(const uint32_t a_childIndex) const; + + + void dump() const override; + + uint32_t getChildValue(const QString& a_name, bool* a_error = nullptr) const; + uint16_t getEnumSize() const { return m_EnumSize; } + + protected: + + uint16_t m_EnumSize; + std::vector m_ChildList; + + }; + +} diff --git a/TetraIF/LogView/LogViewXdrType.cpp b/TetraIF/LogView/LogViewXdrType.cpp new file mode 100644 index 000000000..c4a4b05c5 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrType.cpp @@ -0,0 +1,106 @@ + + + + + + + + + + + + + +#include "LogViewXdrType.hpp" + +namespace N_LogView +{ + + +LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrElement") + , m_Type(a_type) + , m_ArraySize(a_arraySize) + , m_MaxArraySize(a_dynArrayOffset) + , m_FirstBit(-1) + , m_LastBit(-1) + , m_IsLast(true) +{ +} + + + +LogViewXdrType::LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrType") + , m_Type(a_type) + , m_ArraySize(a_arraySize) + , m_MaxArraySize(a_dynArrayOffset) + , m_FirstBit(a_firstBit) + , m_LastBit(a_lastBit) + , m_IsLast(a_isLast) +{ +} + + + +void LogViewXdrType::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() + << "]: kind=" << getKindName() + << " type=" << getType() + << " arraySize=" << getArraySize() + << " maxArraySize=" << getMaxArraySize() + << " firstBit=" << m_FirstBit + << " lastBit=" << m_LastBit + << " isLast=" << m_IsLast; +} + + + +const QString& LogViewXdrType::getType() const +{ + return m_Type; +} + + + + + + +uint16_t LogViewXdrType::getArraySize() const +{ + return m_ArraySize; +} + + + +bool LogViewXdrType::maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const +{ + + if (m_FirstBit != -1 && m_LastBit != -1) + { + DEBUG_LOG(m_logger) << "MaskValue for Element " << m_Name + << " type: " << m_Type + << " size: " << m_ArraySize + << " first:last " << m_FirstBit << ":" << m_LastBit + << " isLast: " << m_IsLast; + uint16_t bitshift = (a_size*8)-m_LastBit-1; + uint32_t mask = (1<<(m_LastBit-m_FirstBit+1))-1; + + a_value = (a_value >> bitshift) & mask; + + a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_FirstBit, QLatin1String("")); + a_tooltip.insert(a_tooltip.length()-(a_size*8)+m_LastBit+1, QLatin1String("")); + return m_IsLast; + } + return true; +} + + + +uint16_t LogViewXdrType::getMaxArraySize() const +{ + return m_MaxArraySize; +} + +} diff --git a/TetraIF/LogView/LogViewXdrType.hpp b/TetraIF/LogView/LogViewXdrType.hpp new file mode 100644 index 000000000..a189f3764 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrType.hpp @@ -0,0 +1,72 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrType final : public LogViewXdrElement + { + public: + + + + LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind); + + + + LogViewXdrType(const QString& a_name, const QString& a_type, const uint16_t a_arraySize, const uint16_t a_dynArrayOffset, const E_ElementKind a_kind, const int16_t a_firstBit, const int16_t a_lastBit, const bool a_isLast); + + + void dump() const override; + + + const QString& getType() const; + + + + uint16_t getArraySize() const; + + + + bool maskValue(uint32_t& a_value, const uint16_t a_size, QString& a_tooltip) const; + + + uint16_t getMaxArraySize() const; + + protected: + + QString m_Type; + + + uint16_t m_ArraySize; + + + uint16_t m_MaxArraySize; + + + int16_t m_FirstBit; + + + int16_t m_LastBit; + + + bool m_IsLast; + }; + +} + diff --git a/TetraIF/LogView/LogViewXdrValue.cpp b/TetraIF/LogView/LogViewXdrValue.cpp new file mode 100644 index 000000000..70e8a2b93 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrValue.cpp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + +#include "LogViewXdrValue.hpp" + + +namespace N_LogView +{ + + +LogViewXdrValue::LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind) + : LogViewXdrElement(a_name, a_kind, "LogViewXdrValue") + , m_Value(a_value) +{} + + + +void LogViewXdrValue::dump() const +{ + INFO_LOG(m_logger) << "Element[" << getName() << "]: kind=" << getKindName() << " value=" << getValue(); +} + + + +int64_t LogViewXdrValue::getValue() const +{ + return m_Value; +} + +} diff --git a/TetraIF/LogView/LogViewXdrValue.hpp b/TetraIF/LogView/LogViewXdrValue.hpp new file mode 100644 index 000000000..db8eec061 --- /dev/null +++ b/TetraIF/LogView/LogViewXdrValue.hpp @@ -0,0 +1,34 @@ + + + + + + + + + + + + + +#pragma once + +#include "LogViewXdrElement.hpp" + +namespace N_LogView +{ + + + class LogViewXdrValue final : public LogViewXdrElement + { + public: + LogViewXdrValue(const QString& a_name, const int64_t a_value, const LogViewXdrElement::E_ElementKind a_kind); + + void dump() const override; + int64_t getValue() const; + + protected: + + int64_t m_Value; + }; +} diff --git a/TetraIF/LogView/LogView_log4cxx.props b/TetraIF/LogView/LogView_log4cxx.props new file mode 100644 index 000000000..195ca75b0 --- /dev/null +++ b/TetraIF/LogView/LogView_log4cxx.props @@ -0,0 +1,17 @@ +log4j.reset=true +log4j.rootLogger=INFO, C +log4j.rootLogger=INFO, F + +log4j.appender.C=org.apache.log4j.ConsoleAppender + +log4j.appender.F=org.apache.log4j.RollingFileAppender +log4j.appender.F.File=${LOG4QT_LOGDIR}/${LOG4QT_USER}_LogView.log + +log4j.appender.F.MaxFileSize=10MB +# Keep one backup file +log4j.appender.F.MaxBackupIndex=5 + +log4j.appender.C.layout=org.apache.log4j.PatternLayout +log4j.appender.F.layout=org.apache.log4j.PatternLayout +log4j.appender.C.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n +log4j.appender.F.layout.ConversionPattern=%-5p (%-20.20F:%04L) [%d{HH:mm:ss.SSS}] - %m%n diff --git a/TetraIF/LogView/image/C2P.png b/TetraIF/LogView/image/C2P.png new file mode 100644 index 000000000..90b92e69f Binary files /dev/null and b/TetraIF/LogView/image/C2P.png differ diff --git a/TetraIF/LogView/image/Central.png b/TetraIF/LogView/image/Central.png new file mode 100644 index 000000000..ba118da38 Binary files /dev/null and b/TetraIF/LogView/image/Central.png differ diff --git a/TetraIF/LogView/image/GreenDarkLamp.png b/TetraIF/LogView/image/GreenDarkLamp.png new file mode 100644 index 000000000..a30e19919 Binary files /dev/null and b/TetraIF/LogView/image/GreenDarkLamp.png differ diff --git a/TetraIF/LogView/image/GreenLamp.png b/TetraIF/LogView/image/GreenLamp.png new file mode 100644 index 000000000..8993d95ad Binary files /dev/null and b/TetraIF/LogView/image/GreenLamp.png differ diff --git a/TetraIF/LogView/image/P2C.png b/TetraIF/LogView/image/P2C.png new file mode 100644 index 000000000..8e969cce8 Binary files /dev/null and b/TetraIF/LogView/image/P2C.png differ diff --git a/TetraIF/LogView/image/P2T.png b/TetraIF/LogView/image/P2T.png new file mode 100644 index 000000000..55ad4fd22 Binary files /dev/null and b/TetraIF/LogView/image/P2T.png differ diff --git a/TetraIF/LogView/image/P2W.png b/TetraIF/LogView/image/P2W.png new file mode 100644 index 000000000..025c2a1f0 Binary files /dev/null and b/TetraIF/LogView/image/P2W.png differ diff --git a/TetraIF/LogView/image/RedLamp.png b/TetraIF/LogView/image/RedLamp.png new file mode 100644 index 000000000..e91a5d68c Binary files /dev/null and b/TetraIF/LogView/image/RedLamp.png differ diff --git a/TetraIF/LogView/image/ShowSend.png b/TetraIF/LogView/image/ShowSend.png new file mode 100644 index 000000000..77e048608 Binary files /dev/null and b/TetraIF/LogView/image/ShowSend.png differ diff --git a/TetraIF/LogView/image/T2P.png b/TetraIF/LogView/image/T2P.png new file mode 100644 index 000000000..3cb53c5c3 Binary files /dev/null and b/TetraIF/LogView/image/T2P.png differ diff --git a/TetraIF/LogView/image/TNE.png b/TetraIF/LogView/image/TNE.png new file mode 100644 index 000000000..52f583bf3 Binary files /dev/null and b/TetraIF/LogView/image/TNE.png differ diff --git a/TetraIF/LogView/image/Tetra.png b/TetraIF/LogView/image/Tetra.png new file mode 100644 index 000000000..9dc5412a8 Binary files /dev/null and b/TetraIF/LogView/image/Tetra.png differ diff --git a/TetraIF/LogView/image/W2P.png b/TetraIF/LogView/image/W2P.png new file mode 100644 index 000000000..a70d11a61 Binary files /dev/null and b/TetraIF/LogView/image/W2P.png differ diff --git a/TetraIF/LogView/image/Wls.png b/TetraIF/LogView/image/Wls.png new file mode 100644 index 000000000..61410b000 Binary files /dev/null and b/TetraIF/LogView/image/Wls.png differ diff --git a/TetraIF/LogView/image/YellowDarkLamp.png b/TetraIF/LogView/image/YellowDarkLamp.png new file mode 100644 index 000000000..ab7ccd7db Binary files /dev/null and b/TetraIF/LogView/image/YellowDarkLamp.png differ diff --git a/TetraIF/LogView/image/YellowLamp.png b/TetraIF/LogView/image/YellowLamp.png new file mode 100644 index 000000000..3ee9c49b7 Binary files /dev/null and b/TetraIF/LogView/image/YellowLamp.png differ diff --git a/TetraIF/LogView/logger.cpp b/TetraIF/LogView/logger.cpp new file mode 100644 index 000000000..8790cc277 --- /dev/null +++ b/TetraIF/LogView/logger.cpp @@ -0,0 +1,32 @@ + + + +#include "logger.h" + +#include + +namespace N_LogView +{ + +LOGGER_T getLogger(const char *name) +{ + static const char ns[] = "LogView."; + 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(); + } +} + +} diff --git a/TetraIF/LogView/logger.h b/TetraIF/LogView/logger.h new file mode 100644 index 000000000..8baf71f9f --- /dev/null +++ b/TetraIF/LogView/logger.h @@ -0,0 +1,17 @@ + + + +#pragma once + +#include + +namespace N_LogView +{ +typedef NGL::INGLLogger &LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/TetraIF/LogView/zsksxd_tetraForLogView.cpp b/TetraIF/LogView/zsksxd_tetraForLogView.cpp new file mode 120000 index 000000000..e088a4ab5 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView.cpp @@ -0,0 +1 @@ +zsksxd_tetraForLogView.x \ No newline at end of file diff --git a/TetraIF/LogView/zsksxd_tetraForLogView.x b/TetraIF/LogView/zsksxd_tetraForLogView.x new file mode 100644 index 000000000..49504acd8 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView.x @@ -0,0 +1,1834 @@ +/* +const MAX_LAENGE_GEFECHTSFELDTELEGRAMM = 2000; +*/ + +/*-------------------------------*/ +/* Telegramm-ID's */ +/*-------------------------------*/ + +enum8 gef_telegramm_id_et { + + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG = 3, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG = 5, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_TEILNEHMER = 8, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_POSITIONSKORREKTURDATEN = 24, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFSTOFF = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + + GEF_FEUER_EREIGNIS = 51, + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_STEUERUNG_VERKEHRSAUFKOMMEN = 81, + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_TREFFER_AUFGES_TLN = 94, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTS_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTS = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_IPS_POSITIONSDATEN = 201, + GEF_STANDORTBESTIMMUNG = 25, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + GEF_ANFORDERUNG_KONFIG_ZEG = 220, + GEF_KONFIGURATION_IPS = 221, + GEF_KONFIGURATION_ZEG = 222, + GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG = 223, + GEF_TREFFEREREIGNIS_GEBAEUDE = 224, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_GEFECHTSFELDTELEGRAMM = 300, + GEF_UEBERLAST_WARNUNG_ENTWARNUNG = 301, + GEF_DATENFUNK_INIT = 302, + GEF_DATENFUNK_EXIT = 303, + GEF_DATENFUNK_EXIT_ACKNOWLEDGE = 304, + GEF_ZUORDNUNG_GRUPPENRUFADRESSE = 305, + GEF_NOTRUF = 1120, + GEF_LASER_TARGET_DESIGNATOR_UPDATE = 214 + +}; + + +/*==============================================================*/ +/* Strukturtypen, die mehrfach verwendet werden */ +/*==============================================================*/ + +/*---------------------------------------*/ +/* Identifikation */ +/*---------------------------------------*/ + +typedef UInt16 gef_ausstattungs_id_t; + + +/*---------------------------------------*/ +/* Header */ +/*---------------------------------------*/ + +struct gef_header_rt { + gef_ausstattungs_id_t identitaet; +}; + + +/*---------------------------------------*/ +/* GPS-Zeit */ +/*---------------------------------------*/ + +struct gef_gps_zeit_rt { + u_int GPS_zeit; +}; + + +/*---------------------------------------*/ +/* GPS-Position */ +/*---------------------------------------*/ + +struct gef_gps_position_rt { + SInt24 nordwert; + SInt24 ostwert; +}; + + +/*---------------------------------------*/ +/* Lastzustand Datenfunk */ +/*---------------------------------------*/ + +enum8 gef_lastzustand_datenfunk_et { + Normallast = 0, + Hochlast = 1, + Ueberlast = 2 +}; + + +/*==============================================================*/ +/* Beschreibung der speziellen TETRA-Telegramme */ +/*==============================================================*/ + +struct TETRA_register_indication_rt { + UInt32LE ISSI_ext_host; +}; + +enum8 TETRA_registration_status_et { + ISSI_successful_registered = 0, + Duplicate_ISSI = 1, + Invalid_ISSI = 2, + Invalid_IP_address = 3 +}; + +struct TETRA_register_response_rt { + TETRA_registration_status_et registration_status; +}; + +enum8 TETRA_login_status_et { + Login_Request = 1, + Login_Accept = 2, + Login_Reject = 3 +}; + +enum8 TETRA_login_mastering_et { + No_Mastering = 0, + Mastering = 1 +}; + +enum8 TETRA_reject_cause_et { + Reserved = 0, + EqIdAlreadyAssigned = 1, + IssiAlreadyAssigned = 2, + EqIdAssignedInOtherExercise = 3 +}; + +struct TETRA_login_telegram_rt { + gef_header_rt header; + TETRA_login_status_et:0..1 login_status; + TETRA_login_mastering_et:2..2 login_mastering; + TETRA_reject_cause_et:3..6! reject_cause; +}; + +enum8 TETRA_telegram_type_et { + NotFragmented = 0, + FirstFragment = 1, + MiddleFragment = 3, + LastFragment = 2 +}; + +enum8 TETRA_fragment_counter_et { + 0 = 0, + 1 = 1, + 2 = 2, + 3 = 3, + 4 = 4, + 5 = 5, + 6 = 6, + 7 = 7, + 8 = 8, + 9 = 9, + 10 = 10, + 11 = 11, + 12 = 12, + 13 = 13, + 14 = 14, + 15 = 15 +}; + +struct TETRA_first_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + gef_telegramm_id_et telegram_id; + opaque data<28>; /* 28 => dyn.-array-offset */ +}; + +struct TETRA_middle_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_last_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_air_interface_load_report_rt { + UInt8 network_index; + UInt16LE base_station_ID; + UInt8 channel_ID; + UInt8 queue_length; +}; + +struct TETRA_status_ind_req_rt { + UInt32LE ISSI_host; + UInt32LE ISSI_destination; + UInt32LE status; +}; + +enum8 TETRA_monitor_et { + No_Monitoring = 0, + Monitoring = 1 +}; + +struct TETRA_group_monitoring_ind_rt { + UInt32LE ISSI_host; + TETRA_monitor_et monitor; + UInt16LEIdx count_gssi; + UInt32LE gssi<5>; +}; + +struct TETRA_air_interface_load_req_rt { + UInt16LEIdx number_of_reports; + TETRA_air_interface_load_report_rt air_interface_load_report<4>; +}; + +struct TETRA_unknown_PDU_rt { + UInt8 magic_number; + UInt8 counter; + UInt16LE length; + UInt8 PDU_Type; + opaque data<5>; /* 5 => dyn.-array-offset */ +}; + + +/*==============================================================*/ +/* Beschreibung der Telegramme */ +/*==============================================================*/ + +/*----------------------------------------------------------------*/ +/* Automatische Conversion */ +/*----------------------------------------------------------------*/ +/* +Alle TETRA-Meldungen, die mit der Klasse CoPrtCnvTelegramConverter in +eine Zentral-Meldung konvertiert werden, müssen trotzdem in der TETRA- +union definiert werden, damit die Telegramme Namen bekommen. +*/ + +struct gef_automatic_conversion_rt { + gef_header_rt header; + UInt8 fehler_diese_meldung_sollte_automatisch_konvertiert_werden; +}; + + + +/*----------------------------------------------------------------*/ +/* Init-Meldung */ +/* INIT_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_tln_aufmunitionieren_et { + tln_am_nein = 0, + tln_am_ja = 1 +}; + +enum8 gef_tln_zuruecksetzen_et { + tln_zs_nein = 0, + tln_zs_ja = 1 +}; + +enum8 gef_tln_manipulation_et { + tln_mp_nein = 0, + tln_mp_reset = 1 +}; + +enum8 gef_tln_medizinische_vorraete_auffuellen_et { + tln_mv_nein = 0, + tln_mv_reset = 1 +}; + +/* MSB = 0 ... */ +struct gef_initialisierungsdaten_rt { + gef_tln_aufmunitionieren_et:2..2 tln_aufmunitionieren; + gef_tln_zuruecksetzen_et:1..1 tln_zuruecksetzen; + gef_tln_manipulation_et:7..7 tln_manipulation; + gef_tln_medizinische_vorraete_auffuellen_et:6..6 tln_mediziniesche_vorraete_auffuellen; +}; + +struct gef_init_meldung_rt { + gef_header_rt header; + gef_initialisierungsdaten_rt initialisierungsdaten; +}; + + +/*----------------------------------------------------------------*/ +/* Umgebungs-Meldung */ +/* UMGEBUNGS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_uebungspause_et { + KEINE_UEBUNGSPAUSE = 0, + B_MIT_TEST = 1 +}; + +enum8 gef_inhbit_time_et { + IH_UNDEFINED = 0, + IH_1_SEKUNDE = 1, + IH_2_SEKUNDEN = 2, + IH_3_SEKUNDEN = 3, + IH_4_SEKUNDEN = 4, + IH_5_SEKUNDEN = 5, + IH_6_SEKUNDEN = 6, + IH_7_SEKUNDEN = 7, + IH_8_SEKUNDEN = 8, + IH_9_SEKUNDEN = 9, + IH_10_SEKUNDEN = 10, + IH_11_SEKUNDEN = 11, + IH_12_SEKUNDEN = 12, + IH_13_SEKUNDEN = 13, + IH_14_SEKUNDEN = 14, + IH_15_SEKUNDEN = 15, + IH_16_SEKUNDEN = 16, + IH_17_SEKUNDEN = 17, + IH_18_SEKUNDEN = 18, + IH_19_SEKUNDEN = 19, + IH_20_SEKUNDEN = 20, + IH_21_SEKUNDEN = 21, + IH_22_SEKUNDEN = 22, + IH_23_SEKUNDEN = 23, + IH_24_SEKUNDEN = 24, + IH_25_SEKUNDEN = 25, + IH_26_SEKUNDEN = 26, + IH_27_SEKUNDEN = 27, + IH_28_SEKUNDEN = 28, + IH_29_SEKUNDEN = 29, + IH_30_SEKUNDEN = 30, + IH_31_SEKUNDEN = 31 +}; + +struct gef_betriebszustaende_gefechtsfeld_rt { + gef_uebungspause_et:0..0 uebungspause; + gef_inhbit_time_et:1..5 pos_inhibit_time; + gef_lastzustand_datenfunk_et:6..7! lastzustand_datenfunk; +}; + +struct gef_basiskoordinate_zur_positionsbestimmung_rt { + UInt8 zone; + string band; + string quadrat[2]; + UInt8 ostwert; + UInt8 nordwert; +}; + +struct gef_umgebungs_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; +}; + +struct gef_umgebungs_meldung2_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; + gef_gps_zeit_rt aktuelle_zeit; +}; + + +/*----------------------------------------------------------------*/ +/* Aufforderung BITE-Meldung */ +/* AUFFORDERUNG_BITE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_bite_meldungsart_et { + NUR_STATUSABFRAGE = 0, + ERST_SELBSTTEST = 1 +}; + +struct gef_aufforderung_bite_meldung_rt { + gef_header_rt header; + gef_bite_meldungsart_et bite_meldungsart; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration Wirkmodell */ +/* GEF_KONFIGURATION_WIRKMODELL */ +/*----------------------------------------------------------------*/ + +struct gef_wirkmodell_rt { + UInt8 minen_ied; + UInt8 steilfeuer; + UInt8 einsatzmittel; + UInt8 ac_waffen; +}; + +struct gef_konfiguration_wirkmodell_rt { + gef_header_rt header; + gef_wirkmodell_rt wirkmodelle; +}; + +/*----------------------------------------------------------------*/ +/* Konfigurationsmeldung */ +/* GEF_KONFIGURATION_TEILNEHMER */ +/*----------------------------------------------------------------*/ + +struct gef_login_parameter_rt { + UInt8 wartezeit_versuche; + UInt8 anzahl_versuche; + UInt8 mastering_flag; +}; + +enum8 gef_sprache_et { + keine_aenderung = 0, + deutsch = 1, + englisch = 2, + franzoesisch = 3 +}; + +struct gef_konfiguration_abe_rt { + UInt8 sprachausgabe; + gef_sprache_et sprache; +}; + +struct gef_konfiguration_wirkdarstellung_rt { + UInt8 pyrotechnik; +}; + +enum8 gef_betriebsart_mhgr_sensorik_et { + BetriebAmAusbAusstgPers = 0, + BetriebAnSonstigenFzg = 2, + BetriebAnSrFahrzeug = 3 +}; + +struct gef_konfiguration_mhgr_sensorik_rt { + gef_betriebsart_mhgr_sensorik_et betriebsart; + UInt8 energiesparmodus; +}; + +enum8 gef_konfiguration_ss_fir_et { + keineKonfigurationFir = 0, + fir = 1, + firSpzMarder = 2 +}; + +enum8 gef_konfiguration_ss_minenverlegung_et { + keineKonfigurationMinenverlegung = 0, + MvAnh = 1, + Wmv = 2 +}; + +enum8 gef_konfiguration_ss_standard_et { + keineKonfigurationSsStandard = 0, + ZABC = 3, + CSF = 4, + PzBr = 5, + MRF = 7 +}; + +struct gef_konfiguration_sondersenoriken_rt { + gef_konfiguration_ss_fir_et fir; + gef_konfiguration_ss_minenverlegung_et minenverlegung; + gef_konfiguration_ss_standard_et standard; +}; + +enum8 gef_agdus_hw_modus_et { + ohneHelmOhneWeste = 1, + mitHelmOhneWeste = 2, + mitHelmMitWeste = 3 +}; + +enum8 gef_konfigurations_positionsupdate_et { + Fahrzeug = 0, + Person = 1, + Luftfahrzeug = 2 +}; + +struct gef_konfiguration_anzeige_rt { + UInt8 hauptgruppe; + UInt8 untergruppe; +}; + +struct gef_konfigurationsdaten_rt { + gef_ausstattungs_id_t identitaet; + UInt16 can_startup_zeit; + unsigned char teilnehmertyp; + gef_login_parameter_rt login_parameter; + UInt32LE can_geraete_konfiguration; + gef_konfiguration_abe_rt abe; + gef_konfiguration_wirkdarstellung_rt wirkdarstellung; + gef_konfiguration_mhgr_sensorik_rt mhgr_sensorik; + gef_konfiguration_sondersenoriken_rt sondersenrik; + gef_agdus_hw_modus_et agdus_hw_modus; + gef_konfigurations_positionsupdate_et positionsupdate; + gef_konfiguration_anzeige_rt anzeige; + UInt8 wirkmodellAgdus; +}; +% +struct gef_konfiguration_teilnehmer_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_konfigurationsdaten_rt konfiguration; + gef_wirkmodell_rt wirkmodelle; +}; +/*----------------------------------------------------------------*/ +/* Lizensierung TNE-Meldung */ +/* LIZENSIERUNG_TNE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_lizenzierungsart_et { + ANMELDUNG_ERFOLGREICH = 0, + ANMELDUNG_ABGELEHNT = 1, + ABMELDUNG = 2 +}; + +struct gef_lizensierung_tne_meldung_rt { + gef_header_rt header; + gef_lizenzierungsart_et lizenzierungsart; + opaque fehlercode_lizenzierung[3]; +}; + +enum8 gef_qualifikation_et { + Undefiniert = 0, + Arzt = 1, + Sanitaeter = 2, + Ersthelfer = 3 +}; + +/*----------------------------------------------------------------*/ +/* Bestandsmeldung Saniätsmaterial */ +/* GEF_BESTANDSMELDUNG_SANITAETSMATERIAL */ +/*----------------------------------------------------------------*/ +struct gef_bestandmseldung_sanitatsmaterial_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt8 anzahl_sanmat; + UInt24 bestand_sanmaterialien; +}; + + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung PVSAN */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN */ +/*----------------------------------------------------------------*/ +struct gef_sanitetsdienst_instandsetzung_pvsan_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 massnahmen_getaetigt; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt16 massnahmen_benoetigt; +}; + +/*----------------------------------------------------------------*/ +/* Technik Funktionsraum-Meldung */ +/* TECHNIK_FUNKTIONSRAUM */ +/*----------------------------------------------------------------*/ +struct gef_technik_funktionsraum_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; + UInt8 typ; + string wirkfeldbezeichner[8]; + gef_gps_position_rt zentrum; + UInt16 breite; + UInt16 hoehe; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelgeschoss-Meldung */ +/* WIRKFELD_EINZELGESCHOSS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_munitionsart_steilfeuer_et { + STEILFEUER_AZ = 1, + STEILFEUER_HE_ANNZ = 2, + STEILFEUER_BOMBLET = 3, + STEILFEUER_SM_ART = 4, + STEILFEUER_NEBEL = 5, + MOERSER_AZ = 10, + MOERSER_ANNZ = 11, + BORDKANONE = 20, + UNGEL_RAKETE = 21, + BOMBLET = 22, + SPRENGBOMBE = 23 +}; +struct gef_beschreibung_wirkfeld_einzelgeschoss_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt einschlagort; + UInt8 wirkdurchmesser; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_einzelgeschoss_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_einzelgeschoss_rt beschreibung_wirkfeld_einzelgeschoss; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 wirkfeldbreite; + UInt8 wirkfeldtiefe; + UInt16 drehwinkel; + UInt16 anzahl_einschlaege; + UInt8 wirkkantenlaenge; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt beschreibung_wirkfeld_flaechendeckendes_feuer; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Stop-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_STOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Fortsetzen-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt { + UInt16 wirkfeldkennung; + UInt16 fortsetzungswert_zufallszahl; + UInt16 nummer_des_naechsten_einschags; + gef_gps_zeit_rt fortsetzungszeit; + UInt16 verbleibende_wirkdauer; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Minensperre-Meldung */ +/* WIRKFELD_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_minentyp_et { + SchtzAbwMi_DUS = 211, + SchtzAbVMi_DUS = 212, + PzAbwVMi_DUS = 213, + SchtzAbwMi_virtuell = 214, + PzAbwVMi_virtuell = 215, + PzAbwWMi_virtuell = 216, + PzAbwRiMi_AGDUS = 60 +}; + +struct gef_segment_rt { + gef_gps_position_rt startpunkt; + UInt16 minenanzahl; + UInt16 drehwinkel; +}; + +struct gef_beschreibung_wirkfeld_minensperre_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt16 wirkfeldbreite; + UInt16 wirkfeldtiefe; + UInt8 verlegetiefe; + UInt8 verlegedichte; + gef_minentyp_et minentyp; + UInt16 minenanzahl; + UInt8Idx anzahl_segmente; + gef_segment_rt segment<5>; +}; + +struct gef_wirkfeld_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_minensperre_rt beschreibung_wirkfeld_minensperre; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Status Minensperre-Meldung */ +/* WIRKFELD_STATUS_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_minenstatus_rt { + UInt16 wirkfeldkennung; + UInt16IdxDiv8 anzahl_minen; + opaque minenstatus<150>; +}; + +struct gef_wirkfeld_status_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_minenstatus_rt beschreibung_minenstatus; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld A-Kampfmittel-Meldung */ +/* WIRKFELD_A_KAMPFMITTEL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_a_kampfmittel_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt16 kantenlaenge_bereich_1; + UInt16 kantenlaenge_bereich_2; + UInt16 oeffnungswinkel; + UInt16 drehwinkel; +}; + +struct gef_wirkfeld_a_kampfmittel_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_a_kampfmittel_rt beschreibung_wirkfeld_a_kampfmittel; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld C-Kampfstoff-Meldung */ +/* WIRKFELD_C_KAMPFSTOFF_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_kampfstofftyp_et { + fluechtig = 1, + sesshaft = 2 +}; + +struct gef_beschreibung_wirkfeld_c_kampfstoff_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt8 vergroesserungsfaktor; + UInt16 windrichtung; + UInt8 windgeschwindigkeit; + gef_gps_zeit_rt gueltigkeitszeitpunkt_wetterdaten; + gef_gps_position_rt position_gueltigkeitszeitpunkt_wetterdaten;; + UInt8 kampfstoffkennung; + gef_kampfstofftyp_et kampfstofftyp; +}; + +struct gef_wirkfeld_c_kampfstoff_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_c_kampfstoff_rt beschreibung_wirkfeld_c_kampfstoff; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung-Wirkfeld-Meldung */ +/* DEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_wirkfeldtyp_et { + Undefined = 0, + Minensperre = 1, + Steilfeuer_Flaeche = 2, + Steilfeuer_Einzel = 3, + A_Waffe = 4, + C_Waffe = 5, + Funktionsraum = 6, + TechnicalArea = 7, + DusSingleMineSimulator = 8, + GasPipeDetonation = 9, + SpecialArea = 10, + BeStillWarning = 11, + DangerZoneExplosion = 12, + AirSupport = 13 +}; + +struct gef_deaktivierung_wirkfeld_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Aenderung Bezeichner-Meldung */ +/* WIRKFELD_AENDERUNG_BEZEICHNER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_aenderung_bezeichner_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung Einzelmine-Meldung */ +/* DEAKTIVIERUNG_EINZELMINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivierung_einzelmine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_gps_zeit_rt GPS_Zeit; + UInt16 wirkfeldkennung; + UInt16 minenindex; +}; + + + +/*----------------------------------------------------------------*/ +/* Reaktivierung DUS Mine-Meldung */ +/* REAKTIVIERUNG_DUS_MINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_Minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_reaktivierung_dus_mine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_dus_minenkennungen_rt DUS_minenkennungen; +}; + +/*----------------------------------------------------------------*/ +/* Definition-IED */ +/* DEFINITION_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_typ_et { + S_IED = 1, + IED_innen = 2, + IED_aussen = 3 +}; + +enum8 gef_ied_kopplungsstatus_et { + IED_keine_Kopplung = 1, + IED_Kopplung_an_Tln = 2, + IED_Kopplung_an_IPS = 3 +}; + +enum8 gef_ied_takitscher_zustand_et { + IED_inaktiv = 0, /* verlegt und gesichert */ + IED_aktiv = 1, /* scharf */ + IED_geloescht = 2, /* entschaerft */ + IED_ausgeloest_Schalter = 3, + IED_ausgeloest_Fernbedienung = 4, + IED_ausgeloest_Lichtschranke = 5, + IED_ausgeloest_Zugdraht = 6, + IED_ausgeloest_Kontrollgeraet = 7, + IED_unbekannt = 255 /* Kontakt verloren */ +}; + +struct gef_definition_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_typ_et typ; + UInt8 ausloeser; + UInt8 sprengkraft; + gef_gps_position_rt gps_position; + UInt8 partei_id; + gef_ied_kopplungsstatus_et kopplungsstatus; + gef_ausstattungs_id_t gekoppelte_id; + gef_ied_takitscher_zustand_et taktischer_zustand; /* 0 inaktiv, 1 aktiv */ + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ +}; + +/*----------------------------------------------------------------*/ +/* Zustand-IED */ +/* ZUSTAND_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_fehler_et { + IED_kein_Fehler = 0, + IED_Kommunikations_Fehler = 1 +}; + +struct gef_zustand_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_takitscher_zustand_et taktischer_zustand; + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ + UInt8 batteriewarnung; /* Bitleiste */ + gef_ied_fehler_et fehler_status_elektronik; + gef_ied_fehler_et fehler_status_pyrotechnik1; + gef_ied_fehler_et fehler_status_pyrotechnik2; + gef_ied_fehler_et fehler_status_pyrotechnik3; +}; + + +/*----------------------------------------------------------------*/ +/* Treffer Ausloesung-Meldung */ +/* TREFFER_AUSLOESUNG_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_verwundung_beschaedigung_et { + Einsatzbereit = 0, + Leichter_Treffer = 1, + Mittlerer_Treffer = 2, + Schwerer_Treffer = 3, + Bewegungsunfaehig = 4, + Bewegungsunfaehig_sichtbar = 5, + Ausfall_Waffenanlage = 6, + Ausfall_Waffenanlage_sichtbar = 7, + Totalausfall_sichtbar = 8, + Zeitlicher_Ausfall = 9, + Annaehernder_Treffer = 10, + Treffer_ohne_Wirkung = 11 +}; + +struct gef_treffer_ausloesung_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_verwundung_beschaedigung_et verwundung_beschaedigung; +}; + +/*----------------------------------------------------------------*/ +/* Status Einzelminensimulator */ +/* STATUS_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_status_einzelminensimulator_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 minenkennung; + gef_gps_position_rt gps_position; + UInt8 minentyp; + UInt8 status; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelminensimulator */ +/* WIRKFELD_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_einzelminensimulator_rt { + UInt16 wirkfeldkennung; + UInt8 partei_id; + UInt16 minenkennung; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt minenposition; + UInt8 minentyp; +}; + +struct gef_wirkfeld_einzelminensimulator_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_einzelminensimulator_rt beschreibung_einzelminensimulator; +}; + +/*----------------------------------------------------------------*/ +/* Schiedsrichtereingriff */ +/* SCHIEDSRICHTEREINGRIFF */ +/*----------------------------------------------------------------*/ +/* +struct gef_schiedsrichtereingriff_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_gps_position_rt gps_position; + UInt16 schiedsrichter_aktion; + UInt8 schiedsrichter; +}; + + + +/*----------------------------------------------------------------*/ +/* Selektive Aufmunitionierung */ +/* GEF_SELEKTIVE_AUFMUNITIONIERUNG */ +/*----------------------------------------------------------------*/ +struct gef_aufmunitionierung_rt { + UInt16 munitionsart; + UInt8 ort; /* Turm / Wanne */ + UInt16 neuer_vorrat; /* 0xffff = default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt16 neuer_default_vorrat; /* 0xffff = factory default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt8 tracer_ratio; /* 0 = kein Trace, 1 = jedes Projektil, 2 = jedes 2. Projektil, ... */ +}; + +struct gef_selektive_aufmunitionierung_rt { + gef_header_rt header; + u_int waffen_id; + UInt8Idx anzahl_aufmunitionierungen; + gef_aufmunitionierung_rt aufmunitionierung<10>; +}; + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_behandlungs_ergebnis_et { + Keine = 0, + Erfolg = 1, + Stabilisiert = 2, + Fehler = 3 +}; + +struct gef_sanitetsdienst_instandsetzung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt8 verurschaer_typ; + UInt16 ausstattung_behandelnder; + gef_verwundung_beschaedigung_et status_start; + UInt8 typ_der_behandlung; + UInt8 triage; + UInt8 typ_der_behandlung; + gef_verwundung_beschaedigung_et status_ergebnis; + gef_behandlungs_ergebnis_et ergebhnis_behandlung; + UInt8 triage_priorität; + UInt8 komplett_status; + UInt24 behandlungszeit; + UInt24 erholungszeit; +}; + + + +*/ +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_betriebsmodus_et { + Nicht_vorhanden = 0, + Eingriff_durch_schiedsrichter = 1, + Wartezeit_nach_Erreichen_des_Funktionsraums = 2 +}; + +struct gef_funktionsraum_rt { + gef_betriebsmodus_et betriebsmodus; + UInt8 wartezeit; +}; + +struct gef_beschreibung_funktionsraum_rt { + UInt16 funktionsraumkennung; + string funktionsraumbezeichner[8]; + UInt8 partei_id; + gef_gps_position_rt funktionsraumeckpunkt; + UInt8 funktionsraumbreite; + UInt8 funktionsraumtiefe; + gef_funktionsraum_rt funktionsraum_fuer_entgiftungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_instandsetzungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_sandienstliche_versorgung; +}; + +struct gef_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_funktionsraum_rt beschreibung_funktionsraum; +}; + + + +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivieren_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 funktionsraumkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-SRT-Meldung */ +/* DATENVERKEHR_TDS_SRT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_fuer_tne_transparente_daten_rt { + opaque data<30>; /* 30 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_srt_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-DMF-Meldung */ +/* DATENVERKEHR_TDS_DMF_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_datenverkehr_tds_dmf_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Steuerung Verkehrsaufkommen-Meldung */ +/* STEUERUNG_VERKEHRSAUFKOMMEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_steuerung_verkehrsaufkommen_meldung_rt { + gef_header_rt header; + gef_lastzustand_datenfunk_et lastzustand_datenfunk; + UInt16 inhibit_zeit_fuer_positionsmeldungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Nachforderung Broadcast Telegramme-Meldung */ +/* NACHFORDERUNG_BROADCAST_TELEGRAMME_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachforderung_broadcast_telegramme_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + UInt8 ruecksetzzaehler; + UInt16 broadcast_index; +}; + + + +/*----------------------------------------------------------------*/ +/* Nop-Meldung */ +/* NOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_broadcasttelegramme_rt { + UInt16 feld_anfang; + UInt16 feld_ende; +}; + +struct gef_nop_meldung_rt { + gef_header_rt header; + gef_broadcasttelegramme_rt broadcasttelegramme; +}; + + + +/*----------------------------------------------------------------*/ +/* Sprachauswahl-Meldung */ +/* SPRACHAUSWAHL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_sprachauswahl_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sprache_et sprachauswahl; +}; + + + +/*----------------------------------------------------------------*/ +/* Allgemeine Nachricht-Meldung */ +/* ALLGEMEINE_NACHRICHT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachricht_rt { + UInt8Idx laenge; + string text<80>; +}; + +struct gef_allgemeine_nachricht_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_nachricht_rt nachricht; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Wirkfeld-Meldung */ +/* SAMMELDEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_wirkfeldkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 wirkfeldkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_wirkfeldkennungen_rt liste_der_wirkfeldkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung DUS-Minen-Meldung */ +/* SAMMELDEAKTIVIERUNG_DUS_MINEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_wf_sammeldeaktivierung_dus_minen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_dus_minenkennungen_rt liste_DUS_minenkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Funktionsraum-Meldung */ +/* SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_funktionsraumkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 funktionsraumkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_funktionsraumkennungen_rt liste_der_funktionsraumkennungen; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-GeoP-Meldung */ +/* DATENVERKEHR_TDS_GEOP_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_geop_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_geop_meldung_rt { + gef_header_rt header; + UInt8 laenge_GeoP_Daten; + gef_geop_daten_rt geop_daten; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-TgtS-Meldung */ +/* DATENVERKEHR_TDS_TGTS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_tgts_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_tgts_meldung_rt { + gef_header_rt header; + UInt8 laenge_tgts_Daten; + gef_tgts_daten_rt tgts_daten; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration IPS-Meldung */ +/* KONFIGURATION_IPS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zuordnung_rt { + UInt16 raumnummer_des_gebaeudemodell; + UInt16 IPS_Platz_des_gebaeudemodell; + UInt16 IPS_Kennung; +}; + +struct gef_ips_konfiguration_rt { + UInt8Idx anzahl; + gef_zuordnung_rt zuordnung<255>; +}; + +struct gef_konfiguration_ips_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_ips_konfiguration_rt ips_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG */ +/*----------------------------------------------------------------*/ +struct gef_treffer_ereignis_sekundaerwirkung_rt { + gef_header_rt header; + gef_gps_zeit_rt wirkbeginn; + UInt16 munCode; + UInt16 verursacher; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt8 effectCode; + UInt16 reserve1; + UInt16 reserve2; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration ZEG-Meldung */ +/* KONFIGURATION_ZEG_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zeg_zuordnung_rt { + UInt16 referenzmodul_des_gebaeudemodell; + UInt16 ZEG_Kennung; +}; + +struct gef_zeg_konfiguration_rt { + UInt8Idx anzahl; + gef_zeg_zuordnung_rt zeg_zuordnung<255>; +}; + +struct gef_konfiguration_zeg_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_zeg_konfiguration_rt zeg_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* Ausloseung DUS-Treffer */ +/* GEF_AUSLOESUNG_DUS_TREFFER */ +/*----------------------------------------------------------------*/ +struct gef_ausloesung_dus_treffer_rt { + gef_header_rt header; + gef_gps_zeit_rt zeit; + UInt8Idx munitionsart; + UInt16 richtung; + UInt16 entfernung; + UInt8Idx wirkung; + UInt16 verursacher; +}; +/*----------------------------------------------------------------*/ +/* GEF_ANFORDERUNG_SW_VERSION */ +/* GEF_SW_VERSIONSMELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_anforderung_sw_version_rt { + gef_header_rt header; + UInt16 geraetekennung; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_SETZEN (Zentrale -> SFM) */ +/*----------------------------------------------------------*/ +enum8 gef_tln_sprache_et { + TLN_SPRACHE_KEINE_AENDERUNG = 0, + TLN_SPRACHE_DE = 1, + TLN_SPRACHE_EN = 2, + TLN_SPRACHE_FR = 3, + TLN_SPRACHE_AR = 4, + TLN_SPRACHE_ES = 5, + TLN_SPRACHE_RU = 6 +}; + +enum8 gef_operation_mode_et { + OP_MODE_KEINE_AENDERUNG = 0, + OP_MODE_NORMAL = 1, + OP_MODE_BE_STILL = 2 +}; + +enum8 gef_wph_mode_weste_et { + WPH_MODE_WESTE_KEINE_AENDERUNG = 0, + WPH_MODE_WESTE_OHNE = 1, + WPH_MODE_WESTE_MIT = 2 +}; + +enum8 gef_wph_mode_helm_et { + WPH_MODE_HELM_KEINE_AENDERUNG = 0, + WPH_MODE_HELM_OHNE = 1, + WPH_MODE_HELM_MIT = 2 +}; + +enum8 gef_wph_mode_personenschutz_et { + WPH_MODE_PERSONENSCHUTZ_KEINE_AENDERUNG = 0, + WPH_MODE_PERSONENSCHUTZ_OHNE = 1, + WPH_MODE_PERSONENSCHUTZ_ANZUG = 2, + WPH_MODE_PERSONENSCHUTZ_ANZUG_HANDSCHUHE_SCHUHE = 3 +}; + +enum8 gef_schutzniveau_et { + SN_SCHUTZ_KEINE_AENDERUNG = 0, + SN_IDZ_ES = 1, + SN_IDZ_BS = 2, + SN_KSK = 3, + SN_SOLDAT_MIT_KOERPERSCHUTZ = 4, + SN_SOLDAT_DARSTELLER = 5 +}; + +enum8 gef_handgranaten_suche_et { + HS_KEINE_AENDERUNG = 0, + HS_SUCHE_AUS = 1, + HS_SUCHE_EIN = 2 +}; + +enum8 gef_international_mode_et { + IM_KEINE_AENDERUNG = 0, + IM_AUS = 1, + IM_EIN = 2 +}; + +/* Reaktivierung: in Minuten (0, 10 .. 2550) */ +struct gef_teilnehmermode_rt { + gef_tln_sprache_et sprache; + gef_operation_mode_et op_mode; + UInt8 reaktivierung_entgiftung; + UInt8 reaktivierung_inst; + UInt8 reaktivierung_sanitaet; + gef_wph_mode_personenschutz_et:1..3 mode_personenschutz; + gef_wph_mode_weste_et:4..5 mode_weste; + gef_wph_mode_helm_et:6..7! mode_helm; + gef_schutzniveau_et schutzniveau; + gef_handgranaten_suche_et:6..7! handgranaten_suche; + gef_international_mode_et:4..5 international_mode; +}; + +struct gef_teilnehmermode_setzen_rt { + gef_header_rt header; + UInt16 bcIndex; + gef_teilnehmermode_rt mode; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_MELDUNG (SFM -> Zentrale) */ +/*----------------------------------------------------------*/ +struct gef_teilnehmermode_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_teilnehmermode_rt mode; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_SETZEN */ +/*----------------------------------------------------------------*/ + +enum8 gef_positions_handling_et { + POS_HANDLING_DEFAULT = 0, + POS_HANDLING_UNGUELTIG_NICHT_SCHICKEN = 1, + POS_HANDLING_UNGUELTIG_KENNZEICHNEN = 2, + POS_HANDLING_UNGUELTIG_SCHICKEN = 3 +}; + +enum8 gef_optischer_code_et { + OPTISCHER_CODE_KEINE_AENDERUNG = 0, + OPTISCHER_CODE_OSAG_1_0 = 1, + OPTISCHER_CODE_OSAG_2_0_BASIC = 2 +}; + +struct gef_sfm_konfig_rt { + UInt16 pos_aenderung_fz; + UInt16 pos_aenderung_personal; + UInt16 pos_aenderung_lfz; + UInt16 pos_uebertragungs_interval; + UInt16 hoehengrenze; + gef_positions_handling_et:6..7 positions_handling; + UInt8Idx:0..1! pos_interval_umschaltung; + UInt16 wartezeit_nachforderung; + UInt8 faktor_wartezeit_hochlast; + UInt8 wartezeit_vbg_1_2; + UInt8 wartezeit_vbg_2_3; + UInt8 wartezeit_vbg_3_8; + gef_optischer_code_et optischer_code; + UInt8 verwundungsmodel; + UInt8 gueltigkeitsdauer_standortbestimmung; +}; + +struct gef_teilnehmer_konfig_setzen_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sfm_konfig_rt konfig; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_ANTWORT */ +/*----------------------------------------------------------------*/ + +struct gef_teilnehmer_konfig_antwort_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_sfm_konfig_rt konfig; +}; + +/*-------------------------------------------------------*/ +/* GEF_NOTRUF */ +/*-------------------------------------------------------*/ + +struct gef_notruf_rt { + gef_gps_position_rt gps_position; +}; + +/*==============================================================*/ +/* Zusammenfassung der Telegramm-Typen */ +/*==============================================================*/ +union gef_tg_nd_ switch (gef_telegramm_id_et telegramm_id) { + + case GEF_INIT: + gef_init_meldung_rt init_meldung; + + case GEF_MANIPULATIONSMELDUNG: + case GEF_BITE_MELDUNG: + case GEF_BITE_MELDUNG2: + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_FEHLERMELDUNG_GFD: + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_FEUER_EREIGNIS: + case GEF_TREFFER_EREIGNIS_DUS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + case GEF_TAKTISCHER_STATUS: + case GEF_TREFFER_EREIGNIS_DUS_IPS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + case GEF_EINTRETEN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + case GEF_SONDERSENSORIK_FAHRSPUR: + case GEF_SONDERSENSORIK_DATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + case GEF_DATENVERKEHR_GEOP_TDS: + case GEF_DATENVERKEHR_TGTS_TDS: + case GEF_GERAETEEREIGNIS: + case GEF_WAFFENZUORDNUNG: + case GEF_IPS_POSITIONSDATEN: + case GEF_STANDORTBESTIMMUNG: + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + case GEF_ANFORDERUNG_KONFIG_ZEG: + case GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG: + case GEF_TREFFEREREIGNIS_GEBAEUDE: + case GEF_TEILNEHMERMODE_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_SCHIEDSRICHTEREINGRIFF: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + gef_selektive_aufmunitionierung_rt selektive_aufmunitionierung; + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + gef_sanitetsdienst_instandsetzung_rt sanitetsdienst_instandsetzung; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + gef_bestandmseldung_sanitatsmaterial_rt bestandmseldung_sanitatsmaterial; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + gef_sanitetsdienst_instandsetzung_pvsan_rt sanitetsdienst_instandsetzung_pvsan; + case GEF_TECHNIK_FUNKTIONSRAUM: + gef_technik_funktionsraum_rt technik_funktionsraum; + case GEF_UMGEBUNGS_MELDUNG: + gef_umgebungs_meldung_rt umgebungs_meldung; + + case GEF_UMGEBUNGS_MELDUNG2: + gef_umgebungs_meldung2_rt umgebungs_meldung2; + + case GEF_AUFFORDERUNG_BITE_MELDUNG: + gef_aufforderung_bite_meldung_rt aufforderung_bite_meldung; + + case GEF_LIZENSIERUNG_TNE: + gef_lizensierung_tne_meldung_rt linzensierung_tne_meldung; + + case GEF_KONFIGURATION_TEILNEHMER: + gef_konfiguration_teilnehmer_rt konfiguration_teilnehmer; + + case GEF_KONFIGURATION_WIRKMODELL: + gef_konfiguration_wirkmodell_rt konfiguration_wirkmodell; + + case GEF_TEILNEHMERMODE_SETZEN: + gef_teilnehmermode_setzen_rt teilnehmermode_setzen; + + case GEF_TEILNEHMERMODE_MELDUNG: + gef_teilnehmermode_meldung_rt teilnehmermode_meldung; + + case GEF_TEILNEHMER_KONFIG_SETZEN: + gef_teilnehmer_konfig_setzen_rt teilnehmer_konfig_setzen; + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + gef_teilnehmer_konfig_antwort_rt teilnhemer_konfig_antwort; + +/* case GEF_POSITIONSKORREKTURDATEN: + */ + + case GEF_WIRKFELD_EINZELGESCHOSS: + gef_wirkfeld_einzelgeschoss_meldung_rt wirkfeld_einzelgeschoss_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + gef_wirkfeld_flaechendeckendes_feuer_meldung_rt wirkfeld_flaechendeckendes_feuer_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt wirkfeld_flaechendeckendes_feuer_stop_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung; + + case GEF_WIRKFELD_MINENSPERRE: + gef_wirkfeld_minensperre_meldung_rt wirkfeld_minensperre_meldung; + + case GEF_WIRKFELD_STATUS_MINENSPERRE: + gef_wirkfeld_status_minensperre_meldung_rt wirkfeld_status_minensperre_meldung; + + case GEF_WIRKFELD_A_KAMPFMITTEL: + gef_wirkfeld_a_kampfmittel_meldung_rt wirkfeld_a_kampfmittel_meldung; + + case GEF_WIRKFELD_C_KAMPFSTOFF: + gef_wirkfeld_c_kampfstoff_meldung_rt wirkfeld_c_kampfstoff_meldung; + + case GEF_DEAKTIVIERUNG_WIRKFELD: + gef_deaktivierung_wirkfeld_meldung_rt deaktivierung_wirkfeld_meldung; + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + gef_wirkfeld_aenderung_bezeichner_meldung_rt wirkfeld_aenderung_bezeichner_meldung; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + gef_deaktivierung_einzelmine_meldung_rt deaktivierung_einzelmine_meldung; + + case GEF_REAKTIVIERUNG_DUS_MINE: + gef_reaktivierung_dus_mine_meldung_rt reaktivierung_dus_mine_meldung; + + case GEF_DEFINITION_IED: + gef_definition_ied_rt definition_ied; + + case GEF_ZUSTAND_IED: + gef_zustand_ied_rt zustand_ied; + + case GEF_STATUS_EINZELMINENSIMULATOR: + gef_status_einzelminensimulator_rt status_einzelminensimulator_rt; + + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + gef_wirkfeld_einzelminensimulator_rt wirkfeld_einzelminensimulator_rt; + + case GEF_TREFFER_AUSLOESUNG: + gef_treffer_ausloesung_meldung_rt treffer_ausloesung_meldung; + + case GEF_FUNKTIONSRAUM: + gef_funktionsraum_meldung_rt funktionsraum_meldung; + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + gef_deaktivieren_funktionsraum_meldung_rt deaktivieren_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_SRT: + gef_datenverkehr_tds_srt_meldung_rt datenverkehr_tds_srt_meldung; + + case GEF_DATENVERKEHR_TDS_DMF: + gef_datenverkehr_tds_dmf_meldung_rt datenverkehr_tds_dmf_meldung_meldung; + + case GEF_STEUERUNG_VERKEHRSAUFKOMMEN: + gef_steuerung_verkehrsaufkommen_meldung_rt steuerung_verkehrsaufkommen_meldung; + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + gef_nachforderung_broadcast_telegramme_meldung_rt nachforderung_broadcast_telegramme_meldung; + + case GEF_NOP: + gef_nop_meldung_rt nop_meldung; + + case GEF_SPRACHAUSWAHL: + gef_sprachauswahl_meldung_rt sprachauswahl_meldung; + + case GEF_ALLGEMEINE_NACHRICHT: + gef_allgemeine_nachricht_meldung_rt allgemeine_nachricht_meldung; + +/* case GEF_ECHO_ON_OFF: + case GEF_ESW_MELDUNG: + case GEF_GEFECHTSFELDTELEGRAMM: */ + + case GEF_WF_SAMMELDEAKTIVIERUNG: + gef_wf_sammeldeaktivierung_meldung_rt wf_sammeldeaktivierung_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + gef_wf_sammeldeaktivierung_dus_minen_meldung_rt wf_sammeldeaktivierung_dus_minen_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt wf_sammeldeaktivierung_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_GEOP: + gef_datenverkehr_tds_geop_meldung_rt datenverkehr_tds_geop_meldung; + + case GEF_DATENVERKEHR_TDS_TGTS: + gef_datenverkehr_tds_tgts_meldung_rt datenverkehr_tds_tgts_meldung; + + case GEF_KONFIGURATION_IPS: + gef_konfiguration_ips_meldung_rt konfiguration_ips_meldung; + + case GEF_KONFIGURATION_ZEG: + gef_konfiguration_zeg_meldung_rt konfiguration_zeg_meldung; + + case GEF_AUSLOESUNG_DUS_TREFFER: + gef_ausloesung_dus_treffer_rt gef_ausloesung_dus_treffer; + + case GEF_ANFORDERUNG_SW_VERSION: + gef_anforderung_sw_version_rt anforderung_sw_version; + case GEF_SW_VERSIONSMELDUNG: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + gef_treffer_ereignis_sekundaerwirkung_rt treffer_ereignis_sekundaerwirkung; + + case GEF_NOTRUF: + gef_notruf_rt notruf; + + default: + void; +}; + +/* +struct dafu_tele { + u_long telegramm_zaehler; + unsigned short telegramm_prioritaet; + gef_tg_nd_ daten; +}; +*/ diff --git a/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp b/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp new file mode 120000 index 000000000..22f709a79 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView_guez.cpp @@ -0,0 +1 @@ +zsksxd_tetraForLogView_guez.x \ No newline at end of file diff --git a/TetraIF/LogView/zsksxd_tetraForLogView_guez.x b/TetraIF/LogView/zsksxd_tetraForLogView_guez.x new file mode 100644 index 000000000..68d6bcee7 --- /dev/null +++ b/TetraIF/LogView/zsksxd_tetraForLogView_guez.x @@ -0,0 +1,1839 @@ +/* +const MAX_LAENGE_GEFECHTSFELDTELEGRAMM = 2000; +*/ + +/*-------------------------------*/ +/* Telegramm-ID's */ +/*-------------------------------*/ + +enum8 gef_telegramm_id_et { + + GEF_BESTAETIGUNG = 0, + + GEF_INIT = 1, + GEF_MANIPULATIONSMELDUNG = 2, + GEF_UMGEBUNGS_MELDUNG = 3, + GEF_UMGEBUNGS_MELDUNG2 = 203, + GEF_AUFFORDERUNG_BITE_MELDUNG = 4, + GEF_BITE_MELDUNG = 5, + GEF_BITE_MELDUNG2 = 205, + + GEF_LIZENSIERUNG_TNE = 6, + GEF_BETRIEBSZUSTAND_AUSSTATTUNG = 7, + GEF_KONFIGURATION_TEILNEHMER = 8, + GEF_KONFIGURATION_WIRKMODELL = 9, + GEF_ANFORDERUNG_KONFIGURATIONSDATEN = 10, + GEF_KONFIGURATIONSMELDUNG = 11, + GEF_FEHLERMELDUNG_GFD = 12, + + GEF_POSITIONS_MELDUNG = 21, + GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER = 22, + GEF_POSITIONS_MELDUNG_LFZ = 23, + GEF_POSITIONSKORREKTURDATEN = 24, + + GEF_WIRKFELD_EINZELGESCHOSS = 31, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER = 32, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP = 33, + GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN = 34, + GEF_WIRKFELD_MINENSPERRE = 35, + GEF_WIRKFELD_STATUS_MINENSPERRE = 36, + GEF_WIRKFELD_A_KAMPFMITTEL = 37, + GEF_WIRKFELD_C_KAMPFSTOFF = 38, + GEF_DEAKTIVIERUNG_WIRKFELD = 39, + GEF_WIRKFELD_AENDERUNG_BEZEICHNER = 40, + GEF_DEAKTIVIERUNG_EINZELMINE = 41, + GEF_REAKTIVIERUNG_DUS_MINE = 42, + GEF_DEFINITION_IED = 43, + GEF_ZUSTAND_IED = 44, + GEF_STATUS_EINZELMINENSIMULATOR = 45, + GEF_WIRKFELD_EINZELMINENSIMULATOR = 46, + + GEF_FEUER_EREIGNIS = 51, + GEF_TREFFER_EREIGNIS_DUS = 52, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION = 53, + GEF_TREFFER_AUSLOESUNG = 54, + GEF_SCHIEDSRICHTEREINGRIFF = 55, + GEF_SELEKTIVE_AUFMUNITIONIERUNG = 56, + + GEF_TREFFER_EREIGNIS_DUS_IPS = 228, + GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS = 229, + + GEF_TAKTISCHER_STATUS = 61, + GEF_FUNKTIONSRAUM = 62, + GEF_EINTRETEN_FUNKTIONSRAUM = 63, + GEF_DEAKTIVIEREN_FUNKTIONSRAUM = 64, + + GEF_DATENVERKEHR_SRT_TDS = 71, + GEF_DATENVERKEHR_TDS_SRT = 72, + GEF_DATENVERKEHR_DMF_TDS = 73, + GEF_DATENVERKEHR_TDS_DMF = 74, + + GEF_STEUERUNG_VERKEHRSAUFKOMMEN = 81, + GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME = 82, + GEF_NOP = 83, + + GEF_SONDERSENSORIK_BETRIEBSZUSTAND = 91, + GEF_SONDERSENSORIK_FAHRSPUR = 92, + GEF_SONDERSENSORIK_DATEN = 93, + GEF_SONDERSENSORIK_TREFFER_AUFGES_TLN = 94, + GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN = 95, + GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN = 96, + GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION = 97, + + GEF_SPRACHAUSWAHL = 101, + GEF_ALLGEMEINE_NACHRICHT = 102, + GEF_ECHO_ON_OFF = 103, + GEF_ESW_MELDUNG = 104, + + GEF_WF_SAMMELDEAKTIVIERUNG = 105, + GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN = 106, + GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM = 107, + + GEF_DATENVERKEHR_GEOP_TDS = 181, + GEF_DATENVERKEHR_TDS_GEOP = 182, + + GEF_DATENVERKEHR_TGTS_TDS = 183, + GEF_DATENVERKEHR_TDS_TGTS = 184, + GEF_GERAETEEREIGNIS = 185, + + GEF_WAFFENZUORDNUNG = 200, + GEF_IPS_POSITIONSDATEN = 201, + GEF_STANDORTBESTIMMUNG = 25, + GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE = 202, + GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG = 210, + GEF_AUSLOESUNG_DUS_TREFFER = 211, + GEF_ANFORDERUNG_SW_VERSION = 212, + GEF_SW_VERSIONSMELDUNG = 213, + + GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG = 218, + GEF_TECHNIK_FUNKTIONSRAUM = 219, + GEF_ANFORDERUNG_KONFIG_ZEG = 220, + GEF_KONFIGURATION_IPS = 221, + GEF_KONFIGURATION_ZEG = 222, + GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG = 223, + GEF_TREFFEREREIGNIS_GEBAEUDE = 224, + + GEF_TEILNEHMERMODE_SETZEN = 230, + GEF_TEILNEHMERMODE_MELDUNG = 231, + GEF_TEILNEHMERMODE_ANFORDERN = 232, + GEF_TEILNEHMER_KONFIG_ANTWORT = 233, + GEF_TEILNEHMER_KONFIG_SETZEN = 234, + GEF_TEILNEHMER_KONFIG_ANFORDERN = 235, + + GEF_SANITAETSDIENST_INSTANDSETZUNG = 240, + GEF_BESTANDSMELDUNG_SANITAETSMATERIAL = 241, + GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN = 242, + + GEF_GEFECHTSFELDTELEGRAMM = 300, + GEF_UEBERLAST_WARNUNG_ENTWARNUNG = 301, + GEF_DATENFUNK_INIT = 302, + GEF_DATENFUNK_EXIT = 303, + GEF_DATENFUNK_EXIT_ACKNOWLEDGE = 304, + GEF_ZUORDNUNG_GRUPPENRUFADRESSE = 305, + GEF_NOTRUF = 1120 +}; + + +/*==============================================================*/ +/* Strukturtypen, die mehrfach verwendet werden */ +/*==============================================================*/ + +/*---------------------------------------*/ +/* Identifikation */ +/*---------------------------------------*/ + +typedef UInt16 gef_ausstattungs_id_t; + + +/*---------------------------------------*/ +/* Header */ +/*---------------------------------------*/ + +struct gef_header_rt { + gef_ausstattungs_id_t identitaet; +}; + + +/*---------------------------------------*/ +/* GPS-Zeit */ +/*---------------------------------------*/ + +struct gef_gps_zeit_rt { + u_int GPS_zeit; +}; + + +/*---------------------------------------*/ +/* GPS-Position */ +/*---------------------------------------*/ + +struct gef_gps_position_rt { + SInt24 nordwert; + SInt24 ostwert; +}; + + +/*---------------------------------------*/ +/* Lastzustand Datenfunk */ +/*---------------------------------------*/ + +enum8 gef_lastzustand_datenfunk_et { + Normallast = 0, + Hochlast = 1, + Ueberlast = 2 +}; + + +/*==============================================================*/ +/* Beschreibung der speziellen TETRA-Telegramme */ +/*==============================================================*/ + +struct TETRA_register_indication_rt { + UInt32LE ISSI_ext_host; +}; + +enum8 TETRA_registration_status_et { + ISSI_successful_registered = 0, + Duplicate_ISSI = 1, + Invalid_ISSI = 2, + Invalid_IP_address = 3 +}; + +struct TETRA_register_response_rt { + TETRA_registration_status_et registration_status; +}; + +enum8 TETRA_login_status_et { + Login_Request = 1, + Login_Accept = 2, + Login_Reject = 3 +}; + +enum8 TETRA_login_mastering_et { + No_Mastering = 0, + Mastering = 1 +}; + +enum8 TETRA_reject_cause_et { + Reserved = 0, + EqIdAlreadyAssigned = 1, + IssiAlreadyAssigned = 2, + EqIdAssignedInOtherExercise = 3 +}; + +struct TETRA_login_telegram_rt { + gef_header_rt header; + TETRA_login_status_et:0..1 login_status; + TETRA_login_mastering_et:2..2 login_mastering; + TETRA_reject_cause_et:3..6! reject_cause; +}; + +enum8 TETRA_telegram_type_et { + NotFragmented = 0, + FirstFragment = 1, + MiddleFragment = 3, + LastFragment = 2 +}; + +enum8 TETRA_fragment_counter_et { + 0 = 0, + 1 = 1, + 2 = 2, + 3 = 3, + 4 = 4, + 5 = 5, + 6 = 6, + 7 = 7, + 8 = 8, + 9 = 9, + 10 = 10, + 11 = 11, + 12 = 12, + 13 = 13, + 14 = 14, + 15 = 15 +}; + +struct TETRA_first_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + gef_telegramm_id_et telegram_id; + opaque data<28>; /* 28 => dyn.-array-offset */ +}; + +struct TETRA_middle_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_last_fragment_rt { + TETRA_telegram_type_et:0..1 telegram_type; + TETRA_fragment_counter_et:4..7! fragment_counter; + opaque data<27>; /* 27 => dyn.-array-offset */ +}; + +struct TETRA_air_interface_load_report_rt { + UInt8 network_index; + UInt16LE base_station_ID; + UInt8 channel_ID; + UInt8 queue_length; +}; + +struct TETRA_status_ind_req_rt { + UInt32LE ISSI_host; + UInt32LE ISSI_destination; + UInt32LE status; +}; + +enum8 TETRA_monitor_et { + No_Monitoring = 0, + Monitoring = 1 +}; + +struct TETRA_group_monitoring_ind_rt { + UInt32LE ISSI_host; + TETRA_monitor_et monitor; + UInt16LEIdx count_gssi; + UInt32LE gssi<5>; +}; + +struct TETRA_air_interface_load_req_rt { + UInt16LEIdx number_of_reports; + TETRA_air_interface_load_report_rt air_interface_load_report<4>; +}; + +struct TETRA_unknown_PDU_rt { + UInt8 magic_number; + UInt8 counter; + UInt16LE length; + UInt8 PDU_Type; + opaque data<5>; /* 5 => dyn.-array-offset */ +}; + + +/*==============================================================*/ +/* Beschreibung der Telegramme */ +/*==============================================================*/ + +/*----------------------------------------------------------------*/ +/* Automatische Conversion */ +/*----------------------------------------------------------------*/ +/* +Alle TETRA-Meldungen, die mit der Klasse CoPrtCnvTelegramConverter in +eine Zentral-Meldung konvertiert werden, müssen trotzdem in der TETRA- +union definiert werden, damit die Telegramme Namen bekommen. +*/ + +struct gef_automatic_conversion_rt { + gef_header_rt header; + UInt8 fehler_diese_meldung_sollte_automatisch_konvertiert_werden; +}; + + + +/*----------------------------------------------------------------*/ +/* Init-Meldung */ +/* INIT_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_tln_aufmunitionieren_et { + tln_am_nein = 0, + tln_am_ja = 1 +}; + +enum8 gef_tln_zuruecksetzen_et { + tln_zs_nein = 0, + tln_zs_ja = 1 +}; + +enum8 gef_tln_manipulation_et { + tln_mp_nein = 0, + tln_mp_reset = 1 +}; + +enum8 gef_tln_medizinische_vorraete_auffuellen_et { + tln_mv_nein = 0, + tln_mv_reset = 1 +}; + +/* MSB = 0 ... */ +struct gef_initialisierungsdaten_rt { + gef_tln_aufmunitionieren_et:2..2 tln_aufmunitionieren; + gef_tln_zuruecksetzen_et:1..1 tln_zuruecksetzen; + gef_tln_manipulation_et:7..7 tln_manipulation; + gef_tln_medizinische_vorraete_auffuellen_et:6..6 tln_mediziniesche_vorraete_auffuellen; +}; + +struct gef_init_meldung_rt { + gef_header_rt header; + gef_initialisierungsdaten_rt initialisierungsdaten; +}; + + +/*----------------------------------------------------------------*/ +/* Umgebungs-Meldung */ +/* UMGEBUNGS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_uebungspause_et { + KEINE_UEBUNGSPAUSE = 0, + B_MIT_TEST = 1 +}; + +enum8 gef_inhbit_time_et { + IH_UNDEFINED = 0, + IH_1_SEKUNDE = 1, + IH_2_SEKUNDEN = 2, + IH_3_SEKUNDEN = 3, + IH_4_SEKUNDEN = 4, + IH_5_SEKUNDEN = 5, + IH_6_SEKUNDEN = 6, + IH_7_SEKUNDEN = 7, + IH_8_SEKUNDEN = 8, + IH_9_SEKUNDEN = 9, + IH_10_SEKUNDEN = 10, + IH_11_SEKUNDEN = 11, + IH_12_SEKUNDEN = 12, + IH_13_SEKUNDEN = 13, + IH_14_SEKUNDEN = 14, + IH_15_SEKUNDEN = 15, + IH_16_SEKUNDEN = 16, + IH_17_SEKUNDEN = 17, + IH_18_SEKUNDEN = 18, + IH_19_SEKUNDEN = 19, + IH_20_SEKUNDEN = 20, + IH_21_SEKUNDEN = 21, + IH_22_SEKUNDEN = 22, + IH_23_SEKUNDEN = 23, + IH_24_SEKUNDEN = 24, + IH_25_SEKUNDEN = 25, + IH_26_SEKUNDEN = 26, + IH_27_SEKUNDEN = 27, + IH_28_SEKUNDEN = 28, + IH_29_SEKUNDEN = 29, + IH_30_SEKUNDEN = 30, + IH_31_SEKUNDEN = 31 +}; + +struct gef_betriebszustaende_gefechtsfeld_rt { + gef_uebungspause_et:0..0 uebungspause; + gef_inhbit_time_et:1..5 pos_inhibit_time; + gef_lastzustand_datenfunk_et:6..7! lastzustand_datenfunk; +}; + +struct gef_basiskoordinate_zur_positionsbestimmung_rt { + UInt8 zone; + string band; + string quadrat[2]; + UInt8 ostwert; + UInt8 nordwert; +}; + +struct gef_umgebungs_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; +}; + +struct gef_umgebungs_meldung2_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 uebungskennung; + UInt8 ruecksetzzaehler; + gef_betriebszustaende_gefechtsfeld_rt betriebszustaende_gefechtsfeld; + string zeitzone; + gef_basiskoordinate_zur_positionsbestimmung_rt basiskoordinate_zur_positionsbestimmung; + gef_gps_zeit_rt aktuelle_zeit; +}; + + +/*----------------------------------------------------------------*/ +/* Aufforderung BITE-Meldung */ +/* AUFFORDERUNG_BITE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_bite_meldungsart_et { + NUR_STATUSABFRAGE = 0, + ERST_SELBSTTEST = 1 +}; + +struct gef_aufforderung_bite_meldung_rt { + gef_header_rt header; + gef_bite_meldungsart_et bite_meldungsart; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration Wirkmodell */ +/* GEF_KONFIGURATION_WIRKMODELL */ +/*----------------------------------------------------------------*/ + +struct gef_wirkmodell_rt { + UInt8 minen_ied; + UInt8 steilfeuer; + UInt8 einsatzmittel; + UInt8 ac_waffen; +}; + +struct gef_konfiguration_wirkmodell_rt { + gef_header_rt header; + gef_wirkmodell_rt wirkmodelle; +}; + +/*----------------------------------------------------------------*/ +/* Konfigurationsmeldung */ +/* GEF_KONFIGURATION_TEILNEHMER */ +/*----------------------------------------------------------------*/ + +struct gef_login_parameter_rt { + UInt8 wartezeit_versuche; + UInt8 anzahl_versuche; + UInt8 mastering_flag; +}; + +enum8 gef_sprache_et { + keine_aenderung = 0, + deutsch = 1, + englisch = 2, + franzoesisch = 3 +}; + +struct gef_konfiguration_abe_rt { + UInt8 sprachausgabe; + gef_sprache_et sprache; +}; + +struct gef_konfiguration_wirkdarstellung_rt { + UInt8 pyrotechnik; +}; + +enum8 gef_betriebsart_mhgr_sensorik_et { + BetriebAmAusbAusstgPers = 0, + BetriebAnSonstigenFzg = 2, + BetriebAnSrFahrzeug = 3 +}; + +struct gef_konfiguration_mhgr_sensorik_rt { + gef_betriebsart_mhgr_sensorik_et betriebsart; + UInt8 energiesparmodus; +}; + +enum8 gef_konfiguration_ss_fir_et { + keineKonfigurationFir = 0, + fir = 1, + firSpzMarder = 2 +}; + +enum8 gef_konfiguration_ss_minenverlegung_et { + keineKonfigurationMinenverlegung = 0, + MvAnh = 1, + Wmv = 2 +}; + +enum8 gef_konfiguration_ss_standard_et { + keineKonfigurationSsStandard = 0, + ZABC = 3, + CSF = 4, + PzBr = 5, + MRF = 7 +}; + +struct gef_konfiguration_sondersenoriken_rt { + gef_konfiguration_ss_fir_et fir; + gef_konfiguration_ss_minenverlegung_et minenverlegung; + gef_konfiguration_ss_standard_et standard; +}; + +enum8 gef_agdus_hw_modus_et { + ohneHelmOhneWeste = 1, + mitHelmOhneWeste = 2, + mitHelmMitWeste = 3 +}; + +enum8 gef_konfigurations_positionsupdate_et { + Fahrzeug = 0, + Person = 1, + Luftfahrzeug = 2 +}; + +struct gef_konfiguration_anzeige_rt { + UInt8 hauptgruppe; + UInt8 untergruppe; +}; + +struct gef_konfigurationsdaten_rt { + gef_ausstattungs_id_t identitaet; + UInt16 can_startup_zeit; + unsigned char teilnehmertyp; + gef_login_parameter_rt login_parameter; + UInt32LE can_geraete_konfiguration; + gef_konfiguration_abe_rt abe; + gef_konfiguration_wirkdarstellung_rt wirkdarstellung; + gef_konfiguration_mhgr_sensorik_rt mhgr_sensorik; + gef_konfiguration_sondersenoriken_rt sondersenrik; + gef_agdus_hw_modus_et agdus_hw_modus; + gef_konfigurations_positionsupdate_et positionsupdate; + gef_konfiguration_anzeige_rt anzeige; + UInt8 wirkmodellAgdus; +}; +% +struct gef_konfiguration_teilnehmer_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_konfigurationsdaten_rt konfiguration; + gef_wirkmodell_rt wirkmodelle; +}; +/*----------------------------------------------------------------*/ +/* Lizensierung TNE-Meldung */ +/* LIZENSIERUNG_TNE_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_lizenzierungsart_et { + ANMELDUNG_ERFOLGREICH = 0, + ANMELDUNG_ABGELEHNT = 1, + ABMELDUNG = 2 +}; + +struct gef_lizensierung_tne_meldung_rt { + gef_header_rt header; + gef_lizenzierungsart_et lizenzierungsart; + opaque fehlercode_lizenzierung[3]; +}; + +enum8 gef_qualifikation_et { + Undefiniert = 0, + Arzt = 1, + Sanitaeter = 2, + Ersthelfer = 3 +}; + +/*----------------------------------------------------------------*/ +/* Bestandsmeldung Saniätsmaterial */ +/* GEF_BESTANDSMELDUNG_SANITAETSMATERIAL */ +/*----------------------------------------------------------------*/ +struct gef_bestandmseldung_sanitatsmaterial_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt8 anzahl_sanmat; + UInt24 bestand_sanmaterialien; +}; + + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung PVSAN */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN */ +/*----------------------------------------------------------------*/ +struct gef_sanitetsdienst_instandsetzung_pvsan_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 massnahmen_getaetigt; + UInt16 id_behandelnder; + gef_qualifikation_et qualifikation; + UInt16 massnahmen_benoetigt; +}; + +/*----------------------------------------------------------------*/ +/* Technik Funktionsraum-Meldung */ +/* TECHNIK_FUNKTIONSRAUM */ +/*----------------------------------------------------------------*/ +struct gef_technik_funktionsraum_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; + UInt8 typ; + string wirkfeldbezeichner[8]; + gef_gps_position_rt zentrum; + UInt16 breite; + UInt16 hoehe; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelgeschoss-Meldung */ +/* WIRKFELD_EINZELGESCHOSS_MELDUNG */ +/*----------------------------------------------------------------*/ + + +enum8 gef_munitionsart_steilfeuer_et { + STEILFEUER_AZ = 1, + STEILFEUER_HE_ANNZ = 2, + STEILFEUER_BOMBLET = 3, + STEILFEUER_SM_ART = 4, + STEILFEUER_NEBEL = 5, + MOERSER_AZ = 10, + MOERSER_ANNZ = 11, + BORDKANONE = 20, + UNGEL_RAKETE = 21, + BOMBLET = 22, + SPRENGBOMBE = 23 +}; +struct gef_beschreibung_wirkfeld_einzelgeschoss_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt einschlagort; + UInt8 wirkdurchmesser; + gef_munitionsart_steilfeuer_et munitionsart; +}; + +struct gef_wirkfeld_einzelgeschoss_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_einzelgeschoss_rt beschreibung_wirkfeld_einzelgeschoss; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 wirkfeldbreite; + UInt8 wirkfeldtiefe; + UInt16 drehwinkel_alt; + UInt8 mtpbreite; + UInt8 mtpdtiefe; + UInt16 drehwinkel; + UInt16 anzahl_einschlaege; + UInt16 wirkfeldradius; + gef_munitionsart_steilfeuer_et munitionsart; + UInt8 gefahrenabstand; + UInt8 gefahrenart; + gef_gps_position_rt mtp1; + gef_gps_position_rt mtp2; + gef_gps_position_rt mtp3; + gef_gps_position_rt mtp4; + +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_rt beschreibung_wirkfeld_flaechendeckendes_feuer; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Stop-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_STOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Flächendeckes Feuer-Feuer Fortsetzen-Meldung */ +/* WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt { + UInt16 wirkfeldkennung; + UInt16 fortsetzungswert_zufallszahl; + UInt16 nummer_des_naechsten_einschags; + gef_gps_zeit_rt fortsetzungszeit; + UInt16 verbleibende_wirkdauer; +}; + +struct gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen_rt beschreibung_wirkfeld_flaechendeckendes_feuer_fortsetzen; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Minensperre-Meldung */ +/* WIRKFELD_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_minentyp_et { + SchtzAbwMi_DUS = 211, + SchtzAbVMi_DUS = 212, + PzAbwVMi_DUS = 213, + SchtzAbwMi_virtuell = 214, + PzAbwVMi_virtuell = 215, + PzAbwWMi_virtuell = 216, + PzAbwRiMi_AGDUS = 60 +}; + +struct gef_segment_rt { + gef_gps_position_rt startpunkt; + gef_gps_position_rt endpunkt; +}; + +struct gef_beschreibung_wirkfeld_minensperre_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt wirkfeldeckpunkt; + UInt8 verlegetiefe; + UInt8 verlegedichte; + gef_minentyp_et minentyp; + UInt16 minenanzahl; + UInt8Idx anzahl_segmente; + gef_segment_rt segment<5>; +}; + +struct gef_wirkfeld_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_minensperre_rt beschreibung_wirkfeld_minensperre; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Status Minensperre-Meldung */ +/* WIRKFELD_STATUS_MINENSPERRE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_minenstatus_rt { + UInt16 wirkfeldkennung; + UInt16IdxDiv8 anzahl_minen; + opaque minenstatus<150>; +}; + +struct gef_wirkfeld_status_minensperre_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_minenstatus_rt beschreibung_minenstatus; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld A-Kampfmittel-Meldung */ +/* WIRKFELD_A_KAMPFMITTEL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_wirkfeld_a_kampfmittel_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt16 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt16 kantenlaenge_bereich_1; + UInt16 kantenlaenge_bereich_2; + UInt16 oeffnungswinkel; + UInt16 drehwinkel; +}; + +struct gef_wirkfeld_a_kampfmittel_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_a_kampfmittel_rt beschreibung_wirkfeld_a_kampfmittel; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld C-Kampfstoff-Meldung */ +/* WIRKFELD_C_KAMPFSTOFF_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_kampfstofftyp_et { + fluechtig = 1, + sesshaft = 2 +}; + +struct gef_beschreibung_wirkfeld_c_kampfstoff_rt { + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; + UInt8 partei_id; + gef_gps_zeit_rt wirkbeginn; + UInt8 wirkdauer; + gef_gps_position_rt einschlagort; + UInt16 radius; + UInt8 vergroesserungsfaktor; + UInt16 windrichtung; + UInt8 windgeschwindigkeit; + gef_gps_zeit_rt gueltigkeitszeitpunkt_wetterdaten; + gef_gps_position_rt position_gueltigkeitszeitpunkt_wetterdaten;; + UInt8 kampfstoffkennung; + gef_kampfstofftyp_et kampfstofftyp; +}; + +struct gef_wirkfeld_c_kampfstoff_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_wirkfeld_c_kampfstoff_rt beschreibung_wirkfeld_c_kampfstoff; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung-Wirkfeld-Meldung */ +/* DEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_wirkfeldtyp_et { + Undefined = 0, + Minensperre = 1, + Steilfeuer_Flaeche = 2, + Steilfeuer_Einzel = 3, + A_Waffe = 4, + C_Waffe = 5, + Funktionsraum = 6, + TechnicalArea = 7, + DusSingleMineSimulator = 8, + GasPipeDetonation = 9, + SpecialArea = 10, + BeStillWarning = 11, + DangerZoneExplosion = 12, + AirSupport = 13 +}; + +struct gef_deaktivierung_wirkfeld_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Wirkfeld Aenderung Bezeichner-Meldung */ +/* WIRKFELD_AENDERUNG_BEZEICHNER_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_wirkfeld_aenderung_bezeichner_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt16 wirkfeldkennung; + string wirkfeldbezeichner[8]; +}; + + + +/*----------------------------------------------------------------*/ +/* Deaktivierung Einzelmine-Meldung */ +/* DEAKTIVIERUNG_EINZELMINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivierung_einzelmine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_gps_zeit_rt GPS_Zeit; + UInt16 wirkfeldkennung; + UInt16 minenindex; +}; + + + +/*----------------------------------------------------------------*/ +/* Reaktivierung DUS Mine-Meldung */ +/* REAKTIVIERUNG_DUS_MINE_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_Minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_reaktivierung_dus_mine_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_dus_minenkennungen_rt DUS_minenkennungen; +}; + +/*----------------------------------------------------------------*/ +/* Definition-IED */ +/* DEFINITION_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_typ_et { + S_IED = 1, + IED_innen = 2, + IED_aussen = 3 +}; + +enum8 gef_ied_kopplungsstatus_et { + IED_keine_Kopplung = 1, + IED_Kopplung_an_Tln = 2, + IED_Kopplung_an_IPS = 3 +}; + +enum8 gef_ied_takitscher_zustand_et { + IED_inaktiv = 0, /* verlegt und gesichert */ + IED_aktiv = 1, /* scharf */ + IED_geloescht = 2, /* entschaerft */ + IED_ausgeloest_Schalter = 3, + IED_ausgeloest_Fernbedienung = 4, + IED_ausgeloest_Lichtschranke = 5, + IED_ausgeloest_Zugdraht = 6, + IED_ausgeloest_Kontrollgeraet = 7, + IED_unbekannt = 255 /* Kontakt verloren */ +}; + +struct gef_definition_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_typ_et typ; + UInt8 ausloeser; + UInt8 sprengkraft; + gef_gps_position_rt gps_position; + UInt8 partei_id; + gef_ied_kopplungsstatus_et kopplungsstatus; + gef_ausstattungs_id_t gekoppelte_id; + gef_ied_takitscher_zustand_et taktischer_zustand; /* 0 inaktiv, 1 aktiv */ + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ +}; + +/*----------------------------------------------------------------*/ +/* Zustand-IED */ +/* ZUSTAND_IED */ +/*----------------------------------------------------------------*/ + +enum8 gef_ied_fehler_et { + IED_kein_Fehler = 0, + IED_Kommunikations_Fehler = 1 +}; + +struct gef_zustand_ied_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 kennung; + gef_ied_takitscher_zustand_et taktischer_zustand; + UInt8 pyrotechnik; /* 0 keine Pyro, 1 mit Pyro */ + UInt8 batteriewarnung; /* Bitleiste */ + gef_ied_fehler_et fehler_status_elektronik; + gef_ied_fehler_et fehler_status_pyrotechnik1; + gef_ied_fehler_et fehler_status_pyrotechnik2; + gef_ied_fehler_et fehler_status_pyrotechnik3; +}; + + +/*----------------------------------------------------------------*/ +/* Treffer Ausloesung-Meldung */ +/* TREFFER_AUSLOESUNG_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_verwundung_beschaedigung_et { + Einsatzbereit = 0, + Leichter_Treffer = 1, + Mittlerer_Treffer = 2, + Schwerer_Treffer = 3, + Bewegungsunfaehig = 4, + Bewegungsunfaehig_sichtbar = 5, + Ausfall_Waffenanlage = 6, + Ausfall_Waffenanlage_sichtbar = 7, + Totalausfall_sichtbar = 8, + Zeitlicher_Ausfall = 9, + Annaehernder_Treffer = 10, + Treffer_ohne_Wirkung = 11 +}; + +struct gef_treffer_ausloesung_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_verwundung_beschaedigung_et verwundung_beschaedigung; +}; + +/*----------------------------------------------------------------*/ +/* Status Einzelminensimulator */ +/* STATUS_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_status_einzelminensimulator_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt16 minenkennung; + gef_gps_position_rt gps_position; + UInt8 minentyp; + UInt8 status; +}; + +/*----------------------------------------------------------------*/ +/* Wirkfeld Einzelminensimulator */ +/* WIRKFELD_EINZELMINENSIMULATOR */ +/*----------------------------------------------------------------*/ + +struct gef_beschreibung_einzelminensimulator_rt { + UInt16 wirkfeldkennung; + UInt8 partei_id; + UInt16 minenkennung; + gef_gps_zeit_rt wirkbeginn; + gef_gps_position_rt minenposition; + UInt8 minentyp; +}; + +struct gef_wirkfeld_einzelminensimulator_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_einzelminensimulator_rt beschreibung_einzelminensimulator; +}; + +/*----------------------------------------------------------------*/ +/* Schiedsrichtereingriff */ +/* SCHIEDSRICHTEREINGRIFF */ +/*----------------------------------------------------------------*/ +/* +struct gef_schiedsrichtereingriff_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_gps_position_rt gps_position; + UInt16 schiedsrichter_aktion; + UInt8 schiedsrichter; +}; + + + +/*----------------------------------------------------------------*/ +/* Selektive Aufmunitionierung */ +/* GEF_SELEKTIVE_AUFMUNITIONIERUNG */ +/*----------------------------------------------------------------*/ +struct gef_aufmunitionierung_rt { + UInt16 munitionsart; + UInt8 ort; /* Turm / Wanne */ + UInt16 neuer_vorrat; /* 0xffff = default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt16 neuer_default_vorrat; /* 0xffff = factory default, 0xfffe = unveraendert lassen, 0xfffd = unbegrenzt */ + UInt8 tracer_ratio; /* 0 = kein Trace, 1 = jedes Projektil, 2 = jedes 2. Projektil, ... */ +}; + +struct gef_selektive_aufmunitionierung_rt { + gef_header_rt header; + u_int waffen_id; + UInt8Idx anzahl_aufmunitionierungen; + gef_aufmunitionierung_rt aufmunitionierung<10>; +}; + +/*----------------------------------------------------------------*/ +/* SaniätsDienst Instandssetzung */ +/* GEF_SANITAETSDIENST_INSTANDSETZUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_behandlungs_ergebnis_et { + Keine = 0, + Erfolg = 1, + Stabilisiert = 2, + Fehler = 3 +}; + +struct gef_sanitetsdienst_instandsetzung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + UInt8 verurschaer_typ; + UInt16 ausstattung_behandelnder; + gef_verwundung_beschaedigung_et status_start; + UInt8 typ_der_behandlung; + UInt8 triage; + UInt8 typ_der_behandlung; + gef_verwundung_beschaedigung_et status_ergebnis; + gef_behandlungs_ergebnis_et ergebhnis_behandlung; + UInt8 triage_priorität; + UInt8 komplett_status; + UInt24 behandlungszeit; + UInt24 erholungszeit; +}; + + + +*/ +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +enum8 gef_betriebsmodus_et { + Nicht_vorhanden = 0, + Eingriff_durch_schiedsrichter = 1, + Wartezeit_nach_Erreichen_des_Funktionsraums = 2 +}; + +struct gef_funktionsraum_rt { + gef_betriebsmodus_et betriebsmodus; + UInt8 wartezeit; +}; + +struct gef_beschreibung_funktionsraum_rt { + UInt16 funktionsraumkennung; + string funktionsraumbezeichner[8]; + UInt8 partei_id; + gef_gps_position_rt funktionsraumeckpunkt; + UInt8 funktionsraumbreite; + UInt8 funktionsraumtiefe; + gef_funktionsraum_rt funktionsraum_fuer_entgiftungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_instandsetzungsmassnahmen; + gef_funktionsraum_rt funktionsraum_fuer_sandienstliche_versorgung; +}; + +struct gef_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_beschreibung_funktionsraum_rt beschreibung_funktionsraum; +}; + + + +/*----------------------------------------------------------------*/ +/* Funktionsraum-Meldung */ +/* FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_deaktivieren_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + UInt16 funktionsraumkennung; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-SRT-Meldung */ +/* DATENVERKEHR_TDS_SRT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_fuer_tne_transparente_daten_rt { + opaque data<30>; /* 30 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_srt_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-DMF-Meldung */ +/* DATENVERKEHR_TDS_DMF_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_datenverkehr_tds_dmf_meldung_rt { + gef_header_rt header; + gef_fuer_tne_transparente_daten_rt fuer_TNE_transparente_daten; +}; + + + +/*----------------------------------------------------------------*/ +/* Steuerung Verkehrsaufkommen-Meldung */ +/* STEUERUNG_VERKEHRSAUFKOMMEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_steuerung_verkehrsaufkommen_meldung_rt { + gef_header_rt header; + gef_lastzustand_datenfunk_et lastzustand_datenfunk; + UInt16 inhibit_zeit_fuer_positionsmeldungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Nachforderung Broadcast Telegramme-Meldung */ +/* NACHFORDERUNG_BROADCAST_TELEGRAMME_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachforderung_broadcast_telegramme_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + UInt8 ruecksetzzaehler; + UInt16 broadcast_index; +}; + + + +/*----------------------------------------------------------------*/ +/* Nop-Meldung */ +/* NOP_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_broadcasttelegramme_rt { + UInt16 feld_anfang; + UInt16 feld_ende; +}; + +struct gef_nop_meldung_rt { + gef_header_rt header; + gef_broadcasttelegramme_rt broadcasttelegramme; +}; + + + +/*----------------------------------------------------------------*/ +/* Sprachauswahl-Meldung */ +/* SPRACHAUSWAHL_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_sprachauswahl_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sprache_et sprachauswahl; +}; + + + +/*----------------------------------------------------------------*/ +/* Allgemeine Nachricht-Meldung */ +/* ALLGEMEINE_NACHRICHT_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_nachricht_rt { + UInt8Idx laenge; + string text<80>; +}; + +struct gef_allgemeine_nachricht_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_nachricht_rt nachricht; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Wirkfeld-Meldung */ +/* SAMMELDEAKTIVIERUNG_WIRKFELD_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_wirkfeldkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 wirkfeldkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_wirkfeldkennungen_rt liste_der_wirkfeldkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung DUS-Minen-Meldung */ +/* SAMMELDEAKTIVIERUNG_DUS_MINEN_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_dus_minenkennungen_rt { + UInt16Idx anzahl_DUS_minen; + UInt16 kennung_DUS_Mine<500>; +}; + +struct gef_wf_sammeldeaktivierung_dus_minen_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_dus_minenkennungen_rt liste_DUS_minenkennungen; +}; + + + +/*----------------------------------------------------------------*/ +/* Sammeldeaktivierung Funktionsraum-Meldung */ +/* SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM_MELDUNG */ +/*----------------------------------------------------------------*/ + +struct gef_liste_funktionsraumkennungen_rt { + UInt8Idx anzahl_kennungen; + UInt16 funktionsraumkennung<100>; +}; + +struct gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_liste_funktionsraumkennungen_rt liste_der_funktionsraumkennungen; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-GeoP-Meldung */ +/* DATENVERKEHR_TDS_GEOP_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_geop_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_geop_meldung_rt { + gef_header_rt header; + UInt8 laenge_GeoP_Daten; + gef_geop_daten_rt geop_daten; +}; + + +/*----------------------------------------------------------------*/ +/* Datenverkehr TDS-TgtS-Meldung */ +/* DATENVERKEHR_TDS_TGTS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_tgts_daten_rt { + opaque data<31>; /* 31 => dyn.-array-offset */ +}; + +struct gef_datenverkehr_tds_tgts_meldung_rt { + gef_header_rt header; + UInt8 laenge_tgts_Daten; + gef_tgts_daten_rt tgts_daten; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration IPS-Meldung */ +/* KONFIGURATION_IPS_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zuordnung_rt { + UInt16 raumnummer_des_gebaeudemodell; + UInt16 IPS_Platz_des_gebaeudemodell; + UInt16 IPS_Kennung; +}; + +struct gef_ips_konfiguration_rt { + UInt8Idx anzahl; + gef_zuordnung_rt zuordnung<255>; +}; + +struct gef_konfiguration_ips_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_ips_konfiguration_rt ips_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG */ +/*----------------------------------------------------------------*/ +struct gef_treffer_ereignis_sekundaerwirkung_rt { + gef_header_rt header; + gef_gps_zeit_rt wirkbeginn; + UInt16 munCode; + UInt16 verursacher; + gef_wirkfeldtyp_et wirkfeldtyp; + UInt8 effectCode; + UInt16 minenIndex; + UInt16 unused; +}; + +/*----------------------------------------------------------------*/ +/* Konfiguration ZEG-Meldung */ +/* KONFIGURATION_ZEG_MELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_zeg_zuordnung_rt { + UInt16 referenzmodul_des_gebaeudemodell; + UInt16 ZEG_Kennung; +}; + +struct gef_zeg_konfiguration_rt { + UInt8Idx anzahl; + gef_zeg_zuordnung_rt zeg_zuordnung<255>; +}; + +struct gef_konfiguration_zeg_meldung_rt { + gef_header_rt header; + UInt16 gebaeudemodell; + gef_zeg_konfiguration_rt zeg_konfiguration; +}; + +/*----------------------------------------------------------------*/ +/* Ausloseung DUS-Treffer */ +/* GEF_AUSLOESUNG_DUS_TREFFER */ +/*----------------------------------------------------------------*/ +struct gef_ausloesung_dus_treffer_rt { + gef_header_rt header; + gef_gps_zeit_rt zeit; + UInt8Idx munitionsart; + UInt16 richtung; + UInt16 entfernung; + UInt8Idx wirkung; + UInt16 verursacher; +}; +/*----------------------------------------------------------------*/ +/* GEF_ANFORDERUNG_SW_VERSION */ +/* GEF_SW_VERSIONSMELDUNG */ +/*----------------------------------------------------------------*/ +struct gef_anforderung_sw_version_rt { + gef_header_rt header; + UInt16 geraetekennung; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_SETZEN (Zentrale -> SFM) */ +/*----------------------------------------------------------*/ +enum8 gef_tln_sprache_et { + TLN_SPRACHE_KEINE_AENDERUNG = 0, + TLN_SPRACHE_DE = 1, + TLN_SPRACHE_EN = 2, + TLN_SPRACHE_FR = 3, + TLN_SPRACHE_AR = 4, + TLN_SPRACHE_ES = 5, + TLN_SPRACHE_RU = 6 +}; + +enum8 gef_operation_mode_et { + OP_MODE_KEINE_AENDERUNG = 0, + OP_MODE_NORMAL = 1, + OP_MODE_BE_STILL = 2 +}; + +enum8 gef_wph_mode_weste_et { + WPH_MODE_WESTE_KEINE_AENDERUNG = 0, + WPH_MODE_WESTE_OHNE = 1, + WPH_MODE_WESTE_MIT = 2 +}; + +enum8 gef_wph_mode_helm_et { + WPH_MODE_HELM_KEINE_AENDERUNG = 0, + WPH_MODE_HELM_OHNE = 1, + WPH_MODE_HELM_MIT = 2 +}; + +enum8 gef_wph_mode_personenschutz_et { + WPH_MODE_PERSONENSCHUTZ_KEINE_AENDERUNG = 0, + WPH_MODE_PERSONENSCHUTZ_OHNE = 1, + WPH_MODE_PERSONENSCHUTZ_ANZUG = 2, + WPH_MODE_PERSONENSCHUTZ_ANZUG_HANDSCHUHE_SCHUHE = 3 +}; + +enum8 gef_schutzniveau_et { + SN_SCHUTZ_KEINE_AENDERUNG = 0, + SN_IDZ_ES = 1, + SN_IDZ_BS = 2, + SN_KSK = 3, + SN_SOLDAT_MIT_KOERPERSCHUTZ = 4, + SN_SOLDAT_DARSTELLER = 5 +}; + +enum8 gef_handgranaten_suche_et { + HS_KEINE_AENDERUNG = 0, + HS_SUCHE_AUS = 1, + HS_SUCHE_EIN = 2 +}; + +enum8 gef_international_mode_et { + IM_KEINE_AENDERUNG = 0, + IM_AUS = 1, + IM_EIN = 2 +}; + +/* Reaktivierung: in Minuten (0, 10 .. 2550) */ +struct gef_teilnehmermode_rt { + gef_tln_sprache_et sprache; + gef_operation_mode_et op_mode; + UInt8 reaktivierung_entgiftung; + UInt8 reaktivierung_inst; + UInt8 reaktivierung_sanitaet; + gef_wph_mode_personenschutz_et:1..3 mode_personenschutz; + gef_wph_mode_weste_et:4..5 mode_weste; + gef_wph_mode_helm_et:6..7! mode_helm; + gef_schutzniveau_et schutzniveau; + gef_handgranaten_suche_et:6..7! handgranaten_suche; + gef_international_mode_et:4..5 international_mode; +}; + +struct gef_teilnehmermode_setzen_rt { + gef_header_rt header; + UInt16 bcIndex; + gef_teilnehmermode_rt mode; +}; +/*----------------------------------------------------------*/ +/* TEILNEHMERMODE_MELDUNG (SFM -> Zentrale) */ +/*----------------------------------------------------------*/ +struct gef_teilnehmermode_meldung_rt { + gef_header_rt header; + gef_gps_zeit_rt gps_zeit; + gef_teilnehmermode_rt mode; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_SETZEN */ +/*----------------------------------------------------------------*/ + +enum8 gef_positions_handling_et { + POS_HANDLING_DEFAULT = 0, + POS_HANDLING_UNGUELTIG_NICHT_SCHICKEN = 1, + POS_HANDLING_UNGUELTIG_KENNZEICHNEN = 2, + POS_HANDLING_UNGUELTIG_SCHICKEN = 3 +}; + +enum8 gef_optischer_code_et { + OPTISCHER_CODE_KEINE_AENDERUNG = 0, + OPTISCHER_CODE_OSAG_1_0 = 1, + OPTISCHER_CODE_OSAG_2_0_BASIC = 2 +}; + +struct gef_sfm_konfig_rt { + UInt16 pos_aenderung_fz; + UInt16 pos_aenderung_personal; + UInt16 pos_aenderung_lfz; + UInt16 pos_uebertragungs_interval; + UInt16 hoehengrenze; + gef_positions_handling_et:6..7 positions_handling; + UInt8Idx:0..1! pos_interval_umschaltung; + UInt16 wartezeit_nachforderung; + UInt8 faktor_wartezeit_hochlast; + UInt8 wartezeit_vbg_1_2; + UInt8 wartezeit_vbg_2_3; + UInt8 wartezeit_vbg_3_8; + gef_optischer_code_et optischer_code; + UInt8 verwundungsmodel; + UInt8 gueltigkeitsdauer_standortbestimmung; +}; + +struct gef_teilnehmer_konfig_setzen_rt { + gef_header_rt header; + UInt16 broadcast_index; + gef_sfm_konfig_rt konfig; +}; + +/*----------------------------------------------------------------*/ +/* GEF_TEILNEHMER_KONFIG_ANTWORT */ +/*----------------------------------------------------------------*/ + +struct gef_teilnehmer_konfig_antwort_rt { + gef_header_rt header; + gef_gps_zeit_rt GPS_zeit; + gef_sfm_konfig_rt konfig; +}; + +/*-------------------------------------------------------*/ +/* GEF_NOTRUF */ +/*-------------------------------------------------------*/ + +struct gef_notruf_rt { + gef_gps_position_rt gps_position; +}; + +/*==============================================================*/ +/* Zusammenfassung der Telegramm-Typen */ +/*==============================================================*/ +union gef_tg_nd_ switch (gef_telegramm_id_et telegramm_id) { + + case GEF_INIT: + gef_init_meldung_rt init_meldung; + + case GEF_MANIPULATIONSMELDUNG: + case GEF_BITE_MELDUNG: + case GEF_BITE_MELDUNG2: + case GEF_BETRIEBSZUSTAND_AUSSTATTUNG: + case GEF_ANFORDERUNG_KONFIGURATIONSDATEN: + case GEF_FEHLERMELDUNG_GFD: + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_FEUER_EREIGNIS: + case GEF_TREFFER_EREIGNIS_DUS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION: + case GEF_FEUEREREIGNIS_MIT_WAFFENZUORDNUNG: + case GEF_TAKTISCHER_STATUS: + case GEF_TREFFER_EREIGNIS_DUS_IPS: + case GEF_TREFFER_EREIGNIS_WIRKSIMULATION_IPS: + case GEF_EINTRETEN_FUNKTIONSRAUM: + case GEF_DATENVERKEHR_SRT_TDS: + case GEF_DATENVERKEHR_DMF_TDS: + case GEF_SONDERSENSORIK_BETRIEBSZUSTAND: + case GEF_SONDERSENSORIK_FAHRSPUR: + case GEF_SONDERSENSORIK_DATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEDATEN: + case GEF_SONDERSENSORIK_WMIV_VERLEGEDATEN: + case GEF_SONDERSENSORIK_MIVANH_VERLEGEPOSITION: + case GEF_DATENVERKEHR_GEOP_TDS: + case GEF_DATENVERKEHR_TGTS_TDS: + case GEF_GERAETEEREIGNIS: + case GEF_WAFFENZUORDNUNG: + case GEF_IPS_POSITIONSDATEN: + case GEF_STANDORTBESTIMMUNG: + case GEF_MUNITIONSVORRAT_EINER_ZUGEORDNETEN_WAFFE: + case GEF_ANFORDERUNG_KONFIG_ZEG: + case GEF_TREFFEREREIGNIS_SEKUNDAERWIRKUNG: + case GEF_TREFFEREREIGNIS_GEBAEUDE: + case GEF_TEILNEHMERMODE_ANFORDERN: + case GEF_TEILNEHMER_KONFIG_ANFORDERN: + case GEF_SCHIEDSRICHTEREINGRIFF: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_SELEKTIVE_AUFMUNITIONIERUNG: + gef_selektive_aufmunitionierung_rt selektive_aufmunitionierung; + + case GEF_SANITAETSDIENST_INSTANDSETZUNG: + gef_sanitetsdienst_instandsetzung_rt sanitetsdienst_instandsetzung; + case GEF_BESTANDSMELDUNG_SANITAETSMATERIAL: + gef_bestandmseldung_sanitatsmaterial_rt bestandmseldung_sanitatsmaterial; + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + gef_sanitetsdienst_instandsetzung_pvsan_rt sanitetsdienst_instandsetzung_pvsan; + case GEF_TECHNIK_FUNKTIONSRAUM: + gef_technik_funktionsraum_rt technik_funktionsraum; + case GEF_UMGEBUNGS_MELDUNG: + gef_umgebungs_meldung_rt umgebungs_meldung; + + case GEF_UMGEBUNGS_MELDUNG2: + gef_umgebungs_meldung2_rt umgebungs_meldung2; + + case GEF_AUFFORDERUNG_BITE_MELDUNG: + gef_aufforderung_bite_meldung_rt aufforderung_bite_meldung; + + case GEF_LIZENSIERUNG_TNE: + gef_lizensierung_tne_meldung_rt linzensierung_tne_meldung; + + case GEF_KONFIGURATION_TEILNEHMER: + gef_konfiguration_teilnehmer_rt konfiguration_teilnehmer; + + case GEF_KONFIGURATION_WIRKMODELL: + gef_konfiguration_wirkmodell_rt konfiguration_wirkmodell; + + case GEF_TEILNEHMERMODE_SETZEN: + gef_teilnehmermode_setzen_rt teilnehmermode_setzen; + + case GEF_TEILNEHMERMODE_MELDUNG: + gef_teilnehmermode_meldung_rt teilnehmermode_meldung; + + case GEF_TEILNEHMER_KONFIG_SETZEN: + gef_teilnehmer_konfig_setzen_rt teilnehmer_konfig_setzen; + + case GEF_TEILNEHMER_KONFIG_ANTWORT: + gef_teilnehmer_konfig_antwort_rt teilnhemer_konfig_antwort; + +/* case GEF_POSITIONSKORREKTURDATEN: + */ + + case GEF_WIRKFELD_EINZELGESCHOSS: + gef_wirkfeld_einzelgeschoss_meldung_rt wirkfeld_einzelgeschoss_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + gef_wirkfeld_flaechendeckendes_feuer_meldung_rt wirkfeld_flaechendeckendes_feuer_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + gef_wirkfeld_flaechendeckendes_feuer_stop_meldung_rt wirkfeld_flaechendeckendes_feuer_stop_meldung; + + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + gef_wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung_rt wirkfeld_flaechendeckendes_feuer_fortsetzen_meldung; + + case GEF_WIRKFELD_MINENSPERRE: + gef_wirkfeld_minensperre_meldung_rt wirkfeld_minensperre_meldung; + + case GEF_WIRKFELD_STATUS_MINENSPERRE: + gef_wirkfeld_status_minensperre_meldung_rt wirkfeld_status_minensperre_meldung; + + case GEF_WIRKFELD_A_KAMPFMITTEL: + gef_wirkfeld_a_kampfmittel_meldung_rt wirkfeld_a_kampfmittel_meldung; + + case GEF_WIRKFELD_C_KAMPFSTOFF: + gef_wirkfeld_c_kampfstoff_meldung_rt wirkfeld_c_kampfstoff_meldung; + + case GEF_DEAKTIVIERUNG_WIRKFELD: + gef_deaktivierung_wirkfeld_meldung_rt deaktivierung_wirkfeld_meldung; + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + gef_wirkfeld_aenderung_bezeichner_meldung_rt wirkfeld_aenderung_bezeichner_meldung; + + case GEF_DEAKTIVIERUNG_EINZELMINE: + gef_deaktivierung_einzelmine_meldung_rt deaktivierung_einzelmine_meldung; + + case GEF_REAKTIVIERUNG_DUS_MINE: + gef_reaktivierung_dus_mine_meldung_rt reaktivierung_dus_mine_meldung; + + case GEF_DEFINITION_IED: + gef_definition_ied_rt definition_ied; + + case GEF_ZUSTAND_IED: + gef_zustand_ied_rt zustand_ied; + + case GEF_STATUS_EINZELMINENSIMULATOR: + gef_status_einzelminensimulator_rt status_einzelminensimulator_rt; + + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + gef_wirkfeld_einzelminensimulator_rt wirkfeld_einzelminensimulator_rt; + + case GEF_TREFFER_AUSLOESUNG: + gef_treffer_ausloesung_meldung_rt treffer_ausloesung_meldung; + + case GEF_FUNKTIONSRAUM: + gef_funktionsraum_meldung_rt funktionsraum_meldung; + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + gef_deaktivieren_funktionsraum_meldung_rt deaktivieren_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_SRT: + gef_datenverkehr_tds_srt_meldung_rt datenverkehr_tds_srt_meldung; + + case GEF_DATENVERKEHR_TDS_DMF: + gef_datenverkehr_tds_dmf_meldung_rt datenverkehr_tds_dmf_meldung_meldung; + + case GEF_STEUERUNG_VERKEHRSAUFKOMMEN: + gef_steuerung_verkehrsaufkommen_meldung_rt steuerung_verkehrsaufkommen_meldung; + + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + gef_nachforderung_broadcast_telegramme_meldung_rt nachforderung_broadcast_telegramme_meldung; + + case GEF_NOP: + gef_nop_meldung_rt nop_meldung; + + case GEF_SPRACHAUSWAHL: + gef_sprachauswahl_meldung_rt sprachauswahl_meldung; + + case GEF_ALLGEMEINE_NACHRICHT: + gef_allgemeine_nachricht_meldung_rt allgemeine_nachricht_meldung; + +/* case GEF_ECHO_ON_OFF: + case GEF_ESW_MELDUNG: + case GEF_GEFECHTSFELDTELEGRAMM: */ + + case GEF_WF_SAMMELDEAKTIVIERUNG: + gef_wf_sammeldeaktivierung_meldung_rt wf_sammeldeaktivierung_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + gef_wf_sammeldeaktivierung_dus_minen_meldung_rt wf_sammeldeaktivierung_dus_minen_meldung; + + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + gef_wf_sammeldeaktivierung_funktionsraum_meldung_rt wf_sammeldeaktivierung_funktionsraum_meldung; + + case GEF_DATENVERKEHR_TDS_GEOP: + gef_datenverkehr_tds_geop_meldung_rt datenverkehr_tds_geop_meldung; + + case GEF_DATENVERKEHR_TDS_TGTS: + gef_datenverkehr_tds_tgts_meldung_rt datenverkehr_tds_tgts_meldung; + + case GEF_KONFIGURATION_IPS: + gef_konfiguration_ips_meldung_rt konfiguration_ips_meldung; + + case GEF_KONFIGURATION_ZEG: + gef_konfiguration_zeg_meldung_rt konfiguration_zeg_meldung; + + case GEF_AUSLOESUNG_DUS_TREFFER: + gef_ausloesung_dus_treffer_rt gef_ausloesung_dus_treffer; + + case GEF_ANFORDERUNG_SW_VERSION: + gef_anforderung_sw_version_rt anforderung_sw_version; + case GEF_SW_VERSIONSMELDUNG: + gef_automatic_conversion_rt manipulations_meldung; + + case GEF_TREFFER_EREIGNIS_SEKUNDAERWIRKUNG: + gef_treffer_ereignis_sekundaerwirkung_rt treffer_ereignis_sekundaerwirkung; + + case GEF_NOTRUF: + gef_notruf_rt notruf; + + default: + void; +}; + +/* +struct dafu_tele { + u_long telegramm_zaehler; + unsigned short telegramm_prioritaet; + gef_tg_nd_ daten; +}; +*/ diff --git a/TetraIF/PrtCnv/AppComponent.cpp b/TetraIF/PrtCnv/AppComponent.cpp new file mode 100644 index 000000000..c81081775 --- /dev/null +++ b/TetraIF/PrtCnv/AppComponent.cpp @@ -0,0 +1,88 @@ + + + + + + + + + + + + + +#include "AppComponent.hpp" + +namespace N_AppComponent +{ + +int32_t AppComponent::create(NGL::Settings *settings) +{ + for (IAppComponent *c : m_Childs) + c->create(settings); + return 0; +} + + +int32_t AppComponent::destroy() +{ + for (IAppComponent *c : m_Childs) + c->destroy(); + return 0; +} + + +int32_t AppComponent::init() +{ + for (IAppComponent *c : m_Childs) + c->init(); + return 0; +} + + +int32_t AppComponent::deinit() +{ + for (IAppComponent *c : m_Childs) + c->deinit(); + return 0; +} + + +int32_t AppComponent::start() +{ + for (IAppComponent *c : m_Childs) + c->start(); + return 0; +} + + +int32_t AppComponent::stop() +{ + for (IAppComponent *c : m_Childs) + c->stop(); + return 0; +} + + +void AppComponent::addChild(IAppComponent *a_child, const QString &a_name) +{ + if (a_child) + { + a_child->setName(a_name); + m_Childs.push_back(a_child); + } +} + + +IAppComponent *AppComponent::getChild(const QString &a_name) +{ + for (IAppComponent *c : m_Childs) + { + if (a_name == c->getName()) + return c; + } + return nullptr; +} + +} + diff --git a/TetraIF/PrtCnv/AppComponent.hpp b/TetraIF/PrtCnv/AppComponent.hpp new file mode 100644 index 000000000..e129a0403 --- /dev/null +++ b/TetraIF/PrtCnv/AppComponent.hpp @@ -0,0 +1,45 @@ + + + + + + + + + + + + +#pragma once + +#include +#include "IAppComponent.hpp" +#include + +namespace NGL { +class Settings; +} + +namespace N_AppComponent +{ +class PRTCNVLIB_EXPORT AppComponent : public N_AppComponent::IAppComponent +{ +public: + AppComponent() = default; + ~AppComponent() = default; + + + int32_t create(NGL::Settings *settings) override; + int32_t deinit() override; + int32_t destroy() override; + int32_t init() override; + int32_t start() override; + int32_t stop() override; + +protected: + void addChild(IAppComponent* a_child, const QString& a_name = QString()); + IAppComponent* getChild(const QString& a_name); +private: + std::vector m_Childs; +}; +} diff --git a/TetraIF/PrtCnv/CMakeLists.txt b/TetraIF/PrtCnv/CMakeLists.txt new file mode 100644 index 000000000..9d01e7289 --- /dev/null +++ b/TetraIF/PrtCnv/CMakeLists.txt @@ -0,0 +1,78 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + + +#ADD_SUBDIRECTORY(TetraTestServer) +ADD_SUBDIRECTORY(LastTest) +ADD_SUBDIRECTORY(LastTestAuswertung) + +SET(PrtCnv_SRCS + logger.h + logger.cpp + + AppComponent.cpp + AppComponent.hpp + IAppComponent.hpp + PrtCnvApplication.cpp + PrtCnvApplication.hpp + PrtCnvBroadcastMgr.cpp + PrtCnvBroadcastMgr.hpp + PrtCnvCentralThread.cpp + PrtCnvCentralThread.hpp + PrtCnvDbThread.cpp + PrtCnvDbThread.hpp + PrtCnvInjectionSocket.cpp + PrtCnvInjectionSocket.hpp + PrtCnvInjectionThread.cpp + PrtCnvInjectionThread.hpp + PrtCnvMember.cpp + PrtCnvMember.hpp + PrtCnvRadioThread.cpp + PrtCnvRadioThread.hpp + PrtCnvRadioTrafficThread.cpp + PrtCnvRadioTrafficThread.hpp + PrtCnvSocketThread.cpp + PrtCnvSocketThread.hpp + PrtCnvStoredCentralTelegram.hpp + PrtCnvStoredRadioTelegram.hpp + PrtCnvStoredTelegram.hpp + PrtCnvTelegramLogThread.cpp + PrtCnvTelegramLogThread.hpp + PrtCnvThread.cpp + PrtCnvThread.hpp + PrtCnvThreadStarter.cpp + PrtCnvThreadStarter.hpp +) + +NGL_ADD_LIBRARY2(AAR SV PrtCnvLib SHARED ${PrtCnv_SRCS}) +NGL_TARGET_LINK_LIBRARIES(PrtCnvLib + PRIVATE + ngldb + nglsettings + LtsUtilsCoreHeaderOnly + Qt5::Sql + Qt5::WebSockets + PUBLIC + CoPrtCnv + Qt5::Core + Qt5::Network + NGLLogger +) +NGL_TARGET_INCLUDE_DIRECTORIES(PrtCnvLib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +NGL_ADD_EXECUTABLE(AAR SV PrtCnv PrtCnvMain.cpp) +NGL_TARGET_LINK_LIBRARIES(PrtCnv + PrtCnvLib + Qt5::Core + LtsCommandLineParser + nglcoreapplication +) +NGL_INSTALL_TARGET(PrtCnv) +NGL_INSTALL(AAR SV FILES log4cxx_prtcnv.props DESTINATION bin) +NGL_INSTALL(AAR SV FILES PrtCnv.dat.tts DESTINATION bin) diff --git a/TetraIF/PrtCnv/IAppComponent.hpp b/TetraIF/PrtCnv/IAppComponent.hpp new file mode 100644 index 000000000..44b7138c3 --- /dev/null +++ b/TetraIF/PrtCnv/IAppComponent.hpp @@ -0,0 +1,59 @@ + + + + + + + + + + + + +#pragma once + +#include + +namespace NGL { + class Settings; +} + +namespace N_AppComponent +{ + class IAppComponent + { + public: + IAppComponent() = default; + virtual ~IAppComponent() = default; + + virtual int32_t create(NGL::Settings *settings) = 0; + + + virtual int32_t deinit() = 0; + + + virtual int32_t destroy() = 0; + + + virtual int32_t init() = 0; + + + virtual int32_t start() = 0; + + + virtual int32_t stop() = 0; + + + inline const QString& getName() const + { + return m_Name; + } + inline void setName(const QString& newVal) + { + m_Name = newVal; + } + protected: + QString m_Name; + }; + +} diff --git a/TetraIF/PrtCnv/LastTest/CMakeLists.txt b/TetraIF/PrtCnv/LastTest/CMakeLists.txt new file mode 100644 index 000000000..5bd0aca8a --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(my_SRCS + main.cpp + tetra_if.cpp + tetra_if.h +) + +NGL_ADD_EXECUTABLE(AAR SV PrtCnvLastTest ${my_SRCS}) +NGL_TARGET_LINK_LIBRARIES(PrtCnvLastTest + Qt5::Core + Qt5::Network + CoPrtCnv + NGLLogger + ngltools +) +NGL_INSTALL_TARGET(PrtCnvLastTest) diff --git a/TetraIF/PrtCnv/LastTest/main.cpp b/TetraIF/PrtCnv/LastTest/main.cpp new file mode 100644 index 000000000..c13be4fad --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/main.cpp @@ -0,0 +1,62 @@ + + +#include +#include +#include +#include +#include +#include "tetra_if.h" + +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx_tetra.props", false); + + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + + const QStringList args = app.arguments().mid(1); + if (args.count() < 4) + TetraIF::usage(); + QHostAddress tetra(args[0]); + if (tetra.isNull()) + { + ERROR_LOG(logger) << "Invalid IP address " << args[0]; + TetraIF::usage(); + } + bool bOk; + unsigned short port = args[1].toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Invalid IP port " << args[1]; + TetraIF::usage(); + } + unsigned short issi = args[2].toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(logger) << "Invalid ISSI id " << args[2]; + TetraIF::usage(); + } + const QString mode = args[3].toLower(); + if (mode != QLatin1String("listen") && + mode != QLatin1String("send_random") && + mode != QLatin1String("send_file")) + { + ERROR_LOG(logger) << "Invalid mode " << args[3]; + TetraIF::usage(); + } + TetraIF t(tetra, port, issi); + if (mode == QLatin1String("listen")) + t.listenMode(args.mid(4)); + else if (mode == QLatin1String("send_random")) + t.randomMode(args.mid(4)); + else if (mode == QLatin1String("send_file")) + t.fileMode(args.mid(4)); + + t.start(); + + return app.exec(); +} diff --git a/TetraIF/PrtCnv/LastTest/tetra_if.cpp b/TetraIF/PrtCnv/LastTest/tetra_if.cpp new file mode 100644 index 000000000..78aa2d235 --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/tetra_if.cpp @@ -0,0 +1,503 @@ + + +#include "tetra_if.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +TetraIF::TetraIF(const QHostAddress &addr, unsigned short port, unsigned short issi) + : QObject() + , m_addr(addr) + , m_port(port) + , m_issi(issi) + , m_socket(new QTcpSocket(this)) + , m_count(0) + , m_telegramsPerSecond(0) + , m_telegramsInCurSecond(0) + , m_secondFragment(0) + , m_timer(nullptr) + , m_SendCounter(0) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()) + +{ + connect(m_socket, &QTcpSocket::connected, this, &TetraIF::onConnected); + connect(m_socket, &QTcpSocket::disconnected, this, &TetraIF::onDisconnected); + connect(m_socket, &QTcpSocket::readyRead, this, &TetraIF::onReadyRead); + connect(m_socket, QOverload::of(&QTcpSocket::error), this, &TetraIF::onError); + + m_outputDir = QCoreApplication::applicationDirPath(); + m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-'); +} + +void TetraIF::start() +{ + m_socket->connectToHost(m_addr, m_port); +} + +void TetraIF::listenMode(const QStringList &args) +{ + + if (args.count() > 1) + usage(); + m_outputDir = QCoreApplication::applicationDirPath(); + if (args.count() == 1) + m_outputDir = args[0]; + if (!QDir().mkpath(m_outputDir)) + { + ERROR_LOG(m_logger) << "Error creating directory " + << m_outputDir; + usage(); + } + + m_outputDir += QLatin1Char('/') + QString::number(m_issi) + QLatin1Char('-'); +} + +void TetraIF::randomMode(const QStringList &args) +{ + if (args.count() < 3) + { + ERROR_LOG(m_logger) << "Invalid argument count"; + usage(); + } + bool bOk; + int dataSize = args[0].toInt(&bOk); + if (!bOk || dataSize > 256 || dataSize < 0) + { + ERROR_LOG(m_logger) << "Invalid data size " << args[0]; + usage(); + } + m_count = args[1].toInt(&bOk); + if (!bOk || m_count == 0 || m_count < -1) + { + ERROR_LOG(m_logger) << "Invalid count " << args[1]; + usage(); + } + m_telegramsPerSecond = args[2].toInt(&bOk); + if (!bOk || m_telegramsPerSecond < 1) + { + ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2]; + usage(); + } + m_data.reserve(dataSize); + for (int i = 0; i < dataSize; ++i) + m_data += (i % 256); + + parseISSIs(args.mid(3)); + + INFO_LOG(m_logger) << "Sending " << m_data.size() + << " bytes, " << m_telegramsPerSecond + << " telegrams/second for " << m_count + << " time(s) to issi(s) " << getIssisAsString(); + + setupTimer(); +} + +void TetraIF::fileMode(const QStringList &args) +{ + if (args.count() < 3) + { + ERROR_LOG(m_logger) << "Invalid argument count"; + usage(); + } + QFile f(args[0]); + if (!f.exists() || f.size() > 256) + { + ERROR_LOG(m_logger) << "Invalid file: " << args[0]; + usage(); + } + bool bOk; + m_count = args[1].toInt(&bOk); + if (!bOk || m_count == 0 || m_count < -1) + { + ERROR_LOG(m_logger) << "Invalid count " << args[1]; + usage(); + } + m_telegramsPerSecond = args[2].toInt(&bOk); + if (!bOk || m_telegramsPerSecond < 1) + { + ERROR_LOG(m_logger) << "Invalid telegrams/second " << args[2]; + usage(); + } + if (!f.open(QIODevice::ReadOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for reading - error: " + << f.errorString(); + } + m_data = f.readAll(); + + parseISSIs(args.mid(3)); + + INFO_LOG(m_logger) << "Sending " << m_data.size() + << " bytes, " << m_telegramsPerSecond + << " telegrams/second for " << m_count + << " time(s) to issi(s) " << getIssisAsString(); + + setupTimer(); +} + +void TetraIF::usage() +{ + NGL::INGLLogger &logger(NGL::NGLLoggerBootstrap::getNGLRootLogger()); + ERROR_LOG(logger) << "Usage : " << QCoreApplication::applicationFilePath() << " "; + ERROR_LOG(logger) << " : listen|send_random|send_file"; + ERROR_LOG(logger) << " : []"; + ERROR_LOG(logger) << " : [ .. ]"; + ERROR_LOG(logger) << " : [ .. ]"; + exit(1); +} + +void TetraIF::onConnected() +{ + INFO_LOG(m_logger) << "Connected to " << m_socket->peerName() << ":" << m_socket->peerPort(); + doInitialLogin(); +} + +void TetraIF::onDisconnected() +{ + INFO_LOG(m_logger) << "Disconnected - exiting application"; + QCoreApplication::quit(); +} + +void TetraIF::onReadyRead() +{ + do + { + DEBUG_LOG(m_logger) << "Got " << m_socket->bytesAvailable() << " bytes from socket"; + + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + if (m_socket->bytesAvailable() < int(sizeof(header))) + return; + + m_socket->peek(reinterpret_cast(&header), sizeof(header)); + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Incorrect magic number (0x" + << QString::number(header.m_MagicNumber, 16) + << " - aborting"; + exit(2); + } + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + { + ERROR_LOG(m_logger) << "Radio-Telegram length to big: " + << header.m_Length + << ", but I proceed with this telegram."; + } + + const quint16 dataSize = header.m_Length + sizeof(header); + if (m_socket->bytesAvailable() < dataSize) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data"; + return; + } + QByteArray buf(dataSize, Qt::Uninitialized); + m_socket->read(buf.data(), dataSize); + handleReceivedTelegram(buf); + + } + while (m_socket->bytesAvailable()); +} + +void TetraIF::onError(QAbstractSocket::SocketError err) +{ + ERROR_LOG(m_logger) << "Socket error " + << err + << " (" + << m_socket->errorString() + << ") - aborting"; + exit(2); +} + +void TetraIF::doInitialLogin() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(m_issi); + m_socket->write(tele.data()); + m_socket->flush(); +} + +void TetraIF::handleReceivedTelegram(const QByteArray &data) +{ + const auto type = N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type(data.at(4)); + + switch (type) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + handleRegisterRsp(data.at(5)); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + + break; + + default: + return; + } + INFO_LOG(m_logger) << "PDU Type: " << type; + dumpData(data); +} + +void TetraIF::handleRegisterRsp(const uint8_t a_registrationStatus) +{ + QByteArray logText; + switch (a_registrationStatus) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered: + INFO_LOG(m_logger) << "Valid register response from Tetra "; + if (m_timer) + m_timer->start(); + return; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI: + logText = "TETRA: Register-Response: Status=Duplicate ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI: + logText = "TETRA: Register-Response: Status=Invalid ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress: + logText = "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address ("; + { + const QList ipList = QNetworkInterface::allAddresses(); + for (const QHostAddress &addr : ipList) + logText += addr.toString().toUtf8() + ", "; + logText += ")..."; + } + break; + default: + logText = "Unknown registration status: " + QByteArray::number(a_registrationStatus); + break; + } + + ERROR_LOG(m_logger) << logText; + exit(2); +} + +void TetraIF::dumpData(const QByteArray &data) +{ + + if (m_outputDir.isEmpty()) + return; + const qint64 msecs = QDateTime::currentMSecsSinceEpoch(); + const QString timeStr = QStringLiteral("%1.%2").arg(msecs / 1000).arg(msecs % 1000); + { + QFile f(m_outputDir + timeStr + QLatin1String(".dat")); + if (!f.open(QIODevice::WriteOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for writing - error: " + << f.errorString(); + } + f.write(data); + f.close(); + } + if (data.size() > 27) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(data); + INFO_LOG(m_logger) << "Got telegram from " + << tele.getSrcISSI() + << " with size " + << data.size() + << " and payload size " + << tele.getPayloadSize(); + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, tele.data()); + QFile f(m_outputDir + QStringLiteral("payload-%1-%2.dat").arg(QString::number(tele.getSrcISSI()), timeStr)); + if (!f.open(QIODevice::WriteOnly)) + { + ERROR_LOG(m_logger) << "Error opening file " + << f.fileName() + << " for writing - error: " + << f.errorString(); + } + + f.write(&data.data()[27], data.size() - 27); + f.close(); + } +} + +void TetraIF::onSendData() +{ + ++m_secondFragment; + + if (m_secondFragment == 100) + { + m_secondFragment = 0; + m_telegramsInCurSecond = 0; + } + + int telegramsToSendNow = (m_telegramsPerSecond - m_telegramsInCurSecond) / (100 - m_secondFragment); + NOTICE_LOG(m_logger) << "telegramsToSendNow: " << telegramsToSendNow << ", " << m_telegramsPerSecond << ", " << m_telegramsInCurSecond << ", " << m_secondFragment; + + m_telegramsInCurSecond += telegramsToSendNow; + static uint8_t s_counter = 1; + static char s_randomChar = 0; + for (int i = 0; i < telegramsToSendNow; ++i) + { + for (unsigned short dest_issi : qAsConst(m_issiList)) + { + + m_data[0] = s_randomChar++; + N_CoPrtCnv::CoPrtCnvRadioTelegram tele(GEF_BESTAETIGUNG, m_data.size(), dest_issi); + tele.setPayloadDataComplete(m_data); + tele.setSrcISSI(m_issi); + tele.setDestISSI(dest_issi); + tele.setZaehler(s_counter++); + DEBUG_LOG(m_logger) << "Sending " << tele.getSize() << " bytes to Tetra (ISSI: " << dest_issi << ")"; + m_socket->write(tele.data()); + } + if (m_count > 0) + { + if (--m_count <= 0) + { + INFO_LOG(m_logger) << "Finsihed"; + m_socket->disconnectFromHost(); + } + } + m_socket->flush(); + } +} + +void TetraIF::parseISSIs(const QStringList &issiList) +{ + m_issiList.clear(); + + if (issiList.count() == 0) + { + m_issiList += 0; + return; + } + for (const QString &issiStr : issiList) + { + bool bOk; + unsigned short issi = issiStr.toUShort(&bOk); + if (!bOk) + { + ERROR_LOG(m_logger) << "Not a valid issi number: " << issiStr; + usage(); + } + m_issiList += issi; + } +} + +QString TetraIF::getIssisAsString() const +{ + QString ret; + for (unsigned short issi : qAsConst(m_issiList)) + ret += QString::number(issi) + QLatin1String(", "); + return ret.left(ret.size() - 2); +} + +void TetraIF::handleDataIndReq(const QByteArray &data) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(data); + uint32_t m_HostISSI = 2; + if (m_HostISSI == radioTelegram->getDestISSI()) + { + + switch (radioTelegram->getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_NotFragmented: + handleLoginTelegram(radioTelegram); + break; + default: + ERROR_LOG(m_logger) << "Unknown payload-status!: " << radioTelegram->getFragmentStatus(); + break; + } + + delete radioTelegram; + } +} + +void TetraIF::handleLoginTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *a_loginTelegram) +{ + uint16_t identity = a_loginTelegram->getIdentity(); + uint32_t issi = a_loginTelegram->getSrcISSI(); + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest == (a_loginTelegram->getPayloadDataUInt8(2) & N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginStatusMask)) + { + bool sent = sendLoginResponse(issi); + if (sent) + INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " logged in"; + else + + INFO_LOG(m_logger) << "Login: New TPU with Id=" << identity << " and ISSI=" << issi << " is NOT logged in"; + } + +} + +bool TetraIF::sendLoginResponse(const uint32_t a_ISSI) +{ + ++m_SendCounter; + N_CoPrtCnv::CoPrtCnvRadioTelegram *a_telegram = new N_CoPrtCnv::CoPrtCnvRadioTelegram(GEF_BESTAETIGUNG, 20, a_ISSI); + a_telegram->setZaehler(m_SendCounter); + + a_telegram->setDestISSI(a_ISSI); + a_telegram->setSrcISSI(2); + gef_telegramm_id_et telId = a_telegram->isNormalTelegram() ? a_telegram->getTelID() : GEF_BESTAETIGUNG; + + + INFO_LOG(m_logger) << "Send telegram to radio: telId=" << telId << " wcounter=" << a_telegram->zaehler() << " size= 28"; + + + + a_telegram->setProtocolIdentifier(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_TDSMessageWithoutSDS_TL); + a_telegram->setPayloadData(0x01); + a_telegram->setPayloadData(0x04); + + a_telegram->getData()[22] = 0x0d; + + char *data = a_telegram->getData(); + + + data[02] = 0x18; + + data[22] = 0x0d; + data[23] = 0x00; + + data[24] = 0x02; + data[25] = 0x00; + + data[13] = 0x00; + data[26] = 0x01; + data[27] = 0x40; + + m_socket->write(data, 28); + delete a_telegram; + return m_socket->flush(); + +} + +void TetraIF::setupTimer() +{ + delete m_timer; + m_timer = new QTimer(this); + connect(m_timer, &QTimer::timeout, this, &TetraIF::onSendData); + m_timer->setInterval(10); +} diff --git a/TetraIF/PrtCnv/LastTest/tetra_if.h b/TetraIF/PrtCnv/LastTest/tetra_if.h new file mode 100644 index 000000000..c239a2315 --- /dev/null +++ b/TetraIF/PrtCnv/LastTest/tetra_if.h @@ -0,0 +1,61 @@ + + +#pragma once +#include +#include +#include + +#include +#include + +class QTcpSocket; +class QTimer; +class TetraIF : public QObject +{ + Q_OBJECT +public: + TetraIF(const QHostAddress &addr, unsigned short port, unsigned short issi); + + void start(); + void listenMode(const QStringList &args); + void randomMode(const QStringList &args); + void fileMode(const QStringList &args); + + static void usage(); +protected Q_SLOTS: + void onConnected(); + void onDisconnected(); + void onReadyRead(); + void onError(QAbstractSocket::SocketError); + void onSendData(); +protected: + void doInitialLogin(); + void handleReceivedTelegram(const QByteArray &data); + void handleRegisterRsp(const uint8_t a_registrationStatus); + void dumpData(const QByteArray &data); + + void parseISSIs(const QStringList &issiList); + void handleDataIndReq(const QByteArray &data); + void handleLoginTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *a_loginTelegram); + bool sendLoginResponse(const uint32_t a_ISSI); + QString getIssisAsString() const; + + void setupTimer(); + +protected: + QHostAddress m_addr; + unsigned short m_port; + unsigned short m_issi; + QTcpSocket *m_socket; + int m_count; + int m_telegramsPerSecond; + int m_telegramsInCurSecond; + int m_secondFragment; + QByteArray m_data; + QList m_issiList; + QTimer *m_timer; + uint8_t m_SendCounter; + + QString m_outputDir; + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt b/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt new file mode 100644 index 000000000..4d4301fd1 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(lta_SRCS + main.cpp + mainwindow.cpp +) + +SET(lta_HDRS + mainwindow.h +) + +SET(lta_UICS + mainwindow.ui +) + +NGL_WRAP_UI(lta_SRCS ${lta_UICS}) +NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION LastTestAuswertung ${lta_SRCS} ${lta_HDRS} ${lta_UICS}) +NGL_TARGET_LINK_LIBRARIES(LastTestAuswertung + Qt5::Core + Qt5::Widgets +) diff --git a/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro b/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro new file mode 100644 index 000000000..0ccbcd0c8 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/LastTestAuswertung.pro @@ -0,0 +1,16 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2011-05-13T08:20:33 +# +#------------------------------------------------- + +TARGET = LastTestAuswertung +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp + +HEADERS += mainwindow.h + +FORMS += mainwindow.ui diff --git a/TetraIF/PrtCnv/LastTestAuswertung/main.cpp b/TetraIF/PrtCnv/LastTestAuswertung/main.cpp new file mode 100644 index 000000000..84bb2601d --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/main.cpp @@ -0,0 +1,10 @@ +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp new file mode 100644 index 000000000..0cad665e9 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.cpp @@ -0,0 +1,428 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include +#include +#include +#include + + + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + init(); +} + +MainWindow::~MainWindow() +{ + m_files.clear(); + + + + +} + +void MainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void MainWindow::init() +{ + + connect(ui->pushButtonOrdnerFinden, &QPushButton::clicked, this, &MainWindow::slot_findFolder); + connect(ui->pushButtonAnalysieren, &QPushButton::clicked, this, &MainWindow::slot_analysieren); + + ui->progressBar->setValue(0); + ui->labelResult->setText(QString()); + QIntValidator intVal; + intVal.setBottom(0); + intVal.setTop(100000); + ui->lineEditISSI->setValidator(&intVal); +} + +void MainWindow::slot_findFolder() +{ + + + + QString name = QFileDialog::getExistingDirectory(this, tr("Choose folder"), QDir::homePath(), QFileDialog::DontResolveSymlinks); + ui->lineEditOrdner->setText(name); + ui->labelResult->setText(QString()); + +} + +void MainWindow::slot_analysieren() +{ + ui->labelResult->setText(QString()); + QString ISSI = ui->lineEditISSI->text(); + if (ISSI.isEmpty()) + ISSI = QLatin1String("1"); + m_logfileList.clear(); + + + QDir folder(ui->lineEditOrdner->text()); + m_files = folder.entryList(); + folder.~QDir(); + ui->progressBar->setValue(1); + const QString paytext = ISSI + QLatin1String("-payload"); + const QString issitext = ISSI + QLatin1String("-1"); + for (int i = 0; i < m_files.count(); i++) + { + + QString name = m_files[i]; + if (name.contains(paytext)) + { + m_files.removeAt(i); + i--; + } + else + { + if (!name.contains(QLatin1String(".dat"))) + { + m_files.removeAt(i); + i--; + } + else + { + if (!name.contains(issitext)) + { + m_files.removeAt(i); + i--; + } + } + } + } + + ui->progressBar->setValue(10); + if (m_files.count() == 0) + ui->labelResult->setText(tr("no logfiles found")); + else + { + openLogfile(ui->lineEditOrdner->text(), m_files.count()); + ui->progressBar->setValue(12); + ui->progressBar->repaint(); + readFiles(); + ui->progressBar->setValue(90); + ui->progressBar->repaint(); + QString ausgabetext = QLatin1String("\tANALYSIS COMPLETED - ") + QString::number(auswerten()) + QLatin1String(" missing messages"); + ui->labelResult->setText(ausgabetext); + } + ui->progressBar->setValue(100); + ui->progressBar->repaint(); +} + +void MainWindow::readFiles() +{ + for (int j = 0; j < m_files.count(); j++) + { + QString filename = ui->lineEditOrdner->text(); + filename += QLatin1Char('/'); + filename += m_files[j]; + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) + { + + QByteArray ar = file.read(150); + file.close(); + if (ar.count() > 36) + { + QString issi = getISSI(ar); + QByteArray bytes = ar; + + + bytes.remove(0, 34); + bytes.remove(2, 150); + uint nr = bytes[0] & 255; + nr *= 256; + nr += bytes[1] & 255; + + + bytes = ar; + bytes.remove(0, 30); + bytes.remove(4, 150); + + const QByteArray test = bytes.toHex(); + qint64 zeit = test.toLongLong(nullptr, 16); + + const QDateTime timeStart(QDateTime::fromMSecsSinceEpoch(zeit * 1000)); + + writeToLogfile(issi, timeStart, getTimestamp(m_files[j]), m_files[j], nr); + writeLogZeiten(timeStart, getTimestamp(m_files[j]), issi); + + } + } + file.close(); + double val = 70; + val /= m_files.count(); + val *= (j + 1); + val += 20; + ui->progressBar->setValue(int(val)); + + } + +} + +void MainWindow::openLogfile(const QString &folder, int count) +{ + m_logfile = folder; + m_logZeiten = folder; + m_logfile += QLatin1String("/logfile_analysis.txt"); + QFile file(m_logfile); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + const QString msg = QStringLiteral("There are %1 logfiles evaluated.\nISSI SENDING TIME RECIEVING TIME FILENAME NO \n").arg(count); + file.write(msg.toUtf8()); + file.close(); + } + m_logZeiten += QLatin1String("/transmission_times.csv"); + file.setFileName(m_logZeiten); + if (file.open(QIODevice::WriteOnly)) + { + file.write("ISSI;Sending Time ; Receiving Time\n"); + file.close(); + } + +} + +void MainWindow::writeToLogfile(const QString &issi, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr, + const QString &bytes) +{ + QString text = issi; + text += QLatin1String(": "); + text += timestamp.toString(QLatin1String("dd.MM.yyyy hh:mm:ss")); + text += QLatin1String(" - "); + text += filename; + text += QLatin1String(" -> "); + text += bytes; + text += QLatin1String(" --> "); + text += QString::number(lfdNr, 10); + text += QLatin1Char('\n'); + QFile file(m_logfile); + if (file.open(QIODevice::Append | QIODevice::Text)) + { + file.write(text.toLatin1()); + file.close(); + } + LogfileInfo info; + info.timestamp = timestamp; + info.issi = issi; + info.lfdNr = lfdNr; + m_logfileList.append(info); +} + +void MainWindow::writeToLogfile(const QString &issi, + const QDateTime &sendeZeit, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr) +{ + QString text = issi; + text += QLatin1String(": "); + text += sendeZeit.toString(QLatin1String("hh:mm:ss")); + text += QLatin1String(" --> "); + text += timestamp.toString(QLatin1String("dd.MM.yyyy hh:mm:ss")); + text += QLatin1String(" - "); + text += filename; + text += QLatin1String(" --> "); + text += QString::number(lfdNr, 10); + text += QLatin1Char('\n'); + QFile file(m_logfile); + if (file.open(QIODevice::Append | QIODevice::Text)) + { + file.write(text.toLatin1()); + file.close(); + } + LogfileInfo info; + info.timestamp = timestamp; + info.issi = issi; + info.lfdNr = lfdNr; + m_logfileList.append(info); +} + +QDateTime MainWindow::getTimestamp(const QString &filename) const +{ + const auto list1 = filename.splitRef(QLatin1Char('-')); + if (list1.size() < 2) + return {}; + + const QStringRef &fn = list1.at(1); + const auto list2 = fn.split(QLatin1Char('.')); + auto str = list2.at(0).toString(); + str.remove(10, 10); + + return QDateTime::fromMSecsSinceEpoch(str.toLongLong() * 1000); +} + +QString MainWindow::getISSI(QByteArray ar) +{ + + ar.remove(0, 5); + ar.remove(4, 200); + QByteArray issi = ar.toHex(); + + if (ar.count() == 4) + { + if (ar[2] == '\0' && ar[3] == '\0') + { + ar.remove(2, 2); + issi = ar.toHex(); + int hex[4]; + for (int i = 3; i >= 0; i--) + { + char c = issi.at(i); + if (c >= '0' && c <= '9') + hex[i] = c - '0'; + else if (c >= 'a' && c <= 'f') + hex[i] = c - 'a' + 10; + + } + int sum = 0; + sum += hex[1]; + sum += hex[0] * 16; + sum += hex[3] * 256; + sum += hex[2] * 4096; + issi = QByteArray::number(sum); + } + } + + + return QString::fromLatin1(issi); +} + +int MainWindow::auswerten() +{ + + + QFile f(m_logfile); + if (!f.open(QIODevice::Append | QIODevice::Text)) + return -1; + f.write("***************************RESULT************************************\n"); + QSet issis; + issis.reserve(100); + for (int i = 0; i < m_logfileList.count(); i++) + { + + issis += m_logfileList.at(i).issi; + } + ui->progressBar->setValue(94); + ui->progressBar->repaint(); + int fehlcount = 0; + QVector numList; + int i = 0; + for (const QString &issi : qAsConst(issis)) + { + + numList.clear(); + for (int j = 0; j < m_logfileList.count(); j++) + { + if (issi == m_logfileList.at(j).issi) + numList.append(m_logfileList.at(j).lfdNr); + } + QByteArray text = issi.toLatin1(); + text += ":\t"; + text += QByteArray::number(numList.count()); + text += " messages transmitted\n"; + text += "\t"; + f.write(text); + + fehlcount += fehlendeNumsEintragen(numList, f); + + + double val = 5; + val /= issis.count(); + val *= (i + 1); + val += 94; + ui->progressBar->setValue(qRound(val)); + ui->progressBar->repaint(); + + ++i; + } + return fehlcount; +} + +int MainWindow::fehlendeNumsEintragen(const QVector &numList, QFile &f) +{ + + QVector fehlendeNums = getFehlendeNums(numList); + QByteArray text = QByteArray::number(fehlendeNums.count()); + text += " lost messages\n"; + text += "\t\t following messages are missing ("; + for (int j = 0; j < fehlendeNums.count(); j++) + { + text += QByteArray::number(fehlendeNums.at(j)); + text += ", "; + } + + text += ")\n"; + + f.write(text); + + return fehlendeNums.count(); +} + +QVector MainWindow::getFehlendeNums(const QVector &numsDurchgang) +{ + + uint count = numsDurchgang.count(); + uint maxnum = 0; + uint minnum = 999999; + for (uint k = 0; k < count; k++) + { + + if (numsDurchgang.at(k) > maxnum) + maxnum = numsDurchgang.at(k); + if (numsDurchgang.at(k) < minnum) + minnum = numsDurchgang.at(k); + } + + QVector fehlendeNum; + for (uint z = minnum; z <= maxnum; z++) + { + + bool vorhanden = false; + for (uint j = 0; j < count; j++) + { + if (numsDurchgang.at(j) == z) + { + vorhanden = true; + break; + } + } + if (!vorhanden) + fehlendeNum.append(z); + } + return fehlendeNum; +} + +void MainWindow::writeLogZeiten(const QDateTime &beginn, const QDateTime &end, const QString &issi) +{ + QString msg = issi; + msg += QLatin1Char(';'); + msg += beginn.toString(QLatin1String("hh:mm:ss")); + msg += QLatin1Char(';'); + msg += end.toString(QLatin1String("hh:mm:ss")); + msg += QLatin1Char('\n'); + QFile file(m_logZeiten); + file.open(QIODevice::Append | QIODevice::Text); + file.write(msg.toUtf8()); + file.close(); + + +} diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h new file mode 100644 index 000000000..e8b60ec56 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.h @@ -0,0 +1,69 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +namespace Ui +{ +class MainWindow; +} + +struct LogfileInfo +{ + QString issi; + QDateTime timestamp; + uint lfdNr; +}; +struct ZeitNum +{ + uint zeit; + int num; +}; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::MainWindow *ui; + void init(); + void readFiles(); + QStringList m_files; + QDateTime getTimestamp(const QString &filename) const; + QString m_logfile; + QString m_logZeiten; + void openLogfile(const QString &folder, int count); + void writeToLogfile(const QString &issi, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr, + const QString &bytes); + void writeToLogfile(const QString &issi, + const QDateTime &sendeZeit, + const QDateTime ×tamp, + const QString &filename, + uint lfdNr); + QString getISSI(QByteArray ar); + int auswerten(); + QVector getFehlendeNums(const QVector &numsDurchgang); + int fehlendeNumsEintragen(const QVector &numList, QFile &file); + void writeLogZeiten(const QDateTime &beginn, const QDateTime &end, const QString &issi); + + QVector m_logfileList; + +private slots: + void slot_findFolder(); + void slot_analysieren(); +}; + + + +#endif diff --git a/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui new file mode 100644 index 000000000..b34067217 --- /dev/null +++ b/TetraIF/PrtCnv/LastTestAuswertung/mainwindow.ui @@ -0,0 +1,123 @@ + + + MainWindow + + + + 0 + 0 + 521 + 234 + + + + Logfiles analysieren + + + + + + 10 + 80 + 501 + 101 + + + + + + + analyse logfiles + + + + + + + 24 + + + + + + + + 12 + + + + TextLabel + + + + + + + + + 9 + 0 + 501 + 65 + + + + + + + + + + + + choose folder + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ISSI by the central<br />(if no ISSI is entered, ISSI 1 will be used)</p></body></html> + + + + + + + + + + + + 0 + 0 + 521 + 21 + + + + + + TopToolBarArea + + + false + + + + + + + + diff --git a/TetraIF/PrtCnv/PrtCnv.dat.tts b/TetraIF/PrtCnv/PrtCnv.dat.tts new file mode 100644 index 000000000..c8d1f0fc9 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnv.dat.tts @@ -0,0 +1,90 @@ +[Common] +LogCentralTelegrams=1 +LogRadioTelegrams=1 +LogTelegramPath=logdata +LogTelegramPrefix=PrtCnv_ +; virtual TeilnehmerId of protocol-converter +VirtualIdPrtCnv=90 + +[Db] +DatabaseFileName=db/telegrams.db + +[Central] +UseSocketsInsteadFiles=1 +HostName=ECCORSV01 +Port=9600 +; Milliseconds +AckTimeout=900 +ConnectTimeout=2000 +DisconnectTimeout=10000 +AliveTimeout=3000 +; nbr of unsuccessful send-attempts, before telegram will be deleted without sending it +NbrOfAttempts=5 + +[Radio] +HostName=127.0.0.1 +Port=52010 +HostISSI=9999 +; Seconds +CyclicEnvironmentTime=30 +; Milliseconds +BroadcastISSI=5000 +ConnectTimeout=2000 +DisconnectTimeout=10000 +AliveTimeout=3000 +; 1 - UseSDS_TL +UseSDS_TL=0 +DumpReceivedTelegrams=1 +DumpSentTelegrams=1 +; GSSIs which we would like to subscribe to - make sure to not subscribe to our own BroadcastISSI ! +ListenGroups=5001 + +[Login] +LoginFilePathWithPrefix=login/pk_ +DoLicenseDespiteSelftestOrConfigFailure=0 +DoCheckPlayerId=1 +LowestPlayerId=500 +HighestPlayerId=9999 +PlayerIdFilePath=playerIds.dat + +[Broadcast] +; In seconds, delay between sending 1st and 2nd broadcast +BroadcastDelay2=10 +; In seconds, delay between sending 2nd and 3rd broadcast +BroadcastDelay3=20 +; the time to wait for NachforderungBroadcast from TNEs, before begin sending the broadcasts +ClaimWindow=30 +; factor for extend the claimwindow when we have full load in downlink +FullLoadFactor=3 +; if less TNEs ask for broadcasts, they will be send directed +BroadcastLimit=10 +; the time to wait before sending next broadcast in milliseconds +SendGap=500 + +[TrafficControl] +; from PrtCnv to Tetra (Telegram-Counting) +; Number of telegrams (0..255) reported by air-interface-report telegram when we have high load +SendQueueHighLoad=150 +; Number of telegrams that will be sent per second, when we have high-load +SendTelegramsHighLoad=50 +; Number of telegrams (0..255) reported by air-interface-report telegram when we have full load +SendQueueFullLoad=200 +; Number of telegrams that will be sent per second, when we have full-load +SendTelegramsFullLoad=10 +; from Tetra to PrtCnv (Byte-Counting) +; high load in percent (0 .. 100) +ReceiveQueueHighLoad=50 +; full load in percent (ReceiveQueueHighLoad .. 100) +ReceiveQueueFullLoad=75 +; hysteresis in percent (0 .. 10) +ReceiveQueueHysteresis=5 +; Averaging time in seconds +ReceiveAveragingTime=5 +; Throughput in KB/s per Transceiver +ReceiveThroughput=3.6 +; Transceiver count +TransceiverCount=6 + +[Injection] +Enable=true +Port=46666 diff --git a/TetraIF/PrtCnv/PrtCnvApplication.cpp b/TetraIF/PrtCnv/PrtCnvApplication.cpp new file mode 100644 index 000000000..ada274ae4 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvApplication.cpp @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + +#include "PrtCnvApplication.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvThread.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + +static std::string threadIdToString(PrtCnvApplication::E_ThreadId id) +{ + switch (id) + { + case PrtCnvApplication::e_Central: + return "Central"; + case PrtCnvApplication::e_Radio: + return "Radio"; + case PrtCnvApplication::e_Db: + return "Db"; + case PrtCnvApplication::e_Log: + return "Log"; + case PrtCnvApplication::e_Injection: + return "Injection"; + case PrtCnvApplication::e_RadioTraffic: + return "RadioTraffic"; + case PrtCnvApplication::e_ThreadIdMax: + break; + } + return std::to_string(id); +} + +PrtCnvApplication::PrtCnvApplication() + : m_Config(nullptr) + , m_exerciseId(0) + , m_accessMutex(QMutex::Recursive) + , m_logger(getLogger("PrtCnvApplication")) +{} + + +PrtCnvApplication::~PrtCnvApplication() +{ + delete m_Config; + for (const auto &ti : m_threadInfo) + delete ti.thread; +} + + + + + +void PrtCnvApplication::waitForCreate(const E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can create " << threadIdToString(a_threadId); + setConstructed(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isConstructed(e_Db) && + isConstructed(e_Radio) && + isConstructed(e_Log) && + isConstructed(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isConstructed(e_Db) && + isConstructed(e_Central) && + isConstructed(e_Log) && + isConstructed(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isConstructed(e_Radio) && + isConstructed(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can create " << threadIdToString(a_threadId); +} + + + + + +void PrtCnvApplication::waitForInit(E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can initialize " << threadIdToString(a_threadId); + setCreated(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isCreated(e_Db) && + isCreated(e_Radio))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isCreated(e_Db) && + isCreated(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isCreated(e_Radio) && + isCreated(e_Central))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can initialize " << threadIdToString(a_threadId); +} + + + + +void PrtCnvApplication::waitForStart(E_ThreadId a_threadId) +{ + INFO_LOG(m_logger) << "Wait for others until we can start " << threadIdToString(a_threadId); + setInitialized(a_threadId); + switch (a_threadId) + { + case e_Central: + while (!(isStarted(e_Db) && + isInitialized(e_Radio) && + isStarted(e_Log) && + isStarted(e_Injection))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Radio: + while (!(isStarted(e_Db) && + isInitialized(e_Central) && + isStarted(e_Log) && + isStarted(e_Injection) && + isInitialized(e_RadioTraffic))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_Db: + while (!(isInitialized(e_Radio) && + isInitialized(e_Central) && + isStarted(e_Log))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + + case e_RadioTraffic: + while (!(isInitialized(e_Radio) && + isStarted(e_Log))) + { + DEBUG_LOG(m_logger) << "wait..."; + QThread::sleep(1); + } + break; + default: + break; + } + INFO_LOG(m_logger) << "Now we can start " << threadIdToString(a_threadId); +} + + + + + +void PrtCnvApplication::waitForExec(E_ThreadId a_threadId) +{ + setStarted(a_threadId); +} + + + + +void PrtCnvApplication::startApp() +{ + createApplication(); + init(); + start(); +} + +void PrtCnvApplication::shutdownApp() +{ + stop(); + deinit(); + destroy(); + for (const auto &ti : m_threadInfo) + ti.thread->quit(); + for (const auto &ti : m_threadInfo) + ti.thread->wait(); + for (auto &ti : m_threadInfo) + { + delete ti.thread; + ti.thread = nullptr; + } +} + +void PrtCnvApplication::setCleanDb(bool bCleanDb) +{ + PrtCnvThread::m_DoCleanDb = bCleanDb; +} + +void PrtCnvApplication::setExerciseId(int exerciseId) +{ + m_exerciseId = exerciseId; +} + +void PrtCnvApplication::setConfigFile(const QString &configFile) +{ + m_ConfigFileName = configFile; +} + + + + +int32_t PrtCnvApplication::createApplication() +{ + setName(QStringLiteral("Common")); + if (m_ConfigFileName.isEmpty()) + { + m_ConfigFileName = QCoreApplication::applicationDirPath(); + if (m_exerciseId > 0) + m_ConfigFileName += QStringLiteral("/PrtCnv_ex_") + QString::number(m_exerciseId) + QStringLiteral(".dat"); + else + m_ConfigFileName += QStringLiteral("/PrtCnv.dat"); + } + m_Config = new NGL::Settings(m_ConfigFileName); + std::cout << "Use config-file: " << qPrintable(m_ConfigFileName) << std::endl; + + for (int i = 0; i < e_ThreadIdMax; i++) + m_threadInfo[i].thread = new PrtCnvThreadStarter((E_ThreadId)i, m_ConfigFileName, this); + + N_AppComponent::AppComponent::create(m_Config); + + return 0; +} + + + + +int32_t PrtCnvApplication::start() +{ + + for (const auto &ti : m_threadInfo) + ti.thread->start(); + + N_AppComponent::AppComponent::start(); + + return 0; +} + + + + + +PrtCnv::PrtCnvThreadStarter *PrtCnvApplication::getThreadStarter(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return nullptr; + + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].thread; +} + +void PrtCnvApplication::setDatabaseConnectionParams(const QString &driver, + const QString &hostName, + const QString &database, + const QString &schemaName, + const QString &userName, + const QString &password) +{ + m_dbDriver = driver; + m_dbHostName = hostName; + m_dbDatabaseName = database; + m_dbSchemaName = schemaName; + m_dbUserName = userName; + m_dbPassword = password; +} + +void PrtCnvApplication::logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, + bool bIsSend) +{ + const auto threadHandler = m_threadInfo[e_Log].thread; + PrtCnvTelegramLogThread *t = static_cast(threadHandler ? threadHandler->getThread() : nullptr); + if (t) + t->writeWlsTelegramLog(tele, bIsSend, 0); +} + + +bool PrtCnvApplication::isConstructed(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isConstructed; +} + + +void PrtCnvApplication::setConstructed(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isConstructed = true; +} + + +bool PrtCnvApplication::isInitialized(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isInitialized; +} + + +void PrtCnvApplication::setInitialized(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isInitialized = true; +} + + +bool PrtCnvApplication::isCreated(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isCreated; +} + + +void PrtCnvApplication::setCreated(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isCreated = true; +} + + +bool PrtCnvApplication::isStarted(const E_ThreadId a_threadId) const +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return false; + QMutexLocker l(&m_accessMutex); + return m_threadInfo[a_threadId].isStarted; +} + + +void PrtCnvApplication::setStarted(const E_ThreadId a_threadId) +{ + if (a_threadId < e_Central || a_threadId >= e_ThreadIdMax) + return; + QMutexLocker l(&m_accessMutex); + m_threadInfo[a_threadId].isStarted = true; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvApplication.hpp b/TetraIF/PrtCnv/PrtCnvApplication.hpp new file mode 100644 index 000000000..a496730ba --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvApplication.hpp @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + +#pragma once + +#include +#include "AppComponent.hpp" +#include "logger.h" +#include +#include +#include +#include + + + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + + + class PRTCNVLIB_EXPORT PrtCnvApplication : public QObject, public N_AppComponent::AppComponent + { + Q_OBJECT + public: + + + + enum E_ThreadId + { + e_Central, + e_Radio, + e_Db, + e_Log, + e_Injection, + e_RadioTraffic, + e_ThreadIdMax + }; + PrtCnvApplication(); + ~PrtCnvApplication(); + + + + void startApp(); + void shutdownApp(); + static void setCleanDb(bool bCleanDb); + void setExerciseId(int exerciseId); + int exerciseId() const { return m_exerciseId; } + void setConfigFile(const QString &configFile); + + + + int32_t start() override; + + + + + void waitForInit(E_ThreadId a_threadId); + + + + void waitForStart(E_ThreadId a_threadId); + + + + void waitForCreate(const E_ThreadId a_threadId); + + + + void waitForExec(E_ThreadId a_threadId); + + + + PrtCnvThreadStarter* getThreadStarter(const E_ThreadId a_threadId); + + + + void setDatabaseConnectionParams(const QString &driver, + const QString &hostName, + const QString &database, + const QString &schemaName, + const QString &userName, + const QString &password); + QString databaseDriver() const { return m_dbDriver; } + QString databaseHostName() const { return m_dbHostName; } + QString databaseName() const { return m_dbDatabaseName; } + QString databaseSchemaName() const { return m_dbSchemaName; } + QString databaseUserName() const { return m_dbUserName; } + QString databasePassword() const { return m_dbPassword; } + +public slots: + void logWlsTelegram(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool bIsSend); + +signals: + void textMessageFromPrtCnvToCentral(const QByteArray &ba); + void textMessageFromCentralToPrtCnv(const QByteArray &ba); + void outgoingBroadcastTelegramsRequest(int equipmentNumber, int broadcastIndex, int resetCounter); + void warehouseMessageFromPtrCnv(const QByteArray &jsonData); +protected: + + + int32_t createApplication(); + + + + bool isConstructed(const E_ThreadId a_threadId) const; + + + + void setConstructed(const E_ThreadId a_threadId); + + + + bool isInitialized(const E_ThreadId a_threadId) const; + + + + void setInitialized(const E_ThreadId a_threadId); + + + + bool isCreated(const E_ThreadId a_threadId) const; + + + + void setCreated(const E_ThreadId a_threadId); + + + + bool isStarted(const E_ThreadId a_threadId) const; + + + + void setStarted(const E_ThreadId a_threadId); + +protected: + + + NGL::Settings *m_Config; + + struct ThreadInfo + { + PrtCnvThreadStarter *thread = nullptr; + bool isConstructed = false; + bool isCreated = false; + bool isInitialized = false; + bool isStarted = false; + } m_threadInfo[e_ThreadIdMax]; + + + QString m_ConfigFileName; + + + int m_exerciseId; + + + + mutable QMutex m_accessMutex; + + QString m_dbDriver; + QString m_dbHostName; + QString m_dbDatabaseName; + QString m_dbSchemaName; + QString m_dbUserName; + QString m_dbPassword; + + NGL::INGLLogger &m_logger; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp new file mode 100644 index 000000000..b36512d8f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.cpp @@ -0,0 +1,1709 @@ + + + + + + + + + + + + + +#include "PrtCnvBroadcastMgr.hpp" +#include "PrtCnvDbThread.hpp" +#include +#include +#include +#include + +namespace PrtCnv +{ + +PrtCnvBroadcastMgr::PrtCnvBroadcastMgr() + : m_ClaimWindow(0) + , m_HighLoadFactor(0) + , m_BroadcastLimit(0) + , m_Config(nullptr) + , m_ActClaimWindow(0) + , m_State(e_ST_UNDEFINED) + , m_TickCounter(0) + , m_DbThread(nullptr) + , m_BroadcastIndex(0) + , m_IsFullLoad(false) + , m_FinishedBroadcastIndex(0) + , m_FirstBroadcastIndexOfBc1(0) + , m_logger(getLogger("PrtCnvBroadcastMgr")) + , m_loggerBcRequest(getLogger("PrtCnvBroadcastMgr.BcRequest")) +{ +} + + + + +int32_t PrtCnvBroadcastMgr::create(NGL::Settings *settings) +{ + m_Config = settings; + return 0; +} + + + + +int32_t PrtCnvBroadcastMgr::init() +{ + const QString broadcastGroup(QStringLiteral("Broadcast")); + N_CoPrtCnv::CoPrtCnvRadioTelegram::setBroadcastDelayTimes( + m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay2"), 60), + m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastDelay3"), 60)); + N_CoPrtCnv::CoPrtCnvRadioTelegram::setMaxBroadcastSendCnt(m_Config->getInteger(broadcastGroup, QStringLiteral("MaxBroadcastSendCount"), 1)); + + const int sendGap = m_Config->getInteger(broadcastGroup, QStringLiteral("SendGap"), 500); + m_ClaimWindow = (m_Config->getInteger(broadcastGroup, QStringLiteral("ClaimWindow"), 30) * 1000) / sendGap; + m_HighLoadFactor = m_Config->getInteger(broadcastGroup, QStringLiteral("HighLoadFactor"), 3); + m_BroadcastLimit = m_Config->getInteger(broadcastGroup, QStringLiteral("BroadcastLimit"), 10); + + cleanAndInit(true); + + INFO_LOG(m_loggerBcRequest) << "m_ActClaimWindow=" << m_ActClaimWindow << " m_State=" << m_State; + + return 0; +} + + + + + + +void PrtCnvBroadcastMgr::setDbThread(PrtCnvDbThread *a_dbThread) +{ + m_DbThread = a_dbThread; +} + + + + + + +void PrtCnvBroadcastMgr::cleanAndInit(const bool a_deleteTelegrams) +{ + if (a_deleteTelegrams) + { + m_deactivatedAesArea2bcIndex.clear(); + m_deactivatedBcIndex2AesArea.clear(); + + m_deactivatedDusMine2bcIndex.clear(); + m_deactivatedBcIndex2DusMine.clear(); + + m_deactivatedFuncArea2bcIndex.clear(); + m_deactivatedBcIndex2FuncArea.clear(); + + m_BroadcastMap.clear(); + + m_LastTelegramMap.clear(); + m_FunktionsraumTelegramMap.clear(); + m_WirkfeldTelegramMapByKennung.clear(); + m_WirkfeldTelegramMapByTime.clear(); + + m_BroadcastIndex = 0; + } + + m_claimerArray.clear(); + + m_ActClaimWindow = m_ClaimWindow; + m_IsFullLoad = false; + m_TickCounter = 0; + m_State = e_ST_COLLECT; + + m_FinishedBroadcastIndex = 0; + m_FirstBroadcastIndexOfBc1 = 0; +} + + + + +bool PrtCnvBroadcastMgr::handleRadioTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + switch (a_radioTelegram.getTelID()) + { + case GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME: + handleNachforderungBroadcastTelegram(a_radioTelegram.getIdentity(), + a_radioTelegram.getPayloadDataUInt32(8, 2) + 1, + a_radioTelegram.getPayloadDataUInt8(7)); + return false; + default: + + break; + } + return true; +} + + + + +void PrtCnvBroadcastMgr::handleNachforderungBroadcastTelegram(int identity, int broadcastIndex, int resetCounter) +{ + INFO_LOG(m_loggerBcRequest) << "Got NachforderungBroadcast from TNE with id=" << identity + << " resetCounter=" << resetCounter + << " broadcastIndex=" << broadcastIndex - 1 + << " m_TickCounter=" << m_TickCounter << " m_State=" << m_State; + if (resetCounter == m_DbThread->getResetCounter()) + { + m_DbThread->incClaimCount(identity); + + for (auto &ebi : m_claimerArray) + { + if (ebi.equipNo == identity) + { + ebi.bcIndex = broadcastIndex; + return; + } + } + m_claimerArray.emplace_back(identity, broadcastIndex); + return; + } + WARNING_LOG(m_logger) << "NachforderungBroadcast from TNE with id=" << identity + << ": resetCounter different we have: " << int(m_DbThread->getResetCounter()) + << "; TNE has: " << resetCounter << " => discarded"; +} + + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNextBroadcastTelegramToSend(const uint16_t a_beginSearchWithBroadcastIndex, + const time_t a_currentTime) +{ + + + + + DEBUG_LOG(m_logger) << "getNextBroadcastTelegramToSend, startIdx: " << a_beginSearchWithBroadcastIndex; + auto iter = m_BroadcastMap.upper_bound(0 == a_beginSearchWithBroadcastIndex ? m_FinishedBroadcastIndex : a_beginSearchWithBroadcastIndex); + while (iter != m_BroadcastMap.end()) + { + auto broadcastTelegram = iter->second; + gef_telegramm_id_et telId = broadcastTelegram->getTelID(); + + if (GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM == telId + || GEF_WF_SAMMELDEAKTIVIERUNG == telId + || GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN == telId) + { + + if (!broadcastTelegram->getBroadcastonlyTelegram()) + { + ++iter; + continue; + } + } + + bool isBcOnly = false; + if (broadcastTelegram->getBroadcastonlyTelegram()) + { + broadcastTelegram = broadcastTelegram->getBroadcastonlyTelegram(); + isBcOnly = true; + } + + bool wasLast = false; + if (broadcastTelegram->mustBeSentAsBroadcast(a_currentTime, wasLast)) + { + + if (wasLast) + { + if (isBcOnly || broadcastTelegram->isBroadcastOnly()) + { + removeFromAllMaps(broadcastTelegram); + } + else + { + + m_FinishedBroadcastIndex = broadcastTelegram->getBroadcastIndex(); + } + } + + broadcastTelegram->setIdentity(0); + return broadcastTelegram; + } + else + { + + + + + + + + + + + + + + + + + + + + + uint16_t bcCounter = broadcastTelegram->getBroadcastCounter(); + if (2 == bcCounter) + { + + + if (m_FirstBroadcastIndexOfBc1 > iter->first) + { + iter = m_BroadcastMap.lower_bound(m_FirstBroadcastIndexOfBc1); + continue; + } + } + else if (1 == bcCounter) + { + m_FirstBroadcastIndexOfBc1 = broadcastTelegram->getBroadcastIndex(); + return nullptr; + } + } + ++iter; + } + return nullptr; +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNextNachforderungTelegramToSend() +{ + removeExpiredTelegrams(); + switch (m_State) + { + case e_ST_COLLECT: + + if (m_TickCounter >= m_ActClaimWindow && !m_IsFullLoad) + { + + prepareForSendNachforderungen(); + } + else + { + + getAllFinishedBroadcastsFromDb(); + } + break; + + + case e_ST_SEND_NACHFORDERUNG: + return evaluateNextNachforderungToSend(); + default: + break; + } + return {}; +} + + + + + +void PrtCnvBroadcastMgr::removeExpiredTelegrams() +{ + const time_t now = time(nullptr); + auto iter = m_WirkfeldTelegramMapByTime.begin(); + while (iter != m_WirkfeldTelegramMapByTime.end()) + { + + + if (iter->first + 5 > now) + return; + + auto radioTelegram = iter->second; + INFO_LOG(m_logger) << "Remove expired telegram with telId=" << radioTelegram->getTelID() + << " and BC=" << radioTelegram->getBroadcastIndex() << " from BC-list"; + uint16_t wirkfeldKennung = radioTelegram->getPayloadDataUInt32(5, 2); + removeWirkfeldTelegrams(wirkfeldKennung); + iter = m_WirkfeldTelegramMapByTime.begin(); + } +} + + + + + +void PrtCnvBroadcastMgr::prepareForSendNachforderungen() +{ + + m_TickCounter = 0; + if (!m_claimerArray.empty()) + { + dump(); + + + + m_State = e_ST_SEND_NACHFORDERUNG; + + + std::swap(m_claimerArray, m_claimerArray); + std::sort(m_claimerArray.begin(), m_claimerArray.end(), + [] (const EquipNoBcIndex &a, const EquipNoBcIndex &b) + { + if (a.bcIndex != b.bcIndex) + return a.bcIndex < b.bcIndex; + return a.equipNo < b.equipNo; + }); + + + INFO_LOG(m_loggerBcRequest) << "BroadcastLimit: " << m_BroadcastLimit; + if (m_claimerArray.size() > m_BroadcastLimit) + { + m_claimerArray.clear(); + m_claimerArray.emplace_back(0, m_claimerArray.begin()->bcIndex); + } + + + for (const EquipNoBcIndex &enbi : m_claimerArray) + { + int curBcIndex = enbi.bcIndex; + int nextBcIndex = -1; + + while (true) + { + auto tel = getNachforderungsTelegram(curBcIndex, enbi.bcIndex, nextBcIndex); + curBcIndex = nextBcIndex; + if (tel) + { + auto copy(std::make_shared(*tel)); + copy->setIdentity(enbi.equipNo); + m_broadcastTelegamsToSend.push_back(copy); + } + else + break; + }; + + std::sort(m_broadcastTelegamsToSend.begin(), m_broadcastTelegamsToSend.end(), + [] (const std::shared_ptr &a, const std::shared_ptr &b) + { + const int bcIndexA = a->getTelID() == GEF_NOP ? a->getPayloadDataUInt32(3, 2) : a->getBroadcastIndex(); + const int bcIndexB = b->getTelID() == GEF_NOP ? b->getPayloadDataUInt32(3, 2) : b->getBroadcastIndex(); + if (bcIndexA != bcIndexB) + return bcIndexA > bcIndexB; + return a->getIdentity() < b->getIdentity(); + }); + + if (m_loggerBcRequest.isDebugEnabled()) + { + DEBUG_LOG(m_loggerBcRequest) << "Created broadcast list:"; + for (const auto &tele : m_broadcastTelegamsToSend) + DEBUG_LOG(m_loggerBcRequest) << "Identity: " << tele->getIdentity() + << ", bc: " << tele->getBroadcastIndex() + << ", type: " << tele->getTelID(); + } + } + m_claimerArray.clear(); + } +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::evaluateNextNachforderungToSend() +{ + if (m_broadcastTelegamsToSend.empty()) + { + m_State = e_ST_COLLECT; + return nullptr; + } + auto tel = m_broadcastTelegamsToSend.back(); + m_broadcastTelegamsToSend.pop_back(); + return tel; +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccumulationTelegram(int curBcIndex, + int startBcIndex, + gef_telegramm_id_et telId, + const QMap &bcIndex2Type, + int maxIdsPerTelegram, + int sizeOfSumField) const +{ + if (bcIndex2Type.isEmpty()) + return nullptr; + + auto itLastBcTele = m_BroadcastMap.end(); + --itLastBcTele; + const int endBcIndex = itLastBcTele->second->getBroadcastIndex(); + + DEBUG_LOG(m_loggerBcRequest) << "createAccumulationTelegram for telId " << telId + << ", begin: " << startBcIndex + << ", cur: " << curBcIndex << ", end: " << endBcIndex + << ", #elements in container: " << bcIndex2Type.size(); + DEBUG_LOG(m_loggerBcRequest) << "Given broadcast list for " << telegramId2String(telId); + for (auto it = bcIndex2Type.begin(); it != bcIndex2Type.end(); ++it) + DEBUG_LOG(m_loggerBcRequest) << " bcIndex: " << it.key() + << ", id: " << it.value(); + + + auto itStart = bcIndex2Type.lowerBound(startBcIndex); + if (itStart == bcIndex2Type.end()) + { + Q_ASSERT(false); + return nullptr; + } + auto itEnd = bcIndex2Type.lowerBound(endBcIndex); + if (itEnd == bcIndex2Type.end()) + --itEnd; + + const int completeTelegrams = std::distance(itStart, itEnd) + 1; + if (completeTelegrams <= 0) + { + Q_ASSERT(false); + return nullptr; + } + const auto itCur = bcIndex2Type.find(curBcIndex); + if (itCur == bcIndex2Type.end()) + { + Q_ASSERT(false); + return nullptr; + } + const int telegramsStillSendable = std::distance(itCur, itEnd) + 1; + if (telegramsStillSendable <= 0) + { + Q_ASSERT(false); + return nullptr; + } + + const int telegramsToSend = (completeTelegrams / maxIdsPerTelegram) + 1; + if (telegramsStillSendable > telegramsToSend) + { + INFO_LOG(m_loggerBcRequest) << telId << ": sending nop since accuTelegram is sent later (" << telegramsStillSendable + << ", need only " << telegramsToSend << ")"; + return nullptr; + } + + const int curIdStart = (telegramsToSend - telegramsStillSendable) * maxIdsPerTelegram; + const int idsToSendNow = (curIdStart + maxIdsPerTelegram <= completeTelegrams ? maxIdsPerTelegram : completeTelegrams % maxIdsPerTelegram); + INFO_LOG(m_loggerBcRequest) << telId << ": creating accuTelegram from index " << curIdStart << ", count: " << idsToSendNow; + + itStart += curIdStart; + + + auto tele(std::make_shared(telId, 3 + 2 + sizeOfSumField + sizeof(uint16_t) * idsToSendNow, 0)); + tele->setPayload2Byte(curBcIndex); + if (sizeOfSumField == 1) + tele->setPayload1Byte(idsToSendNow); + else if (sizeOfSumField == 2) + tele->setPayload2Byte(idsToSendNow); + else + { + Q_ASSERT(false); + return nullptr; + } + for (int i = 0; i < idsToSendNow; ++i) + { + tele->setPayload2Byte(itStart.value()); + ++itStart; + } + return tele; +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedAesAreas(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG, + m_deactivatedBcIndex2AesArea, 100, 1); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedFuncAreas(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM, + m_deactivatedBcIndex2FuncArea, 100, 1); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleDeactivatedDusMines(int curBcIndex, + int startBcIndex) const +{ + return createAccumulationTelegram(curBcIndex, startBcIndex, GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN, + m_deactivatedBcIndex2DusMine, 500, 2); +} + +std::shared_ptr PrtCnvBroadcastMgr::createAccuTeleActivatedDusMines(int curBcIndex) +{ + if (m_activatedDusMines.isEmpty()) + return {}; + + const int idsToSendNow = m_activatedDusMines.size(); + if (idsToSendNow > 500) + { + WARNING_LOG(m_logger) << "More than 500 activated DUS mines in system - this is not allowed!"; + Q_ASSERT(false); + return {}; + } + auto tele(std::make_shared(GEF_REAKTIVIERUNG_DUS_MINE, 5 + 2 + sizeof(uint16_t) * idsToSendNow, 0)); + tele->setPayload2Byte(curBcIndex); + tele->setPayload2Byte(idsToSendNow); + for (int dusMineId : qAsConst(m_activatedDusMines)) + tele->setPayload2Byte(dusMineId); + + return tele; +} + + + + + + + + + + + + + + + +std::shared_ptrPrtCnvBroadcastMgr::getNachforderungsTelegram(int curBcIndex, + int startBcIndex, + int &nextBcIndex) +{ + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex: " << curBcIndex + << ", startBcIndex: " << startBcIndex; + if (curBcIndex == 0) curBcIndex++; + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - curBcIndex after Ssnity: " << curBcIndex + << ", startBcIndex: " << startBcIndex; + + nextBcIndex = curBcIndex; + bool doSendNop = false; + + while (true) + { + auto iter = m_BroadcastMap.lower_bound(nextBcIndex); + if (iter == m_BroadcastMap.end()) + break; + + auto radioTelegram = iter->second; + DEBUG_LOG(m_loggerBcRequest) << "getNachforderungsTelegram - cur tel id is " << radioTelegram->getTelID() + << ", bcIndex: " << radioTelegram->getBroadcastIndex() + << ", send nop: " << doSendNop; + + if (nextBcIndex < iter->first) + { + + + doSendNop = true; + nextBcIndex = iter->first; + } + else if (radioTelegram->isBroadcastOnly()) + { + doSendNop = true; + nextBcIndex = iter->first + 1; + } + else + { + std::shared_ptr retTele; + switch (radioTelegram->getTelID()) + { + case GEF_DEAKTIVIERUNG_WIRKFELD: + retTele = createAccuTeleDeactivatedAesAreas(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + retTele = createAccuTeleDeactivatedFuncAreas(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_DEAKTIVIERUNG_EINZELMINE: + retTele = createAccuTeleDeactivatedDusMines(radioTelegram->getBroadcastIndex(), startBcIndex); + break; + case GEF_REAKTIVIERUNG_DUS_MINE: + retTele = createAccuTeleActivatedDusMines(radioTelegram->getBroadcastIndex()); + break; + default: + retTele = radioTelegram; + break; + } + + + if (retTele && doSendNop) + break; + ++nextBcIndex; + if (retTele) + return retTele; + doSendNop = true; + } + } + + + + if (!doSendNop && nextBcIndex <= m_BroadcastIndex) + { + nextBcIndex = m_BroadcastIndex + 1; + doSendNop = true; + } + + if (doSendNop) + { + + INFO_LOG(m_loggerBcRequest) << "Returning NOP: " << curBcIndex << " to " << nextBcIndex - 1; + return getNopTelegram(curBcIndex, nextBcIndex - 1); + } + + return nullptr; +} + + + + + + + +void PrtCnvBroadcastMgr::getAllFinishedBroadcastsFromDb(const bool a_doRestore) +{ + + + + + + + uint16_t broadcastIndex = 0; + while (true) + { + auto radioTelegram = m_DbThread->getNextBroadcastTelegram(); + if (!radioTelegram) + break; + broadcastIndex = radioTelegram->getBroadcastIndex(); + INFO_LOG(m_logger) << "Move Broadcast-telegram from DbThread>BroadcastMgr with telId=" + << radioTelegram->getTelID() << " BC=" << broadcastIndex; + dumpTelegram(m_logger, broadcastIndex, radioTelegram.get()); + + + + + + + + + + + + { + addToBroadcastMap(radioTelegram); + } + + if (a_doRestore && MAX_BROADCAST_INDEX == broadcastIndex) + handleOverrunOfBroadcastCounter(a_doRestore); + } + + if (m_logger.isDebugEnabled()) + { + static int iBroadcastDumpCounter = 0; + if ((iBroadcastDumpCounter++ % 30) == 0) + { + DEBUG_LOG(m_logger) << "Dumping broadcast map:"; + for (const auto &it : m_BroadcastMap) + dumpTelegram(m_logger, it.first, it.second.get()); + } + } + + + if (a_doRestore) + { + m_BroadcastIndex = broadcastIndex; + m_FinishedBroadcastIndex = m_BroadcastIndex; + } +} + + + + + + +void PrtCnvBroadcastMgr::addToBroadcastMap(const std::shared_ptr &a_radioTelegram) +{ + INFO_LOG(m_logger) << "Move from radioList to bcList: BC=" << a_radioTelegram->getBroadcastIndex() + << " telID=" << a_radioTelegram->getTelID(); + switch (a_radioTelegram->getTelID()) + { + + case GEF_INIT: + case GEF_UMGEBUNGS_MELDUNG2: + ERROR_LOG(m_logger) << "Internal error: telegram with telId=" << a_radioTelegram->getTelID() << " should never be a normal broadcast"; + break; + + case GEF_DATENVERKEHR_TDS_SRT: + case GEF_DATENVERKEHR_TDS_DMF: + case GEF_TREFFER_AUSLOESUNG: + case GEF_ALLGEMEINE_NACHRICHT: + addBroadcastOnlyTelegramToMap(a_radioTelegram); + break; + + + case GEF_SPRACHAUSWAHL: + case GEF_KONFIGURATION_WIRKMODELL: + case GEF_TEILNEHMERMODE_SETZEN: + case GEF_TEILNEHMER_KONFIG_SETZEN: + replaceLastTelegramAndAddAtEnd(a_radioTelegram); + break; + + case GEF_WIRKFELD_EINZELGESCHOSS: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER: + case GEF_WIRKFELD_MINENSPERRE: + case GEF_WIRKFELD_A_KAMPFMITTEL: + case GEF_WIRKFELD_C_KAMPFMITTEL: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + case GEF_WIRKFELD_STATUS_MINENSPERRE: + case GEF_WIRKFELD_EINZELMINENSIMULATOR: + { + + const uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + INFO_LOG(m_logger) << "Adding to braodcast map, Telegram Id: " << a_radioTelegram->getTelID() + << ", kennung: " << wirkfeldKennung; + if (isEffectSimulationIdDeactivated(wirkfeldKennung)) + { + INFO_LOG(m_logger) << "Got tele with tel id " << telegramId2String(a_radioTelegram->getTelID()) + << ", wirkfeldkennung: " << wirkfeldKennung << ", bcIndex: " << a_radioTelegram->getBroadcastIndex() + << " but this effect simulation is already deactivated... ignoring"; + dumpTelegram(m_logger, a_radioTelegram->getBroadcastIndex(), a_radioTelegram.get()); + emit areaEffectSimulationActivated(wirkfeldKennung); + } + else if (0 != wirkfeldKennung && wirkfeldKennung <= std::numeric_limits::max()) + { + switch (a_radioTelegram->getTelID()) + { + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN); + break; + case GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_FORTSETZEN: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_WIRKFELD_FLAECHENDECKENDES_FEUER_STOP); + break; + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + break; + case GEF_WIRKFELD_STATUS_MINENSPERRE: + + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung, GEF_DEAKTIVIERUNG_EINZELMINE); + break; + default: + removeWirkfeldTelegrams(wirkfeldKennung); + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + removeFromDeactivatedAesArea(wirkfeldKennung); + emit areaEffectSimulationActivated(wirkfeldKennung); + break; + } + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung; + } + break; + } + + case GEF_WIRKFELD_AENDERUNG_BEZEICHNER: + { + auto wirkfeldTyp = static_cast(a_radioTelegram->getPayloadDataUInt32(5, 1)); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + INFO_LOG(m_logger) << "addToBroadcastMap - Wirkfeld Aenderung Bezeichner for type " + << wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: " + << wirkfeldKennung; + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + break; + } + case GEF_DEAKTIVIERUNG_WIRKFELD: + { + auto wirkfeldTyp = static_cast(a_radioTelegram->getPayloadDataUInt32(5, 1)); + uint16_t wirkfeldKennung = a_radioTelegram->getPayloadDataUInt32(6, 2); + INFO_LOG(m_logger) << "Deaktivierung Wirkfeld for type " + << wirkfeldTyp2Str(wirkfeldTyp) << " - kennung: " + << wirkfeldKennung << ", bc: " << a_radioTelegram->getBroadcastIndex(); + switch (wirkfeldTyp) + { + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::MineArea: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionArea: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::ExplosionSingle: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::NContamination: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::CContamination: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DusSingleMineSimulator: + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::DangerZoneExplosion: + if (0 != wirkfeldKennung && wirkfeldKennung <= 32767) + { + emit areaEffectSimulationDeactivated(wirkfeldKennung); + + removeWirkfeldTelegrams(wirkfeldKennung); + if (addToDeactivatedAesArea(wirkfeldKennung, a_radioTelegram->getBroadcastIndex())) + addWirkfeldTelegram(a_radioTelegram, wirkfeldKennung); + } + else + { + + ERROR_LOG(m_logger) << "Internal error: Got invalid kennung: " << wirkfeldKennung; + } + break; + case TrainingAreaBase::TetraIcd::AreaEffectSimulationType::FunctionalArea: + default: + + ERROR_LOG(m_logger) << "Internal error: WirkfeldTyp " << wirkfeldTyp2Str(wirkfeldTyp) << " in GEF_DEAKTIVIERUNG_WIRKFELD not implemented"; + } + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + deactivateSingleMine(a_radioTelegram); + break; + } + + case GEF_REAKTIVIERUNG_DUS_MINE: + { + reactivateDusMine(a_radioTelegram); + break; + } + + case GEF_TECHNIK_FUNKTIONSRAUM: + { + + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + + removeFromTechnikFunktionsAndBroadcastMaps(funktionsraumkennung); + + + m_TechnikFunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_FUNKTIONSRAUM: + { + + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + + removeFromFunktionsAndBroadcastMaps(funktionsraumkennung); + removeFromDeactivatedFuncArea(funktionsraumkennung); + + + m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + + + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + case GEF_DEAKTIVIEREN_FUNKTIONSRAUM: + { + uint16_t funktionsraumkennung = a_radioTelegram->getPayloadDataUInt32(5, 2); + emit areaEffectSimulationDeactivated(funktionsraumkennung); + + removeFromFunktionsAndBroadcastMaps(funktionsraumkennung); + if (addToDeactivatedFuncArea(funktionsraumkennung, a_radioTelegram->getBroadcastIndex())) + m_FunktionsraumTelegramMap.insert(std::make_pair(funktionsraumkennung, a_radioTelegram)); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + break; + } + + default: + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + +} + + +template +bool removeFromContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId) +{ + auto it = id2bcIndex.find(aesAreaId); + if (it == id2bcIndex.end()) + return false; + BcIndex2id.remove(it.value()); + id2bcIndex.erase(it); + return true; +} + +template +bool addToContainers(T &id2bcIndex, S &BcIndex2id, int aesAreaId, int bcIndex) +{ + auto it = id2bcIndex.find(aesAreaId); + if (it != id2bcIndex.end()) + { + if (it.value() == bcIndex) + return false; + BcIndex2id.remove(it.value()); + } + id2bcIndex[aesAreaId] = bcIndex; + BcIndex2id[bcIndex] = aesAreaId; + return true; +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedAesArea(int aesAreaId) +{ + return removeFromContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId); +} + + +bool PrtCnvBroadcastMgr::addToDeactivatedAesArea(int aesAreaId, int bcIndex) +{ + return addToContainers(m_deactivatedAesArea2bcIndex, m_deactivatedBcIndex2AesArea, aesAreaId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedFuncArea(int aesAreaId) +{ + return removeFromContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId); +} + +bool PrtCnvBroadcastMgr::addToDeactivatedFuncArea(int aesAreaId, int bcIndex) +{ + return addToContainers(m_deactivatedFuncArea2bcIndex, m_deactivatedBcIndex2FuncArea, aesAreaId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromDeactivatedDusMine(int dusMineId) +{ + return removeFromContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId); +} + +bool PrtCnvBroadcastMgr::addToDeactivatedDusMine(int dusMineId, int bcIndex) +{ + return addToContainers(m_deactivatedDusMine2bcIndex, m_deactivatedBcIndex2DusMine, dusMineId, bcIndex); +} + +bool PrtCnvBroadcastMgr::removeFromActivatedDusMine(int dusMineId) +{ + return (m_activatedDusMines.remove(dusMineId)); +} + +void PrtCnvBroadcastMgr::addToActivatedDusMine(int dusMineId) +{ + m_activatedDusMines.insert(dusMineId); +} + + + + + +int PrtCnvBroadcastMgr::getSammeltelegramIndex(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung) const +{ + + uint16_t nbrLength = 0; + switch (a_sammelTelegram->getTelID()) + { + case GEF_WF_SAMMELDEAKTIVIERUNG: + case GEF_WF_SAMMELDEAKTIVIERUNG_FUNKTIONSRAUM: + nbrLength = 1; + break; + case GEF_WF_SAMMELDEAKTIVIERUNG_DUS_MINEN: + case GEF_REAKTIVIERUNG_DUS_MINE: + nbrLength = 2; + break; + default: + ERROR_LOG(m_logger) << "Unknown Sammeltelegram with telId=" << a_sammelTelegram->getTelID(); + return -1; + } + + const int cntAesIds = a_sammelTelegram->getPayloadDataUInt32(5, nbrLength); + for (int i = 0; i < cntAesIds; i++) + { + if (a_kennung == a_sammelTelegram->getPayloadDataUInt32(5 + nbrLength + i * 2, 2)) + return i; + } + return -1; +} + + + + + + + +void PrtCnvBroadcastMgr::deactivateSingleMine(const std::shared_ptr &a_radioTelegram) +{ + uint32_t wirkfeldkennung = a_radioTelegram->getPayloadDataUInt32(9, 2); + uint32_t minenkennung = a_radioTelegram->getPayloadDataUInt32(11, 2); + + if (0 == wirkfeldkennung) + { + removeFromActivatedDusMine(minenkennung); + addToDeactivatedDusMine(minenkennung, a_radioTelegram->getBroadcastIndex()); + DEBUG_LOG(m_logger) << "Deactivating DUS-Mine: " << minenkennung << ", #deactivated mines: " << m_deactivatedBcIndex2DusMine.size(); + removeDusMineDeactivationFromBroadcastMap(minenkennung); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); + } + else + { + + bool sentAsNormalBroadcastFinished = deactivateEinzelmineFromMinensperre(wirkfeldkennung, minenkennung, a_radioTelegram->getBroadcastIndex()); + if (sentAsNormalBroadcastFinished) + { + + addWirkfeldTelegram(a_radioTelegram, wirkfeldkennung, GEF_BESTAETIGUNG, minenkennung); + addBroadcastOnlyTelegramToMap(a_radioTelegram); + } + else + { + + + + + + } + } +} + + + + + + + + + +bool PrtCnvBroadcastMgr::deactivateEinzelmineFromMinensperre(const uint16_t a_wirkfeldKennung, + const uint16_t a_minenKennung, + const uint16_t a_broadcastIndex) +{ + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_wirkfeldKennung) break; + + auto radioTelegram = iter->second; + if (radioTelegram->getTelID() == GEF_WIRKFELD_STATUS_MINENSPERRE && a_wirkfeldKennung == radioTelegram->getPayloadDataUInt32(5, 2)) + { + + uint16_t nbrOfMines = radioTelegram->getPayloadDataUInt32(7, 2); + if (nbrOfMines >= a_minenKennung && a_minenKennung != 0) + { + + + uint16_t bytePos = 9 + (a_minenKennung - 1) / 8; + if (bytePos < radioTelegram->getPayloadSize()) + { + uint8_t mask = 0x80 >> ((a_minenKennung - 1) % 8); + + + radioTelegram->setPayloadDataWithIndex(bytePos, (uint8_t)(radioTelegram->getPayloadDataUInt8(bytePos) & (~mask)), 1); + moveTelegramInBroadcastMap(radioTelegram, a_broadcastIndex); + + + + + + bool dummy; + if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), dummy, false)) + { + INFO_LOG(m_logger) << "A normal broadcast-telegram WirkfeldStatusMinensperre still exists"; + return false; + } + return true; + } + else + ERROR_LOG(m_logger) << "Got corrupt telegram WirkfeldstatusMinensperre with nbrOfMines=" << nbrOfMines << " and payloadSize=" << radioTelegram->getPayloadSize(); + } + else + { + + ERROR_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " does not fit into status (nbrOfMines=" << nbrOfMines << ")"; + } + return true; + } + ++iter; + } + ERROR_LOG(m_logger) << "Did not find the WirkfeldStatusMinensperre with kennung=" << a_wirkfeldKennung + << ", therefore deactivated mine with kennung=" << a_minenKennung << " could not be updated."; + return true; +} + + + + + + +void PrtCnvBroadcastMgr::reactivateDusMine(const std::shared_ptr &a_radioTelegram) +{ + + const uint32_t nbrOfMines = a_radioTelegram->getPayloadDataUInt32(5, 2); + + DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, #mines: " << nbrOfMines; + if (0 == nbrOfMines) + { + + for (int dusMineId : qAsConst(m_deactivatedBcIndex2DusMine)) + { + removeDusMineDeactivationFromBroadcastMap(dusMineId); + addToActivatedDusMine(dusMineId); + } + m_deactivatedDusMine2bcIndex.clear(); + m_deactivatedBcIndex2DusMine.clear(); + } + else + { + + for (uint32_t i = 0; i < nbrOfMines; i++) + { + const int dusMineId = a_radioTelegram->getPayloadDataUInt32(7 + 2 * i, 2); + DEBUG_LOG(m_logger) << "Reactivating DUS-Mines, mindId: " << dusMineId; + removeDusMineDeactivationFromBroadcastMap(dusMineId); + removeFromDeactivatedDusMine(dusMineId); + addToActivatedDusMine(dusMineId); + } + } + + auto pred = [](const std::shared_ptr &tele) -> bool + { + return (tele->getTelID() == GEF_REAKTIVIERUNG_DUS_MINE); + }; + removeFromBroadcastMapFunc(pred); + m_BroadcastMap.insert(std::make_pair(a_radioTelegram->getBroadcastIndex(), a_radioTelegram)); +} + + + + + + +void PrtCnvBroadcastMgr::addWirkfeldTelegram(const std::shared_ptr &a_radioTelegram, + const uint16_t a_wirkfeldKennung, + const gef_telegramm_id_et a_telId, + const uint16_t a_minenKennung) +{ + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_wirkfeldKennung) + break; + auto radioTelegram = iter->second; + + bool isSameMine = true; + if (0 != a_minenKennung) + { + if (GEF_DEAKTIVIERUNG_EINZELMINE == a_radioTelegram->getTelID()) + { + if (GEF_DEAKTIVIERUNG_EINZELMINE == radioTelegram->getTelID()) + { + uint16_t mineIndex = radioTelegram->getPayloadDataUInt32(11, 2); + isSameMine = mineIndex == a_minenKennung; + INFO_LOG(m_logger) << "Mine with kennung=" << a_minenKennung << " found: " << isSameMine; + } + } + else + ERROR_LOG(m_logger) << "Internal error: Only telegrams 'Deaktivierung_Einzelmine' must be called with a_mineKennung. I proceed without respecting mine-kennung..."; + } + + if ((radioTelegram->getTelID() == a_radioTelegram->getTelID() || radioTelegram->getTelID() == a_telId) && isSameMine) + { + + removeFromWirkfeldAndBroadcastMaps(iter); + iter = m_WirkfeldTelegramMapByKennung.find(a_wirkfeldKennung); + } + else + ++iter; + } + + + INFO_LOG(m_logger) << "Add kennung: " << a_wirkfeldKennung + << " telId=" << a_radioTelegram->getTelID() + << " BC=" << a_radioTelegram->getBroadcastIndex(); + m_WirkfeldTelegramMapByKennung.insert(std::make_pair(a_wirkfeldKennung, a_radioTelegram)); + time_t expireTime = a_radioTelegram->getExpireTime(); + if (expireTime > 0) + m_WirkfeldTelegramMapByTime.insert(std::make_pair(expireTime, a_radioTelegram)); +} + + + + + + + + +void PrtCnvBroadcastMgr::removeWirkfeldTelegrams(const uint16_t a_kennung) +{ + INFO_LOG(m_logger) << "Removing all Wirkfeld-Telegrams with kennung=" << a_kennung; + + auto iter = m_WirkfeldTelegramMapByKennung.find(a_kennung); + while (iter != m_WirkfeldTelegramMapByKennung.end()) + { + if (iter->first != a_kennung) + break; + + removeFromWirkfeldAndBroadcastMaps(iter); + + iter = m_WirkfeldTelegramMapByKennung.find(a_kennung); + } +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung) +{ + auto iter = m_FunktionsraumTelegramMap.find(a_funktionsraumKennung); + if (iter != m_FunktionsraumTelegramMap.end()) + { + auto radioTelegram = iter->second; + + + INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung + << " and BC=" << radioTelegram->getBroadcastIndex(); + m_FunktionsraumTelegramMap.erase(iter); + + removeFromBroadcastMap(radioTelegram); + } +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromTechnikFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung) +{ + auto iter = m_TechnikFunktionsraumTelegramMap.find(a_funktionsraumKennung); + if (iter != m_TechnikFunktionsraumTelegramMap.end()) + { + auto radioTelegram = iter->second; + + + INFO_LOG(m_logger) << "Removing Funktionsraum-telegram with kennung=" << a_funktionsraumKennung + << " and BC=" << radioTelegram->getBroadcastIndex(); + m_TechnikFunktionsraumTelegramMap.erase(iter); + + removeFromBroadcastMap(radioTelegram); + } +} + + + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromWirkfeldAndBroadcastMaps(const std::multimap>::iterator &a_wirkfeldTelegramMapByKennungIterator) +{ + auto radioTelegram = a_wirkfeldTelegramMapByKennungIterator->second; + + INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID() + << ", kennung=" << a_wirkfeldTelegramMapByKennungIterator->first + << " and BC=" << radioTelegram->getBroadcastIndex() + << " from byWirkfeldKennung-map"; + + + m_WirkfeldTelegramMapByKennung.erase(a_wirkfeldTelegramMapByKennungIterator); + + + time_t expireTime = radioTelegram->getExpireTime(); + if (0 != expireTime) + { + auto iter = m_WirkfeldTelegramMapByTime.find(expireTime); + while (iter != m_WirkfeldTelegramMapByTime.end()) + { + if (iter->second == radioTelegram) + { + INFO_LOG(m_logger) << "Removing wirkfeld-telegram with telId=" << radioTelegram->getTelID() + << " also from byTime-map"; + m_WirkfeldTelegramMapByTime.erase(iter); + break; + } + ++iter; + } + } + + removeFromBroadcastMap(radioTelegram); +} + + + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromBroadcastMap(const std::shared_ptr &a_radioTelegram) +{ + + if (!a_radioTelegram) + return; + + auto iter = m_BroadcastMap.find(a_radioTelegram->getBroadcastIndex()); + if (iter != m_BroadcastMap.end()) + { + if (iter->second == a_radioTelegram) + { + m_BroadcastMap.erase(iter); + detachTelegram(a_radioTelegram); + } + else if (iter->second->getBroadcastonlyTelegram() == a_radioTelegram) + iter->second->setBroadcastonlyTelegram(nullptr); + } +} + +void PrtCnvBroadcastMgr::removeFromBroadcastMapFunc(const std::function &)> &pred) +{ + auto it = m_BroadcastMap.begin(); + while (it != m_BroadcastMap.end()) + { + const auto &p = *it; + if (pred(p.second)) + it = m_BroadcastMap.erase(it); + else + ++it; + } +} + +void PrtCnvBroadcastMgr::removeDusMineDeactivationFromBroadcastMap(int dusMineId) +{ + auto pred = [dusMineId](const std::shared_ptr &tele) -> bool + { + return (tele->getTelID() == GEF_DEAKTIVIERUNG_EINZELMINE && + 0 == tele->getPayloadDataUInt32(9, 2) && + uint32_t(dusMineId) == tele->getPayloadDataUInt32(11, 2)); + }; + removeFromBroadcastMapFunc(pred); +} + +template +void removeFromMap(T &cont, const std::shared_ptr &a_radioTelegram) +{ + auto iter = cont.begin(); + while (iter != cont.end()) + { + if (iter->second == a_radioTelegram) + iter = cont.erase(iter); + else + ++iter; + } +} + + + + + + + + + + +void PrtCnvBroadcastMgr::removeFromAllMaps(const std::shared_ptr &a_radioTelegram) +{ + INFO_LOG(m_logger) << "Remove telegram with telId=" << a_radioTelegram->getTelID() << " BC=" << a_radioTelegram->getBroadcastIndex(); + + removeFromBroadcastMap(a_radioTelegram); + + + removeFromMap(m_WirkfeldTelegramMapByKennung, a_radioTelegram); + + + removeFromMap(m_WirkfeldTelegramMapByTime, a_radioTelegram); + + + removeFromMap(m_FunktionsraumTelegramMap, a_radioTelegram); + + + removeFromMap(m_LastTelegramMap, a_radioTelegram); +} + + + + + +void PrtCnvBroadcastMgr::replaceLastTelegramAndAddAtEnd(const std::shared_ptr &a_newRadioTelegram) +{ + + auto iter = m_LastTelegramMap.find(a_newRadioTelegram->getTelID()); + if (iter != m_LastTelegramMap.end()) + { + auto lastRadioTelegram = iter->second; + + INFO_LOG(m_logger) << "remove last telegram with telId=" << lastRadioTelegram->getTelID() + << " and BC=" << lastRadioTelegram->getBroadcastIndex(); + removeFromBroadcastMap(lastRadioTelegram); + m_LastTelegramMap.erase(iter); + } + + m_BroadcastMap.insert(std::make_pair(a_newRadioTelegram->getBroadcastIndex(), a_newRadioTelegram)); + + m_LastTelegramMap.insert(std::make_pair(a_newRadioTelegram->getTelID(), a_newRadioTelegram)); + INFO_LOG(m_logger) << "New last telegram with with telId=" << a_newRadioTelegram->getTelID() + << " and BC=" << a_newRadioTelegram->getBroadcastIndex(); +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::moveTelegramInBroadcastMap(const std::shared_ptr &a_radioTelegram, + const uint16_t a_newBroadcastIndex, + const std::shared_ptr &a_attachTelegram) +{ + + INFO_LOG(m_logger) << "Move telId=" << a_radioTelegram->getTelID() + << " from BC=" << a_radioTelegram->getBroadcastIndex() + << " to BC=" << a_newBroadcastIndex; + removeFromBroadcastMap(a_radioTelegram); + + a_radioTelegram->setBroadcastIndex(a_newBroadcastIndex); + m_BroadcastMap.insert(std::make_pair(a_newBroadcastIndex, a_radioTelegram)); + + if (a_attachTelegram && (a_attachTelegram->getTelID() != GEF_REAKTIVIERUNG_DUS_MINE)) + { + INFO_LOG(m_logger) << "Attach telID=" << a_attachTelegram->getTelID() + << " to telID=" << a_radioTelegram->getTelID() + << " BC=" << a_newBroadcastIndex; + a_radioTelegram->setBroadcastonlyTelegram(a_attachTelegram); + a_attachTelegram->setBroadcastIndex(a_newBroadcastIndex); + } +} + + + + + +uint16_t PrtCnvBroadcastMgr::getBroadcastIndex() const +{ + return m_BroadcastIndex; +} + + + + + +uint16_t PrtCnvBroadcastMgr::getNextBroadcastIndex() +{ + return ++m_BroadcastIndex; +} + + + + + +std::shared_ptr PrtCnvBroadcastMgr::getNopTelegram(const uint16_t a_from, const uint16_t a_to) +{ + auto nopTelegram(std::make_shared(GEF_NOP, 7, 0)); + nopTelegram->setPayloadDataWithIndex(3, a_from, 2); + nopTelegram->setPayloadDataWithIndex(5, a_to, 2); + return nopTelegram; +} + + + + + + + + + + + +void PrtCnvBroadcastMgr::addBroadcastOnlyTelegramToMap(const std::shared_ptr &a_broadcastOnlyTelegram) +{ + uint16_t broadcastIndex = a_broadcastOnlyTelegram->getBroadcastIndex(); + auto iter = m_BroadcastMap.find(broadcastIndex); + if (m_BroadcastMap.end() == iter) + { + + INFO_LOG(m_logger) << "Insert telId=" << a_broadcastOnlyTelegram->getTelID() + << " as broadcastonly telegram with BC=" << broadcastIndex; + a_broadcastOnlyTelegram->setBroadcastOnly(); + m_BroadcastMap.insert(std::make_pair(broadcastIndex, a_broadcastOnlyTelegram)); + } + else + { + + INFO_LOG(m_logger) << "Add telId=" << a_broadcastOnlyTelegram->getTelID() + << " as broadcastonly telegram to telegramm with BC=" << iter->second->getBroadcastIndex(); + iter->second->setBroadcastonlyTelegram(a_broadcastOnlyTelegram); + } +} + + + + + + +void PrtCnvBroadcastMgr::detachTelegram(const std::shared_ptr &a_radioTelegram) +{ + auto broadcastOnlyTelegram = a_radioTelegram->getBroadcastonlyTelegram(); + if (broadcastOnlyTelegram) + { + uint16_t broadcastIndex = a_radioTelegram->getBroadcastIndex(); + + INFO_LOG(m_logger) << "detach bconly-telegram : telId=" << a_radioTelegram->getTelID() << " BC=" << broadcastIndex; + if (broadcastOnlyTelegram->getBroadcastIndex() != broadcastIndex) + ERROR_LOG(m_logger) << "Internal error: BC=" << broadcastOnlyTelegram->getBroadcastIndex() << " of attached telegram is not equal BC=" << broadcastIndex; + auto iter = m_BroadcastMap.find(broadcastIndex); + if (iter != m_BroadcastMap.end()) + ERROR_LOG(m_logger) << "Internal error: m_BroadcastMap-entry with BC=" << broadcastIndex << " must not exists"; + else + { + INFO_LOG(m_logger) << "Insert broadcast-only BC=" << broadcastOnlyTelegram->getBroadcastIndex(); + broadcastOnlyTelegram->setBroadcastOnly(); + m_BroadcastMap.insert(std::make_pair(broadcastIndex, broadcastOnlyTelegram)); + } + a_radioTelegram->setBroadcastonlyTelegram(nullptr); + } +} + + + + + + +void PrtCnvBroadcastMgr::handleOverrunOfBroadcastCounter(const bool a_doRestore) +{ + WARNING_LOG(m_logger) << "Broadcast-counter reaches maximum => reduce broadcast-list and increment reset-counter"; + + + + if (!a_doRestore) + { + m_DbThread->waitUntilDbWritten(); + getAllFinishedBroadcastsFromDb(); + } + + + uint16_t newBroadcastCounter = 0; + std::map> newBroadcastMap; + auto iter = m_BroadcastMap.begin(); + while (iter != m_BroadcastMap.end()) + { + auto radioTelegram = iter->second; + if (radioTelegram->isBroadcastOnly()) + { + + ++iter; + removeFromAllMaps(radioTelegram); + } + else + { + radioTelegram->setBroadcastIndex(++newBroadcastCounter); + auto broadcastOnlyTelegram = radioTelegram->getBroadcastonlyTelegram(); + if (broadcastOnlyTelegram) + { + radioTelegram->setBroadcastonlyTelegram(nullptr); + ++iter; + removeFromAllMaps(broadcastOnlyTelegram); + } + else + { + + + bool wasLast; + if (radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), wasLast, false)) + { + do + { + radioTelegram->mustBeSentAsBroadcast(std::numeric_limits::max(), wasLast, true); + } + while (!wasLast); + } + ++iter; + } + INFO_LOG(m_logger) << "New BC-index for broadcast-telegram with telId=" << radioTelegram->getTelID() << " BC=" << newBroadcastCounter; + newBroadcastMap.insert(std::make_pair(newBroadcastCounter, radioTelegram)); + } + } + m_BroadcastMap.clear(); + m_BroadcastMap = newBroadcastMap; + + + cleanAndInit(false); + if (!a_doRestore) m_DbThread->setResetCounter(m_DbThread->getResetCounter() + 1); + + WARNING_LOG(m_logger) << "New broadcast-counter=" << newBroadcastCounter << " new reset-counter=" << (int)m_DbThread->getResetCounter(); + m_BroadcastIndex = newBroadcastCounter; +} + + + + + +void PrtCnvBroadcastMgr::restoreAfterCrash() +{ + getAllFinishedBroadcastsFromDb(true); +} + + + + + +void PrtCnvBroadcastMgr::dump() +{ + + for (const auto &it : m_BroadcastMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_BroadcastMap, "); + + for (const auto &it : m_WirkfeldTelegramMapByKennung) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByKennung, "); + + for (const auto &it : m_WirkfeldTelegramMapByTime) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_WirkfeldTelegramMapByTime, "); + + for (const auto &it : m_FunktionsraumTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_FunktionsraumTelegramMap, "); + + for (const auto &it : m_TechnikFunktionsraumTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_TechnikFunktionsraumTelegramMap, "); + + for (const auto &it : m_LastTelegramMap) + dumpTelegram(m_loggerBcRequest, it.first, it.second.get(), "m_LastTelegramMap, "); +} + + + + + + +void PrtCnvBroadcastMgr::incTickAndSetTrafficLoad(const bool a_isHighLoad, const bool a_isFullLoad) +{ + if (e_ST_COLLECT == m_State) + ++m_TickCounter; + m_IsFullLoad = a_isFullLoad; + if (a_isHighLoad) + m_ActClaimWindow = m_HighLoadFactor * m_ClaimWindow; + else + m_ActClaimWindow = m_ClaimWindow; +} + + + + +bool PrtCnvBroadcastMgr::isEffectSimulationIdDeactivated(const uint16_t effectsimulationId) const +{ + INFO_LOG(m_logger) << "Checking deactivation for Id " << effectsimulationId; + return m_deactivatedAesArea2bcIndex.contains(effectsimulationId); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp new file mode 100644 index 000000000..7b424aa6f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvBroadcastMgr.hpp @@ -0,0 +1,359 @@ + + + + + + + + + + + + + +#pragma once + +#include "logger.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace N_CoPrtCnv +{ +class CoPrtCnvRadioTelegram; +} + +#define MAX_BROADCAST_INDEX 65535 + + +namespace PrtCnv +{ +class PrtCnvDbThread; + + + +class PrtCnvBroadcastMgr final : public QObject +{ + Q_OBJECT +public: + + + + enum E_State + { + e_ST_UNDEFINED, + e_ST_COLLECT, + e_ST_SEND_NACHFORDERUNG + }; + + PrtCnvBroadcastMgr(); + + + + bool handleRadioTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + + + int32_t create(NGL::Settings *settings); + + + + int32_t init(); + + + + std::shared_ptr getNextBroadcastTelegramToSend(const uint16_t a_beginSearchWithBroadcastIndex, + const time_t a_currentTime); + + + + void setDbThread(PrtCnvDbThread *a_dbThread); + + + + + void cleanAndInit(const bool a_deleteTelegrams); + + + + + void handleOverrunOfBroadcastCounter(const bool a_doRestore = false); + + + + std::shared_ptr getNextNachforderungTelegramToSend(); + + + + void dump(); + + + + + void restoreAfterCrash(); + + + + + uint16_t getBroadcastIndex() const; + + + + uint16_t getNextBroadcastIndex(); + + + + void addBroadcastOnlyTelegramToMap(const std::shared_ptr &a_broadcastOnlyTelegram); + + + + void incTickAndSetTrafficLoad(const bool a_isHighLoad, const bool a_isFullLoad); + + + + bool isEffectSimulationIdDeactivated(const uint16_t effectsimulationId) const; + + + + void handleNachforderungBroadcastTelegram(int identity, int broadcastIndex, int resetCounter); + +protected: + struct EquipNoBcIndex + { + int equipNo = 0; + int bcIndex = 0; + + EquipNoBcIndex() = default; + EquipNoBcIndex(int e, int b) : equipNo(e), bcIndex(b) {} + }; + + + std::vector m_claimerArray; + + + uint16_t m_ClaimWindow; + + + uint16_t m_HighLoadFactor; + + + uint16_t m_BroadcastLimit; + + + NGL::Settings *m_Config; + + + uint16_t m_ActClaimWindow; + + + PrtCnvBroadcastMgr::E_State m_State; + uint16_t m_TickCounter; + + + PrtCnvDbThread *m_DbThread; + + + + + std::map> m_BroadcastMap; + + std::vector> m_broadcastTelegamsToSend; + + + + std::map> m_LastTelegramMap; + + + + + std::multimap> m_WirkfeldTelegramMapByKennung; + + + + + std::multimap> m_WirkfeldTelegramMapByTime; + + + + + std::map> m_FunktionsraumTelegramMap; + + + + + std::map> m_TechnikFunktionsraumTelegramMap; + + + + + uint16_t m_BroadcastIndex; + + + + bool m_IsFullLoad; + + + uint16_t m_FinishedBroadcastIndex; + + + uint16_t m_FirstBroadcastIndexOfBc1; + + + + void addToBroadcastMap(const std::shared_ptr &a_radioTelegram); + + + + std::shared_ptr getNachforderungsTelegram(int curBcIndex, int startBcIndex, int &nextBcIndex); + + + + int getSammeltelegramIndex(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung) const; + + + + void moveTelegramInBroadcastMap(const std::shared_ptr &a_radioTelegram, + const uint16_t a_newBroadcastIndex, + const std::shared_ptr &a_attachTelegram = {}); + + + + void removeFromBroadcastMap(const std::shared_ptr &a_radioTelegram); + void removeFromBroadcastMapFunc(const std::function &)> &pred); + void removeDusMineDeactivationFromBroadcastMap(int dusMineId); + + std::shared_ptr createAccumulationTelegram(int curBcIndex, + int startBcIndex, + gef_telegramm_id_et telId, + const QMap &bcIndex2Type, + int maxIdsPerTelegram, + int sizeOfSumField) const; + + bool removeFromDeactivatedAesArea(int aesAreaId); + bool addToDeactivatedAesArea(int aesAreaId, int bcIndex); + + QHash m_deactivatedAesArea2bcIndex; + + QMap m_deactivatedBcIndex2AesArea; + std::shared_ptrcreateAccuTeleDeactivatedAesAreas(int curBcIndex, int startBcIndex) const; + + bool removeFromDeactivatedFuncArea(int aesAreaId); + bool addToDeactivatedFuncArea(int aesAreaId, int bcIndex); + + QHash m_deactivatedFuncArea2bcIndex; + + QMap m_deactivatedBcIndex2FuncArea; + std::shared_ptrcreateAccuTeleDeactivatedFuncAreas(int curBcIndex, int startBcIndex) const; + + bool removeFromDeactivatedDusMine(int dusMineId); + bool addToDeactivatedDusMine(int dusMineId, int bcIndex); + + QHash m_deactivatedDusMine2bcIndex; + + QMap m_deactivatedBcIndex2DusMine; + std::shared_ptr createAccuTeleDeactivatedDusMines(int curBcIndex, int startBcIndex) const; + + bool removeFromActivatedDusMine(int dusMineId); + void addToActivatedDusMine(int dusMineId); + QSet m_activatedDusMines; + std::shared_ptr createAccuTeleActivatedDusMines(int curBcIndex); + + + + bool removeFromSammeltelegram(const std::shared_ptr &a_sammelTelegram, + const uint16_t a_kennung, + const uint16_t a_anzahlPos, + const uint8_t a_anzahlSize, + bool &a_sammelTelRemoved); + + + + void replaceLastTelegramAndAddAtEnd(const std::shared_ptr &a_newRadioTelegram); + + + + + std::string dumpSammeldeaktivierung(const N_CoPrtCnv::CoPrtCnvRadioTelegram *sammelTelegram); + + + + void getAllFinishedBroadcastsFromDb(const bool a_doRestore = false); + + + + + void removeExpiredTelegrams(); + + + + void removeWirkfeldTelegrams(const uint16_t a_kennung); + + + + void addWirkfeldTelegram(const std::shared_ptr &a_radioTelegram, + const uint16_t a_wirkfeldKennung, const gef_telegramm_id_et a_telId = GEF_BESTAETIGUNG, + const uint16_t a_minenKennung = 0); + + + + bool deactivateEinzelmineFromMinensperre(const uint16_t a_wirkfeldKennung, const uint16_t a_minenKennung, const uint16_t a_broadcastIndex); + + + + std::shared_ptr getNopTelegram(const uint16_t a_from, const uint16_t a_to); + + + void removeFromAllMaps(const std::shared_ptr &a_radioTelegram); + + + + void detachTelegram(const std::shared_ptr &a_radioTelegram); + + + + void removeFromFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung); + void removeFromTechnikFunktionsAndBroadcastMaps(const uint16_t a_funktionsraumKennung); + + + + void removeFromWirkfeldAndBroadcastMaps(const std::multimap>::iterator &a_wirkfeldTelegramMapByKennungIterator); + + + + void reactivateDusMine(const std::shared_ptr &a_radioTelegram); + + + + void deactivateSingleMine(const std::shared_ptr &a_radioTelegram); + + + + void prepareForSendNachforderungen(); + + + + std::shared_ptr evaluateNextNachforderungToSend(); + +Q_SIGNALS: + void areaEffectSimulationActivated(int wirkfeldKennung); + void areaEffectSimulationDeactivated(int wirkfeldKennung); + +private: + + + NGL::INGLLogger &m_logger; + NGL::INGLLogger &m_loggerBcRequest; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvCentralThread.cpp b/TetraIF/PrtCnv/PrtCnvCentralThread.cpp new file mode 100644 index 000000000..4e2b3c736 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvCentralThread.cpp @@ -0,0 +1,842 @@ + + + + + + + + + + + + + + +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvStoredCentralTelegram.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + + +PrtCnvCentralThread::PrtCnvCentralThread(PrtCnv::PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvCentralThread") + , m_webSocket(nullptr) + , m_SendCounter(0) + , m_RadioThread(nullptr) + , m_RadioStopped(false) + , m_CentralStopped(false) + , m_LastSendCounter(0) + , m_VirtualTeilnehmerId(0) + , m_maxEqID(50000) + , m_aliveTimer(nullptr) + , m_sendAckTimer(nullptr) + , m_reconnectTimer(nullptr) + , m_DbThread(nullptr) + , m_LogThread(nullptr) + , m_InjectionThread(nullptr) + , m_ReceiveCounter(0) + , m_ReceiveAckCounter(0) + , m_State(PrtCnvSocketThread::e_INITIAL) + , m_bDirectConnection(false) + , m_bRadioThreadInitDone(false) +{ + m_Name = QStringLiteral("Central"); +} + +PrtCnvCentralThread::~PrtCnvCentralThread() +{ + destroy(); +} + + + + +int32_t PrtCnvCentralThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + INFO_LOG(m_logger) << "Create"; + + m_RadioThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Radio)); + m_DbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + m_LogThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Log)); + m_InjectionThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Injection)); + connect(m_DbThread, &PrtCnvDbThread::playerLicencedChanged, + this, &PrtCnvCentralThread::onPlayerLicencedChanged, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::checkSendToCentral, this, &PrtCnvCentralThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::checkSendToRadio, m_RadioThread, &PrtCnvRadioThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::stopRadio, m_RadioThread, &PrtCnvRadioThread::doStop, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::cleanRadio, m_RadioThread, &PrtCnvRadioThread::doClean, Qt::QueuedConnection); + connect(this, &PrtCnvCentralThread::startRadio, m_RadioThread, &PrtCnvRadioThread::doStart, Qt::QueuedConnection); + connect(m_RadioThread, &PrtCnvRadioThread::initDone, + this, &PrtCnvCentralThread::onRadioThreadInitDone); + connect(m_RadioThread, &PrtCnvRadioThread::areaEffectSimulationActivated, + this, &PrtCnvCentralThread::onAreaEffectSimulationActivated, Qt::QueuedConnection); + connect(m_RadioThread, &PrtCnvRadioThread::areaEffectSimulationDeactivated, + this, &PrtCnvCentralThread::onAreaEffectSimulationDeactivated, Qt::QueuedConnection); + + auto mainApp = m_Parent->getMainApp(); + connect(this, &PrtCnvCentralThread::directTextMessage, + mainApp, &PrtCnvApplication::textMessageFromPrtCnvToCentral); + connect(mainApp, &PrtCnvApplication::textMessageFromCentralToPrtCnv, + this, &PrtCnvCentralThread::onDirectTextMessageReceived); + + m_aliveTimer = new QTimer(this); + connect(m_aliveTimer, &QTimer::timeout, this, &PrtCnvCentralThread::timeoutAliveAndConnection); + + m_sendAckTimer = new QTimer(this); + connect(m_sendAckTimer, &QTimer::timeout, this, &PrtCnvCentralThread::timeoutTick); + + const int disconnectTimeout = m_Config->getInteger(getName(), QStringLiteral("DisconnectTimeout"), 10000); + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setInterval(disconnectTimeout); + m_reconnectTimer->setSingleShot(true); + connect(m_reconnectTimer, &QTimer::timeout, this, &PrtCnvCentralThread::connectSocket); + + return 0; +} + + + + + +int32_t PrtCnvCentralThread::destroy() +{ + INFO_LOG(m_logger) << "Destroy"; + PrtCnvThread::destroy(); + delete m_webSocket; m_webSocket = nullptr; + delete m_aliveTimer; m_aliveTimer = nullptr; + delete m_sendAckTimer; m_sendAckTimer = nullptr; + delete m_reconnectTimer; m_reconnectTimer = nullptr; + return 0; +} + + + + +int32_t PrtCnvCentralThread::init() +{ + INFO_LOG(m_logger) << "Init"; + PrtCnvThread::init(); + m_CentralStopped = false; + m_RadioStopped = false; + + m_aliveTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("AliveTimeout"), 3000)); + m_sendAckTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("AckTimeout"), 900)); + + m_VirtualTeilnehmerId = m_Config->getInteger(QStringLiteral("Common"), QStringLiteral("VirtualIdPrtCnv"), 90); + m_maxEqID = m_Config->getInteger(QStringLiteral("Common"), QStringLiteral("MaxEqID"), 50000); + + return 0; +} + +int32_t PrtCnvCentralThread::deinit() +{ + INFO_LOG(m_logger) << "Deinit"; + PrtCnvThread::deinit(); + return 0; +} + + + + +int32_t PrtCnvCentralThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvThread::start(); + if (m_DbThread->mustProceedCleanup()) + { + INFO_LOG(m_logger) << "Proceed cleanup DB after crash..."; + m_CentralStopped = true; + emit stopRadio(); + } + else + { + connectSocket(); + } + + return 0; +} + + + + +int32_t PrtCnvCentralThread::stop() +{ + INFO_LOG(m_logger) << "Stop"; + PrtCnvThread::stop(); + + return 0; +} + + + + + +void PrtCnvCentralThread::connected() +{ + INFO_LOG(m_logger) << "Central-Socket connected m_Socket=" << m_webSocket; + m_SendCounter = 0; + m_LastSendCounter = 0; + m_ReceiveCounter = 0; + m_ReceiveAckCounter = 0; + m_aliveTimer->start(); + if (m_bRadioThreadInitDone) + m_sendAckTimer->start(); + m_State = PrtCnvSocketThread::e_WORKING; + emit checkSendToCentral(); +} + + + + +void PrtCnvCentralThread::disconnected() +{ + INFO_LOG(m_logger) << "disconnected m_Socket=" << m_webSocket; + + + if (PrtCnvSocketThread::e_WORKING == m_State && m_webSocket) + m_webSocket->close(); + + m_State = PrtCnvSocketThread::e_DISCONNECTING; + if (m_DoCleanup) + { + INFO_LOG(m_logger) << "cleanup while disconnection"; + m_sendAckTimer->stop(); + m_CentralStopped = true; + if (m_RadioStopped) + cleanAndReinit(); + } + else + { + m_DbThread->prepareCentralTelegramsForReconnection(); + connectSocket(); + } +} + + + + + + +void PrtCnvCentralThread::radioStopped() +{ + m_RadioStopped = true; + if (m_CentralStopped) + cleanAndReinit(); +} + + + + + + +void PrtCnvCentralThread::cleanAndReinit() +{ + INFO_LOG(m_logger) << "cleanAndReinit"; + emit cleanRadio(); + + m_ReceiveAckCounter = 0; + m_DbThread->cleanAndInit(); + m_DoCleanup = false; +} + + + + + + +void PrtCnvCentralThread::radioCleant() +{ + if (!m_DoCleanup) + { + m_DbThread->setMachineState(0); + m_RadioStopped = false; + m_CentralStopped = false; + emit startRadio(); + connectSocket(); + } + else + { + ERROR_LOG(m_logger) << "Internal error: radioCleant, but central still cleaning up."; + } +} + + + + +void PrtCnvCentralThread::onTextMessageReceived(const QString &msg) +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + onDirectTextMessageReceived(msg.toUtf8()); +} + +void PrtCnvCentralThread::onDirectTextMessageReceived(const QByteArray &baJson) +{ + try + { + if (baJson.isEmpty()) + throw std::exception(); + const QJsonObject obj = QJsonDocument::fromJson(baJson).object(); + + const QJsonValue typeId = obj.value(QStringLiteral("typeId")); + if (!typeId.isDouble()) + throw TrainingAreaBase::TetraIcd::JsonException(obj, QStringLiteral("typeId")); + + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(baJson, obj, static_cast(typeId.toInt())); + + m_LogThread->writeCentralTelegramLog(&telegram, false, 1); + + m_aliveTimer->start(); + + + if (telegram.telegramId() == TrainingAreaBase::TetraIcd::BESTAETIGUNG) + { + + handleAck(&telegram); + } + else + { + DEBUG_LOG(m_logger) << "Received telegram '" << baJson << "'"; + + handleTelegram(&telegram); + } + } + catch (const std::exception &e) + { + ERROR_LOG(m_logger) << "JSon conversion error happenend. Error:" + << e.what() << ", msg: " << baJson; + + TrainingAreaBase::TetraIcd::CtaDataError tele; + tele.header.equipmentNumber = m_VirtualTeilnehmerId; + tele.header.timeStamp = time(nullptr) * 1000LL; + tele.reason = TrainingAreaBase::TetraIcd::CtaDataError::Reason::JsonDecodeFailure; + tele.originTelegramId = 0; + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(tele); + sendTelegram(&telegram); + } +} + + +void PrtCnvCentralThread::stateChanged(QAbstractSocket::SocketState newState) +{ + INFO_LOG(m_logger) << "Websocket changed to state " << newState; +} + + + + + +void PrtCnvCentralThread::handleTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + + + + DEBUG_LOG(m_logger) << "Receive Central-Telegram with telId=" << a_telegram->telegramId() + << "; rcounter=" << a_telegram->counter(); + if (checkAndUpdateReceiveCounter(a_telegram->counter())) + { + if (handleSpecialTelegram(a_telegram)) + { + using namespace TrainingAreaBase::TetraIcd; + if (a_telegram->telegramId() == TelegramId::DEAKTIVIERUNG_WIRKFELD) + { + const DeactivateEffectSimulation des(DeactivateEffectSimulation::fromJson(a_telegram->jsonData())); + switch (des.aesType) + { + case AreaEffectSimulationType::MineArea: + case AreaEffectSimulationType::ExplosionArea: + case AreaEffectSimulationType::ExplosionSingle: + case AreaEffectSimulationType::NContamination: + case AreaEffectSimulationType::CContamination: + case AreaEffectSimulationType::FunctionalArea: + case AreaEffectSimulationType::DusSingleMineSimulator: + if (m_deactivatedAreaEffectSimulations.contains(des.aesDdsId)) + { + INFO_LOG(m_logger) << "AES with id " << des.aesDdsId << " already deactivated - ignoring new deactivation telegram"; + return; + } + break; + case AreaEffectSimulationType::TechnicalArea: + case AreaEffectSimulationType::GasPipeDetonation: + case AreaEffectSimulationType::SpecialArea: + case AreaEffectSimulationType::Unknown: + Q_ASSERT(false); + break; + case AreaEffectSimulationType::BeStillWarning: + break; + } + } + else if (a_telegram->telegramId() == TelegramId::WIRKFELD_STATUS_MINENSPERRE) + { + const MineAreaSingleMineState msms(MineAreaSingleMineState::fromJson(a_telegram->jsonData())); + QSet &oldTriggeredMines = m_alreadyTriggeredMines[msms.aesDdsId]; + QSet newTriggeredMines; + newTriggeredMines.reserve(oldTriggeredMines.size() + 5); + bool bSomethingChanged = false; + for (int i = 0; i < msms.mineCount; ++i) + { + if (!LtsUtils::BitArray::testBit(msms.mineState, i)) + { + INFO_LOG(m_logger) << "Testing bit " << i << " ... not set = triggered"; + if (!oldTriggeredMines.contains(i)) + { + INFO_LOG(m_logger) << "not in old one"; + bSomethingChanged = true; + } + newTriggeredMines.insert(i); + } + } + if (!bSomethingChanged) + bSomethingChanged = newTriggeredMines.size() != oldTriggeredMines.size(); + if (!bSomethingChanged) + { + INFO_LOG(m_logger) << "MineState telegram contains no new informations - skipping " << msms.aesDdsId; + return; + } + INFO_LOG(m_logger) << "MineState telegram contains new informations... " << msms.aesDdsId; + oldTriggeredMines = newTriggeredMines; + } + + std::shared_ptr + radioTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(a_telegram)); + if (radioTelegram) + { + if (radioTelegram->getIdentity() <= m_maxEqID) { + + m_DbThread->storeRadioTelegram(radioTelegram, a_telegram->counter()); + } else { + WARNING_LOG(m_logger) << "Central telegram with telId=" << a_telegram->telegramId() + << " has invalid identity:" << radioTelegram->getIdentity(); + } + } + else + { + m_DbThread->centralCounterReadyForAck(a_telegram->counter()); + WARNING_LOG(m_logger) << "Central telegram with telId=" << a_telegram->telegramId() + << " could not be converted"; + } + } + } + emit checkSendToRadio(); +} + + + + + + + +bool PrtCnvCentralThread::checkAndUpdateReceiveCounter(const int32_t a_counter) +{ + TRACE_LOG(m_logger) << "checkAndUpdateReceiveCounter: " << a_counter << ", " << m_ReceiveCounter; + + if (std::numeric_limits::max() == ++m_ReceiveCounter) + m_ReceiveCounter = 0; + + + if (m_ReceiveCounter != a_counter) + { + if (m_ReceiveCounter > a_counter) + { + ERROR_LOG(m_logger) << "It seems, the telegram with counter " << a_counter << " was resent from " + << getName() << "! Expected: " << m_ReceiveCounter; + } + else + { + ERROR_LOG(m_logger) << "It seems, we lost one or several telegrams from " << getName() + << ": receive-counter of received telegram: " << a_counter << "; Expected: " << m_ReceiveCounter; + } +#if 0 + m_ReceiveCounter--; + return false; +#else + m_ReceiveCounter = a_counter; + return true; +#endif + } + return true; +} + + + + +void PrtCnvCentralThread::timeoutTick() +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + + + + + + try + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *centralInjectTelegram; + while ((centralInjectTelegram = m_InjectionThread->getNextCentralInjectionTelegram())) + { + sendTelegram(centralInjectTelegram); + delete centralInjectTelegram; + } + } + catch (std::exception& e) + { + ERROR_LOG(m_logger) << "Catched an unexpected exception: " << e.what() + << " => could not inject radio-telegram, but we proceed..."; + } + + + sendAck(); +} + + + + +void PrtCnvCentralThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "timeoutAliveAndConnection socketState=" + << int(m_webSocket ? m_webSocket->state() : -1) + << " m_State=" << m_State << " m_Socket=" << m_webSocket; + switch (m_State) + { + case PrtCnvSocketThread::e_CONNECTING: + connectSocket(); + break; + case PrtCnvSocketThread::e_WORKING: + if (!m_bDirectConnection) + { + disconnectSocket(); + m_reconnectTimer->start(); + } + break; + case PrtCnvSocketThread::e_DISCONNECTING: + break; + default: + ERROR_LOG(m_logger) << "timeoutAlive for m_State=" << m_State << " not implemented"; + } +} + + + + +void PrtCnvCentralThread::sendAck() +{ + TrainingAreaBase::TetraIcd::Acknowledge ack; + ack.timeStamp = time(nullptr) * 1000; + ack.ackCounter = m_ReceiveAckCounter; + N_CoPrtCnv::CoPrtCnvCentralTelegram tele(ack); + + if (m_webSocket) + m_webSocket->sendTextMessage(QString::fromUtf8(tele.data())); + else + emit directTextMessage(tele.data()); + + TRACE_LOG(m_logger) << "Wrote ack: " << tele.data(); +} + + + + + + +void PrtCnvCentralThread::sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + PrtCnvStoredCentralTelegram *handle = nullptr; + sendTelegram(a_telegram, handle); +} + + + + + + + +void PrtCnvCentralThread::sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram, + PrtCnvStoredCentralTelegram *a_handle) +{ + using namespace TrainingAreaBase::TetraIcd; + if (a_telegram->telegramId() == TelegramId::DEAKTIVIERUNG_EINZELMINE) + { + const MineTriggered tele(MineTriggered::fromJson(a_telegram->jsonData())); + m_alreadyTriggeredMines[tele.mineAreaId].insert(tele.mineIndex - 1); + INFO_LOG(m_logger) << "Adding triggered mine with id " << tele.mineIndex << " to area id " << tele.mineAreaId; + } + + + const int writeCounter = a_handle ? a_handle->writeCounter() : 0; + if (writeCounter != 0) + a_telegram->setCounter(writeCounter); + else + a_telegram->setCounter(++m_SendCounter); + + + DEBUG_LOG(m_logger) << "Send telegram to central: telId=" << a_telegram->telegramId() + << " wcounter=" << a_telegram->counter(); + + if (m_webSocket) + m_webSocket->sendTextMessage(QString::fromUtf8(a_telegram->data())); + else + emit directTextMessage(a_telegram->data()); + + + if (a_handle) + m_DbThread->centralTelegramSent(a_telegram->counter(), a_handle); + m_LogThread->writeCentralTelegramLog(a_telegram, true, 1); +} + + + + + + + +void PrtCnvCentralThread::handleAnforderungStatistikBroadcastNachforderungen() +{ + const auto nachforderungsStat = m_DbThread->getClaimStatistics(); + + + TrainingAreaBase::TetraIcd::BroadcastStatistics tele; + tele.header.equipmentNumber = m_VirtualTeilnehmerId; + tele.header.timeStamp = time(nullptr) * 1000LL; + tele.information.reserve(nachforderungsStat.size()); + for (const auto &it : nachforderungsStat) + { + TrainingAreaBase::TetraIcd::BroadcastInformation bi; + bi.equipmentNumber = it.first; + bi.broadcastRequests = it.second; + tele.information.push_back(std::move(bi)); + } + + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(tele); + sendTelegram(&telegram); +} + + + + +void PrtCnvCentralThread::checkSend() +{ + + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + PrtCnvStoredCentralTelegram *handle = nullptr; + auto *centralTelegram = m_DbThread->getNextCentralTelegram(handle); + if (centralTelegram) + { + sendTelegram(centralTelegram, handle); + delete centralTelegram; + emit checkSendToCentral(); + } +} + + + + + +void PrtCnvCentralThread::handleAck(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + TrainingAreaBase::TetraIcd::Acknowledge ack(TrainingAreaBase::TetraIcd::Acknowledge::fromJson(a_telegram->jsonData())); + + m_DbThread->ackCentralTelegrams(ack.ackCounter); +} + + + + + + +void PrtCnvCentralThread::permanentStored(int32_t a_centralCounter) +{ + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + DEBUG_LOG(m_logger) << "got permanentStored a_centralCounter=" << a_centralCounter; + if (0 != a_centralCounter && a_centralCounter > m_ReceiveAckCounter) + { + m_ReceiveAckCounter = a_centralCounter; + sendAck(); + } +} + +void PrtCnvCentralThread::onTetraConnectionState(bool bConnected) +{ + TrainingAreaBase::TetraIcd::ProxyConnectionState connState; + connState.connectedToSystem = bConnected; + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(connState); + sendTelegram(&telegram); +} + +void PrtCnvCentralThread::onPlayerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind) +{ + TrainingAreaBase::TetraIcd::ParticipantLicenseChange lc; + lc.equipmentNumber = equipNo; + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unknown; + switch (kind) + { + case N_CoPrtCnv::E_LicensingKind::Success: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Licensed; + break; + case N_CoPrtCnv::E_LicensingKind::Rejected: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Rejected; + break; + case N_CoPrtCnv::E_LicensingKind::Unlicense: + lc.licenseState = TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unlicense; + break; + } + Q_ASSERT(lc.licenseState != TrainingAreaBase::TetraIcd::ParticipantLicenseState::Unknown); + N_CoPrtCnv::CoPrtCnvCentralTelegram telegram(lc); + sendTelegram(&telegram); +} + +void PrtCnvCentralThread::onAreaEffectSimulationDeactivated(int wirkfeldKennung) +{ + m_deactivatedAreaEffectSimulations.insert(wirkfeldKennung); + m_alreadyTriggeredMines.remove(wirkfeldKennung); +} + +void PrtCnvCentralThread::onAreaEffectSimulationActivated(int wirkfeldKennung) +{ + m_deactivatedAreaEffectSimulations.remove(wirkfeldKennung); +} + +void PrtCnvCentralThread::onRadioThreadInitDone() +{ + m_bRadioThreadInitDone = true; + if (!m_sendAckTimer->isActive()) + m_sendAckTimer->start(); +} + + + + + +bool PrtCnvCentralThread::handleSpecialTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + using namespace TrainingAreaBase::TetraIcd; + + switch (a_telegram->telegramId()) + { + case Constraints::id(): + { + ExerciseStateData tele(ExerciseStateData::fromJson(a_telegram->jsonData())); + switch(tele.exerciseState) + { + case ExerciseStateData::ExerciseState::Terminated: + { + INFO_LOG(m_logger) << "Got Betriebszustandsmeldung Uebung_Aufraeumen => disconnect, cleanup and reconnect"; + m_DbThread->setMachineState(1); + + permanentStored(a_telegram->counter()); + m_DoCleanup = true; + m_CentralStopped = false; + m_RadioStopped = false; + + m_sendAckTimer->stop(); + m_DbThread->waitUntilDbWritten(); + disconnectSocket(); + m_RadioThread->prepareCleanUp(); + emit stopRadio(); + m_reconnectTimer->start(); + break; + } + case ExerciseStateData::ExerciseState::Started: + m_DbThread->setPause(false); + m_RadioThread->sendEnvironmentTelegramTimerNow(); + break; + case ExerciseStateData::ExerciseState::Paused: + m_DbThread->setPause(true); + m_RadioThread->sendEnvironmentTelegramTimerNow(); + break; + default: + break; + } + return false; + } + case Constraints::id(): + + m_DbThread->centralCounterReadyForAck(a_telegram->counter()); + handleAnforderungStatistikBroadcastNachforderungen(); + return false; + + case Constraints::id(): + { + const ExerciseEquipmentAssignmentComplete tele(ExerciseEquipmentAssignmentComplete::fromJson(a_telegram->jsonData())); + m_RadioThread->exerciseEquipmentChanged(tele); + return false; + } + default: + break; + } + return true; +} + + +void PrtCnvCentralThread::connectSocket() +{ + const QString host = m_Config->getString(getName(), QStringLiteral("HostName"), QStringLiteral("EXCTDS01")); + if (host == QLatin1String("directConnection")) + { + m_bDirectConnection = true; + connected(); + return; + } + m_bDirectConnection = false; + + disconnectSocket(); + m_webSocket = new QWebSocket; + + connect(m_webSocket, &QWebSocket::stateChanged, + this, &PrtCnvCentralThread::stateChanged); + connect(m_webSocket, &QWebSocket::textMessageReceived, + this, &PrtCnvCentralThread::onTextMessageReceived); + connect(m_webSocket, &QWebSocket::connected, + this, &PrtCnvCentralThread::connected); + connect(m_webSocket, &QWebSocket::disconnected, + this, &PrtCnvCentralThread::disconnected); + + const uint16_t port = static_cast(m_Config->getInteger(getName(), QStringLiteral("Port"), 4934)); + const QUrl scmUrl(QStringLiteral("ws://%1:%2").arg(host).arg(port)); + + m_webSocket->open(scmUrl); + m_State = PrtCnvSocketThread::e_CONNECTING; +} + + +void PrtCnvCentralThread::disconnectSocket() +{ + m_State = PrtCnvSocketThread::e_INITIAL; + if (!m_webSocket) + return; + + m_State = PrtCnvSocketThread::e_DISCONNECTING; + m_webSocket->disconnect(this); + m_webSocket->close(); + m_webSocket->deleteLater(); + m_webSocket = nullptr; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvCentralThread.hpp b/TetraIF/PrtCnv/PrtCnvCentralThread.hpp new file mode 100644 index 000000000..c56dee7fa --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvCentralThread.hpp @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvDbThread.hpp" +#include + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvRadioThread; + class PrtCnvThreadStarter; + + + class PrtCnvCentralThread : public PrtCnv::PrtCnvThread + { + Q_OBJECT + +private: + + + public: + + + ~PrtCnvCentralThread(); + + + + explicit PrtCnvCentralThread(PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + int32_t deinit() override; + + + int32_t destroy() override; + + + int32_t init() override; + + + int32_t start() override; + + + int32_t stop() override; + + + void onDirectTextMessageReceived(const QByteArray &baJson); + + signals: + + void directTextMessage(const QByteArray &baJson); + + + + void checkSendToCentral(); + + + void checkSendToRadio(); + + + void stopRadio(); + + + void cleanRadio(); + + + void startRadio(); + + protected: + + + QWebSocket *m_webSocket; + + + + int32_t m_SendCounter; + + public slots: + + + void checkSend(); + + + void radioStopped(); + + + void radioCleant(); + + + void permanentStored(int32_t a_centralCounter); + + + void onTetraConnectionState(bool bConnected); + + void onPlayerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + + protected slots: + + void onAreaEffectSimulationDeactivated(int wirkfeldKennung); + void onAreaEffectSimulationActivated(int wirkfeldKennung); + + + void onRadioThreadInitDone(); + + + + void connected(); + + + void disconnected(); + + + void timeoutTick(); + + + void timeoutAliveAndConnection(); + + void onTextMessageReceived(const QString &msg); + void stateChanged(QAbstractSocket::SocketState newState); + + protected: + + + void sendAck(); + + + void handleTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + bool checkAndUpdateReceiveCounter(const int32_t a_counter); + + + void sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram, + PrtCnvStoredCentralTelegram *a_handle); + + + void handleAnforderungStatistikBroadcastNachforderungen(); + + + void handleAck(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + void cleanAndReinit(); + + + + bool handleSpecialTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void sendTelegram(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void connectSocket(); + + + void disconnectSocket(); + + protected: + + + PrtCnvRadioThread *m_RadioThread; + + + bool m_RadioStopped; + + + bool m_CentralStopped; + + + int32_t m_LastSendCounter; + + + uint16_t m_VirtualTeilnehmerId; + + + + uint16_t m_maxEqID; + + + QTimer *m_aliveTimer; + + + QTimer *m_sendAckTimer; + + + QTimer *m_reconnectTimer; + + + + QAtomicInt m_DoCleanup; + PrtCnvDbThread *m_DbThread; + + PrtCnvTelegramLogThread *m_LogThread; + + PrtCnvInjectionThread *m_InjectionThread; + + + + int32_t m_ReceiveCounter; + + + int32_t m_ReceiveAckCounter; + + + + PrtCnvSocketThread::E_State m_State; + + + QSet m_deactivatedAreaEffectSimulations; + + + QHash> m_alreadyTriggeredMines; + + + bool m_bDirectConnection; + + bool m_bRadioThreadInitDone; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvDbThread.cpp b/TetraIF/PrtCnv/PrtCnvDbThread.cpp new file mode 100644 index 000000000..e66bcc171 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvDbThread.cpp @@ -0,0 +1,1647 @@ + + + + + + + + + + + + + +#include "PrtCnvDbThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvMember.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvStoredCentralTelegram.hpp" +#include "PrtCnvStoredRadioTelegram.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace PrtCnv +{ + + + + +PrtCnvDbThread::PrtCnvDbThread(const QString &dbDriver, + const QString &dbHostName, + const QString &dbDatabaseName, + const QString &schemaName, + const QString &dbUserName, + const QString &dbPassword, + PrtCnv::PrtCnvThreadStarter *a_parent) + : PrtCnvThread(a_parent, "PrtCnvDbThread") + , m_BattleFieldOpStateMutex(QMutex::Recursive) + , m_MemberListByIdMutex(QMutex::Recursive) + , m_CentralListMutex(QMutex::Recursive) + , m_OldCentralAckCounter(0) + , m_RadioListMutex(QMutex::Recursive) + , m_SqlCmdListMutex(QMutex::Recursive) + , m_BroadcastMapMutex(QMutex::Recursive) + , m_DoClean(false) + , m_DoWaitUntilSqlWritten(false) + , m_DoStorePermanent(false) + , m_ResetCounter(0) + , m_BattleFieldOperatingState(0) + , m_EnvironmentTelegram(nullptr) + , m_DoProceedCleanup(false) + , m_OldCentralCounter(0) + , m_StorePermanentPending(0) + , m_NbrOfAttempts(5) + , m_dbDriver(dbDriver.isEmpty() ? QStringLiteral("QSQLITE") : dbDriver) + , m_dbHostName(dbHostName) + , m_dbDatabaseName(dbDatabaseName) + , m_dbSchemaName(schemaName) + , m_dbUserName(dbUserName) + , m_dbPassword(dbPassword) +{ + m_Name = QStringLiteral("Db"); +} + + +PrtCnvDbThread::~PrtCnvDbThread() +{ + closeDb(); + qDeleteAll(m_BroadcastList); + qDeleteAll(m_RadioList); + qDeleteAll(m_CentralList); + for (const auto &p : m_MemberListById) + delete p.second; +} + + + + + +static const int s_iCurrentDatabaseSchemeVersion = 1; +void PrtCnvDbThread::reinitDatabase() +{ + DBTransaction trans(m_db); + NSqlQuery q(m_db); + if (m_db.driverName() == QStringLiteral("QSQLITE")) + { + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(versionTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "version integer," + "date text," + "product text," + "change text)").arg(versionTableName())); + q.exec(QStringLiteral("INSERT INTO %1 (version, date, product, change) VALUES " + "(1, '2012-11-20', 'TetraInterface', 'Initial version table');").arg(versionTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(toCentralTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "tel_id INTEGER," + "counter INTEGER DEFAULT 0," + "data BLOB);").arg(toCentralTableName())); + q.exec(QStringLiteral("CREATE INDEX counterIndex ON %1(counter);").arg(toCentralTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(toRadioTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "tel_id INTEGER," + "counter INTEGER DEFAULT 0," + "broadcast_index INTEGER DEFAULT 0," + "reset_counter INTEGER DEFAULT 0," + "data BLOB);").arg(toRadioTableName())); + q.exec(QStringLiteral("CREATE INDEX bcindex ON %1(reset_counter, broadcast_index);").arg(toRadioTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(memberTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY," + "issi INTEGER," + "licensed INTEGER DEFAULT 0," + "claims INTEGER DEFAULT 0," + "exercise_id INTEGER" + ");").arg(memberTableName())); + + q.exec(QStringLiteral("DROP TABLE IF EXISTS %1;").arg(statusTableName())); + q.exec(QStringLiteral("CREATE TABLE %1 (" + "id INTEGER PRIMARY KEY," + "reset_counter INTEGER," + "ctas_operating_state INTEGER," + "machine_state INTEGER" + ");").arg(statusTableName())); + } + + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 1;").arg(statusTableName())); + q.exec(QStringLiteral("INSERT INTO %1 " + "(id, reset_counter, ctas_operating_state, machine_state) " + "VALUES (1, %2, %3, 0);") + .arg(statusTableName()).arg(int(m_ResetCounter)).arg(int(m_BattleFieldOperatingState))); + + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 0;").arg(memberTableName())); + + trans.commit(); +} + + + + +bool PrtCnvDbThread::createDatabase() +{ + closeDb(); + + m_db = QSqlDatabase::addDatabase(m_dbDriver, QStringLiteral("PrtCnv")); + if (m_dbDriver == QLatin1String("QSQLITE")) + { + QString path = m_Config->getString(getName(), QStringLiteral("DatabaseFileName"), QStringLiteral("telegrams.db")); + if (!QDir::isAbsolutePath(path)) + { + path = QCoreApplication::applicationDirPath() + QLatin1String("/../") + path; + QFileInfo fi(path); + QDir().mkpath(fi.absolutePath()); + } + m_db.setDatabaseName(path); + INFO_LOG(m_logger) << "Use db-file: " << path; + std::cout << "Use db-file: " << qPrintable(path) << std::endl; + } + else + { + m_db.setDatabaseName(m_dbDatabaseName); + m_db.setHostName(m_dbHostName); + m_db.setUserName(m_dbUserName); + m_db.setPassword(m_dbPassword); + } + + + DEBUG_LOG(m_logger) << "Connection name: " << m_db.connectionName(); + + if (!m_db.open()) + { + FATAL_LOG(m_logger) << "Error while opening database: " << m_db.lastError().text(); + return false; + } + + if (m_DoCleanDb) + { + NOTICE_LOG(m_logger) << "Permanent data will be erased..."; + reinitDatabase(); + } + else + { + NOTICE_LOG(m_logger) << "Check database..."; + NSqlQuery q(m_db); + if (m_db.driverName() == QStringLiteral("QSQLITE")) + { + if (!q.execAndFetch(QStringLiteral("SELECT MAX(version) FROM %1;").arg(versionTableName()))) + { + ERROR_LOG(m_logger) << "Could not read version table - reinitialize database"; + reinitDatabase(); + } + else + { + + int iVersion = q.value(0).toInt(); + if (iVersion != s_iCurrentDatabaseSchemeVersion) + { + ERROR_LOG(m_logger) << "Database version does not match (is: " + << iVersion << " expected: " << s_iCurrentDatabaseSchemeVersion + << " - reinitialize database"; + reinitDatabase(); + } + } + } + + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(statusTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table Status"; + std::cout << "Failure while checking DB-table Status. Start PrtCnv with --cleandb" << std::endl; + return false; + } + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(toCentralTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table ToCentral"; + std::cout << "Failure while checking DB-table ToCentral. Start PrtCnv with --cleandb" << std::endl; + return false; + } + if (!q.exec(QStringLiteral("SELECT * from %1 LIMIT 1;").arg(toRadioTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table ToRadio"; + std::cout << "Failure while checking DB-table ToRadio. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + if (!q.exec(QStringLiteral("SELECT issi FROM %1 WHERE id=0;").arg(memberTableName()))) + { + ERROR_LOG(m_logger) << "Failure while checking DB-table Member"; + std::cout << "Failure while checking DB-table Member. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + const int broadcastIssi = m_Config->getInteger(QStringLiteral("Radio"), QStringLiteral("BroadcastISSI"), 5000); + if (q.next()) + { + const int dbBroadcastIssi = q.value(0).toInt(); + if (broadcastIssi != dbBroadcastIssi) + { + WARNING_LOG(m_logger) << "Broadcast-ISSI mismatch (DB: " << dbBroadcastIssi << "; Configfile: " << broadcastIssi << ")"; + q.exec(QStringLiteral("DELETE FROM %1 WHERE id = 0;").arg(memberTableName())); + licenseMember(addMember(0, broadcastIssi)); + } + } + else + { + licenseMember(addMember(0, broadcastIssi)); + } + + INFO_LOG(m_logger) << "Restore permanent data (after crash)..."; + m_DoStorePermanent = false; + + INFO_LOG(m_logger) << "restoreStatus"; + + if (!q.execAndFetch(QStringLiteral("SELECT reset_counter, ctas_operating_state, machine_state FROM %1;").arg(statusTableName()))) + { + ERROR_LOG(m_logger) << "Error reading Status from DB"; + std::cout << "Error reading Status from DB. Start PrtCnv with --cleandb" << std::endl; + return false; + } + m_ResetCounter = q.value(0).toInt(); + INFO_LOG(m_logger) << "Restore resetCounter=" << (int)m_ResetCounter; + + if (1 == q.value(2).toInt()) + { + INFO_LOG(m_logger) << "Crash happenend while cleaning-DB"; + + m_DoStorePermanent = true; + m_DoProceedCleanup = true; + return true; + } + m_BattleFieldOperatingState = q.value(1).toInt(); + INFO_LOG(m_logger) << "Restore battleFieldOperatingState=" << (int)m_BattleFieldOperatingState; + + + if (!q.exec(QStringLiteral("SELECT id, issi, licensed, claims, exercise_id FROM %1;").arg(memberTableName()))) + { + ERROR_LOG(m_logger) << "Error reading Member from DB"; + std::cout << "Error reading Member from DB. Start PrtCnv with --cleandb" << std::endl; + return false; + } + + while (q.next()) + { + int id = q.value(0).toInt(); + int issi = q.value(1).toInt(); + bool licensed = q.value(2).toBool(); + int claims = q.value(3).toInt(); + int exerciseId = q.value(4).toInt(); + INFO_LOG(m_logger) << "Restore member: id=" << id << " issi=" << issi << " licensed=" << licensed + << " claims=" << claims << " exerciseId " << exerciseId; + PrtCnvMember *member = addMember(id, issi); + if (member) + { + member->m_ClaimCount = claims; + member->m_loggedInExerciseId = exerciseId; + if (licensed) + { + bool ok = licenseMember(member); + if (ok) + { + + emit playerLicencedChanged(member->m_Id, N_CoPrtCnv::E_LicensingKind::Success); + } + } + } + } + + + + + + if (!q.exec(QStringLiteral("SELECT id, counter, broadcast_index, data " + "FROM %1 ORDER BY reset_counter, broadcast_index, id;").arg(toRadioTableName()))) + { + ERROR_LOG(m_logger) << "Error reading from ToRadio table"; + std::cout << "Error reading from ToRadio table. Start PrtCnv with --cleandb" << std::endl; + return false; + } + while (q.next()) + { + const qint64 id = q.value(0).toLongLong(); + const int counter = q.value(1).toInt(); + const int bcIndex = q.value(2).toInt(); + const QByteArray telData(q.value(3).toByteArray()); + + auto radioTelegram(std::make_shared(telData)); + PrtCnvStoredRadioTelegram *storedTelegram = + new PrtCnvStoredRadioTelegram(radioTelegram); + storedTelegram->m_Id = id; + + + if (0 == counter) + { + + m_RadioList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore unsent radiotelegram: id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_RadioTelegram->getTelID() + << " BC=" << storedTelegram->m_RadioTelegram->getBroadcastIndex() + << " counter=" << counter; + } + else + { + + if (bcIndex == 0) + { + if (radioTelegram->getTelID() == GEF_UMGEBUNGS_MELDUNG2) + m_RadioList.push_back(storedTelegram); + else + delete storedTelegram; + } + else + { + + radioTelegram->setBroadcastIndex(bcIndex); + bool dummy; + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + radioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + m_BroadcastList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore broadcast-radiotelegram: id=" + << storedTelegram->m_Id << " telId=" << storedTelegram->m_RadioTelegram->getTelID() + << " BC=" << storedTelegram->m_RadioTelegram->getBroadcastIndex() + << " counter=" << counter; + } + } + } + + + q.exec(QStringLiteral("UPDATE %1 SET counter=0;").arg(toCentralTableName())); + if (!q.exec(QStringLiteral("SELECT id, data FROM %1 ORDER BY id;").arg(toCentralTableName()))) + { + ERROR_LOG(m_logger) << "Error reading from ToCentral table"; + std::cout << "Error reading from ToCentral table. Start PrtCnv with --cleandb" << std::endl; + return false; + } + while (q.next()) + { + const qint64 id = q.value(0).toLongLong(); + const QByteArray telData(q.value(1).toByteArray()); + + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(telData); + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + PrtCnvStoredCentralTelegram *storedTelegram = new PrtCnvStoredCentralTelegram(centralTelegram, nullptr); + storedTelegram->m_Id = id; + m_CentralList.push_back(storedTelegram); + INFO_LOG(m_logger) << "Restore unsent or unacked centraltelegram: id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_CentralTelegram->telegramId() + << " counter=" << storedTelegram->m_WriteCounter + << " size=" << telData.size(); + + } + else + ERROR_LOG(m_logger) << "Internal error: conversion of telegram with telId=" << radioTelegram.getTelID() << " from radio to central failed"; + } + + if (m_db.driverName() == QLatin1String("QSQLITE")) + { + q.exec(QStringLiteral("VACUUM;")); + q.exec(QStringLiteral("PRAGMA journal_mode=WAL;")); + + + q.exec(QStringLiteral("PRAGMA synchronous=NORMAL;")); + } + } + m_DoStorePermanent = true; + + return true; +} + + + + +int32_t PrtCnvDbThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvThread::create(settings); + m_NbrOfAttempts = m_Config->getInteger(QStringLiteral("Central"), QStringLiteral("NbrOfAttempts"), 5); + if (!createDatabase()) + { + ERROR_LOG(m_logger) << "Trying to create clean database after error"; + m_DoCleanDb = true; + if (!createDatabase()) + exit(-2); + } + + connect(this, &PrtCnvDbThread::doStorePermanent, this, &PrtCnvDbThread::storePermanent, Qt::QueuedConnection); + connect(this, &PrtCnvDbThread::doClean, this, &PrtCnvDbThread::clean, Qt::QueuedConnection); + + PrtCnvCentralThread *centralThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Central)); + connect(this, &PrtCnvDbThread::permanentStored, centralThread, &PrtCnvCentralThread::permanentStored, Qt::QueuedConnection); + + return 0; +} + + + + + +int32_t PrtCnvDbThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvThread::init(); + m_CentralAckCounter = 0; + m_OldCentralAckCounter = 0; + m_OldCentralCounter = 0; + m_DoClean = false; + m_DoWaitUntilSqlWritten = false; + + return 0; +} + + + + + +int32_t PrtCnvDbThread::start() +{ + INFO_LOG(m_logger) << "start"; + PrtCnvThread::start(); + + return 0; +} + + + + + +int32_t PrtCnvDbThread::stop() +{ + PrtCnvThread::stop(); + m_db.close(); + m_db = QSqlDatabase(); + + return 0; +} + + + + + + + + + + + + +void PrtCnvDbThread::storeCentralTelegram(const std::shared_ptr &a_centralTelegram, + const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + PrtCnvStoredCentralTelegram *storedTelegram = + new PrtCnvStoredCentralTelegram(a_centralTelegram, + std::make_shared(a_radioTelegram)); + QMutexLocker l(&m_CentralListMutex); + m_CentralList.push_back(storedTelegram); + + + sendStorePermanentSignal(); +} + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvDbThread::getNextCentralTelegram(PrtCnvStoredCentralTelegram *&a_handle) +{ + + QMutexLocker l(&m_CentralListMutex); + std::vector::const_iterator iter = m_CentralList.begin(); + std::vector::const_iterator end = m_CentralList.end(); + for (; iter != end; ++iter) + { + PrtCnvStoredCentralTelegram *storedTelegram = *iter; + if (!storedTelegram || !storedTelegram->m_CentralTelegram) + continue; + if (0 == storedTelegram->m_WriteCounter || storedTelegram->m_DoResend) + { + const auto &telegram = storedTelegram->m_CentralTelegram; + storedTelegram->m_DoResend = false; + a_handle = storedTelegram; + DEBUG_LOG(m_logger) << "Next telegram to send to central: id=" << storedTelegram->m_Id + << " a_telId=" << telegram->telegramId(); + + return new N_CoPrtCnv::CoPrtCnvCentralTelegram(*telegram); + } + } + return nullptr; +} + + + + + +void PrtCnvDbThread::centralTelegramSent(const int32_t a_counter, PrtCnvStoredCentralTelegram *a_handle) +{ + + QMutexLocker l(&m_CentralListMutex); + a_handle->m_WriteCounter = a_counter; + a_handle->m_WriteCounterChanged = true; + + sendStorePermanentSignal(); +} + + + + + + +void PrtCnvDbThread::ackCentralTelegrams(int32_t a_counter) +{ + + m_CentralAckCounter = a_counter; + + sendStorePermanentSignal(); +} + + + + + + + + + + +void PrtCnvDbThread::centralTelegramCouldNotBeSent(PrtCnvStoredCentralTelegram *a_handle) +{ + if (a_handle) + { + + QMutexLocker l(&m_CentralListMutex); + if (++(a_handle->m_Attempts) >= 5) + { + WARNING_LOG(m_logger) << "Delete unsendable Central-Telegram with id=" << a_handle->m_Id + << " telId=" << a_handle->m_CentralTelegram->telegramId() + << " rc=" << a_handle->m_CentralTelegram->counter() << " wc=" << a_handle->m_WriteCounter; + a_handle->m_DoDelete = true; + + } + l.unlock(); + + waitUntilDbWritten(); + } +} + + + + + + + + +void PrtCnvDbThread::storeRadioTelegram(const std::shared_ptr &a_telegram, + const int32_t a_readCounter) +{ + PrtCnvStoredRadioTelegram *storedTelegram = new PrtCnvStoredRadioTelegram(a_telegram); + storedTelegram->m_ReadCounter = a_readCounter; + { + QMutexLocker l(&m_RadioListMutex); + m_RadioList.push_back(storedTelegram); + } + if (a_telegram) + DEBUG_LOG(m_logger) << "Store Radio-Telegram with telId=" << a_telegram->getTelID() + << " rc=" << a_readCounter + << " wc=" << int(storedTelegram->m_WriteCounter); + + if (m_DoStorePermanent) + sendStorePermanentSignal(); +} + + + + + + + + +void PrtCnvDbThread::centralCounterReadyForAck(const int32_t a_centralCounter) +{ + storeRadioTelegram(nullptr, a_centralCounter); + DEBUG_LOG(m_logger) << "No Radio-Telegram to store, but rc=" << a_centralCounter << " must be acked"; +} + + + + + + + +std::shared_ptr PrtCnvDbThread::getNextBroadcastTelegram() +{ + QMutexLocker l(&m_BroadcastMapMutex); + if (m_BroadcastList.empty()) + return nullptr; + + PrtCnvStoredRadioTelegram *storedRadioTelegram = m_BroadcastList.front(); + std::shared_ptr radioTelegram; + + if (storedRadioTelegram->m_Id != 0 && !storedRadioTelegram->m_WriteCounterChanged) + { + radioTelegram = storedRadioTelegram->m_RadioTelegram; + m_BroadcastList.pop_front(); + delete storedRadioTelegram; + } + + return radioTelegram; +} + + + + + + + +std::shared_ptr PrtCnvDbThread::getNextRadioTelegram(PrtCnvStoredRadioTelegram *&a_handle) +{ + + std::shared_ptr telegram; + uint8_t priority = 255; + + QMutexLocker l(&m_RadioListMutex); + for (PrtCnvStoredRadioTelegram *storedTelegram: m_RadioList) + { + const auto &radioTelegram = storedTelegram->m_RadioTelegram; + if (radioTelegram) + { + if (!storedTelegram->m_IsSent) + { + + uint8_t newPriority = radioTelegram->getPriority(); + if (newPriority < priority) + { + priority = newPriority; + telegram = radioTelegram; + a_handle = storedTelegram; + } + } + } + } + return telegram; +} + + + + +void PrtCnvDbThread::radioTelegramSent(const uint32_t a_sendCounter, PrtCnvStoredRadioTelegram *a_handle, const uint32_t a_broadcastIndex) +{ + QMutexLocker l(&m_RadioListMutex); + + if (a_broadcastIndex) + { + DEBUG_LOG(m_logger) << "request update radio telegramm in db - sc: " << a_sendCounter + << " telId: " << a_handle->m_RadioTelegram->getTelID() + << " BC: " << a_broadcastIndex; + } + + + a_handle->m_WriteCounter = a_sendCounter; + a_handle->m_WriteCounterChanged = true; + a_handle->m_IsSent = true; + if (a_broadcastIndex != 0) + a_handle->m_BroadcastIndex = a_broadcastIndex; + + if (a_handle->m_BroadcastIndex != 0) + { + + bool dummy; + a_handle->m_RadioTelegram->mustBeSentAsBroadcast(0xFFFFFFFF, dummy); + DEBUG_LOG(m_logger) << "Move Radio-Telegram with telId=" << a_handle->m_RadioTelegram->getTelID() + << " and BC=" << a_handle->m_RadioTelegram->getBroadcastIndex() + << " to BC-List of DB"; + + + + + + QMutexLocker l2(&m_BroadcastMapMutex); + m_BroadcastList.push_back(a_handle); + } + else + { + + if (a_handle->m_RadioTelegram->isNormalTelegram() && (a_handle->m_RadioTelegram->getTelID() == GEF_UMGEBUNGS_MELDUNG2)) + { + + if (m_EnvironmentTelegram) + m_EnvironmentTelegram->m_DoDelete = true; + m_EnvironmentTelegram = a_handle; + } + else + a_handle->m_DoDelete = true; + } + + sendStorePermanentSignal(); +} + + +void PrtCnvDbThread::deleteTelegramsFromDbById(const QString &table) +{ + if (m_telegramsToDelete.empty()) + return; + + QStringList sl; + sl.reserve(m_telegramsToDelete.size()); + for (const int64_t telId : m_telegramsToDelete) + sl += QString::number(telId); + + NSqlQuery q(m_db); + q.exec(QStringLiteral("DELETE FROM %1 WHERE id IN (%2);").arg(table, sl.join(QLatin1Char(',')))); + + + m_telegramsToDelete.clear(); +} + +void PrtCnvDbThread::updateTelegramsBroadcast(const QString &table) +{ + if (m_telegramsToUpdateBC.empty()) + return; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("UPDATE %1 SET broadcast_index = :broadcast_index WHERE id = :id").arg(table)); + for (const auto &p : m_telegramsToUpdateBC) + { + const qint64 telId = p.first; + const qint32 bcIndex = p.second; + + q.bindValue(QStringLiteral(":broadcast_index"), bcIndex); + q.bindValue(QStringLiteral(":id"), telId); + q.exec(); + + DEBUG_LOG(m_logger) << "Update broadcastindex for id: " << telId << " to BC: " << bcIndex; + } + + + m_telegramsToUpdateBC.clear(); +} + +void PrtCnvDbThread::updateTelegramsWriteCounter(const QString &table) +{ + if (m_telegramsToUpdateCounter.empty()) + return; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("UPDATE %1 SET counter = :counter WHERE id = :id").arg(table)); + for (const auto &p : m_telegramsToUpdateCounter) + { + const qint64 telId = p.first; + const qint32 writeCounter = p.second; + + q.bindValue(QStringLiteral(":counter"), writeCounter); + q.bindValue(QStringLiteral(":id"), telId); + q.exec(); + + DEBUG_LOG(m_logger) << "Update WriteCounter for id: " << telId << " to wc: " << writeCounter; + } + + + m_telegramsToUpdateCounter.clear(); +} + + + +void PrtCnvDbThread::storeCentralTelegrams() +{ + QMutexLocker l(&m_CentralListMutex); + + if (m_CentralList.empty()) + return; + + + int iEmptyCount = 0; + for (auto &storedCentralTelegram : m_CentralList) + { + if (!storedCentralTelegram) + { + ++iEmptyCount; + continue; + } + const auto centralTelegram = storedCentralTelegram->m_CentralTelegram; + + if (0 == storedCentralTelegram->m_Id) + { + + m_telegramsToInsert.emplace_back(std::make_pair(storedCentralTelegram, 0)); + + DEBUG_LOG(m_logger) << "Permanent Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << centralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + } + else + { + + + const int centralAckCnt = m_CentralAckCounter; + if (storedCentralTelegram->m_WriteCounterChanged) + { + m_telegramsToUpdateCounter.emplace_back(std::make_pair(storedCentralTelegram->m_Id, + storedCentralTelegram->m_WriteCounter)); + storedCentralTelegram->m_WriteCounterChanged = false; + + DEBUG_LOG(m_logger) << "Update Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << centralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + } + + + else if ((storedCentralTelegram->m_WriteCounter > 0 && + storedCentralTelegram->m_WriteCounter <= centralAckCnt) || + storedCentralTelegram->m_DoDelete) + { + DEBUG_LOG(m_logger) << "Delete Central-Telegram with id=" << storedCentralTelegram->m_Id + << " data=" << storedCentralTelegram->m_CentralTelegram->data() + << " wc=" << storedCentralTelegram->m_WriteCounter; + + + if (storedCentralTelegram->m_WriteCounter > centralAckCnt) + m_telegramsToDelete.push_back(storedCentralTelegram->m_Id); + + delete storedCentralTelegram; + storedCentralTelegram = nullptr; + } + } + } + + if (iEmptyCount > 50) + { + const auto isNull = [](const PrtCnvStoredCentralTelegram *t) { return t == nullptr; }; + m_CentralList.erase(std::remove_if(m_CentralList.begin(), m_CentralList.end(), isNull), + m_CentralList.end()); + } + + l.unlock(); + + + + if (!m_telegramsToInsert.empty()) + { + l.relock(); + NSqlQuery q(m_db); + q.prepare(QStringLiteral("INSERT INTO %1 (tel_id, counter, data)" + "VALUES(:tel_id, :counter, :data);").arg(toCentralTableName())); + + + + + for (const auto &p : m_telegramsToInsert) + { + PrtCnvStoredCentralTelegram *storedCentralTelegram = p.first; + + storedCentralTelegram->m_WriteCounterChanged = false; + q.bindValue(QStringLiteral(":tel_id"), storedCentralTelegram->m_CentralTelegram->telegramId()); + q.bindValue(QStringLiteral(":counter"), storedCentralTelegram->m_WriteCounter); + q.bindValue(QStringLiteral(":data"), storedCentralTelegram->m_RadioTelegram->data()); + q.exec(); + storedCentralTelegram->m_Id = q.lastInsertId().toInt(); + } + l.unlock(); + + m_telegramsToInsert.clear(); + } + + + + updateTelegramsWriteCounter(toCentralTableName()); + + + + + + + const unsigned int centralAckCnt = static_cast(m_CentralAckCounter); + if (centralAckCnt > m_OldCentralAckCounter) + { + m_OldCentralAckCounter = centralAckCnt; + + + DEBUG_LOG(m_logger) << "Central delete all counter <= " << m_OldCentralAckCounter; + + NSqlQuery q(m_db); + q.exec(QStringLiteral("DELETE FROM %1 WHERE counter > 0 AND counter <= %2;").arg(toCentralTableName()).arg(m_OldCentralAckCounter)); + } + + + deleteTelegramsFromDbById(toCentralTableName()); +} + +int32_t PrtCnvDbThread::storeRadioTelegrams() +{ + QMutexLocker l(&m_RadioListMutex); + + if (m_RadioList.empty()) + return 0; + + + int32_t centralCounter = 0; + + NSqlQuery q(m_db); + q.prepare(QStringLiteral("INSERT INTO %1 (tel_id, counter, broadcast_index, reset_counter, data) " + "VALUES (:tel_id, :counter, :broadcast_index, :reset_counter, :data);").arg(toRadioTableName())); + + + std::list::iterator radioIter = m_RadioList.begin(); + while (radioIter != m_RadioList.end()) + { + bool doDeleteThisItem = false; + PrtCnvStoredRadioTelegram *storedRadioTelegram = *radioIter; + const auto &radioTelegram = storedRadioTelegram->m_RadioTelegram; + + if (radioTelegram) + { + DEBUG_LOG(m_logger) << "Handling Radio-Telegram with id=" << storedRadioTelegram->m_Id + << " TelID: " << radioTelegram->getTelID() + << " rc: " << int(radioTelegram->zaehler()) + << " BC: " << storedRadioTelegram->m_BroadcastIndex + << " wc: " << int(storedRadioTelegram->m_WriteCounter); + + + + if (0 == storedRadioTelegram->m_Id) + { + if (storedRadioTelegram->m_ReadCounter > centralCounter) + centralCounter = storedRadioTelegram->m_ReadCounter; + + storedRadioTelegram->m_WriteCounterChanged = false; + q.bindValue(QStringLiteral(":tel_id"), radioTelegram->getTelID()); + q.bindValue(QStringLiteral(":counter"), storedRadioTelegram->m_WriteCounter); + q.bindValue(QStringLiteral(":broadcast_index"), storedRadioTelegram->m_BroadcastIndex); + q.bindValue(QStringLiteral(":reset_counter"), int(m_ResetCounter)); + q.bindValue(QStringLiteral(":data"), radioTelegram->data()); + q.exec(); + storedRadioTelegram->m_Id = q.lastInsertId().toInt(); + + DEBUG_LOG(m_logger) << "Stored Telegramm in DB, id: " << storedRadioTelegram->m_Id; + + + + + + + if (storedRadioTelegram->m_RadioTelegram->isMovedToBroadcastList()) + { + dumpTelegram(m_logger, + radioTelegram->getBroadcastCounter(), + storedRadioTelegram->m_RadioTelegram.get()); + DEBUG_LOG(m_logger) << "Removed Telegramm from radioList (place 1), id: " << storedRadioTelegram->m_Id; + doDeleteThisItem = true; + } + } + else + { + + + + + if (storedRadioTelegram->m_DoDelete) + { + DEBUG_LOG(m_logger) << "Delete Telegramm from DB, id: " << storedRadioTelegram->m_Id; + m_telegramsToDelete.push_back(storedRadioTelegram->m_Id); + + delete storedRadioTelegram; + doDeleteThisItem = true; + } + + + else if (storedRadioTelegram->m_WriteCounterChanged) + { + m_telegramsToUpdateCounter.emplace_back(std::make_pair(storedRadioTelegram->m_Id, + storedRadioTelegram->m_WriteCounter)); + if (storedRadioTelegram->m_BroadcastIndex) + m_telegramsToUpdateBC.emplace_back(std::make_pair(storedRadioTelegram->m_Id, + storedRadioTelegram->m_BroadcastIndex)); + storedRadioTelegram->m_WriteCounterChanged = false; + + DEBUG_LOG(m_logger) << "Update Write counter in DB, id: " << storedRadioTelegram->m_Id + << " New wc: " << int(storedRadioTelegram->m_WriteCounter) + << " new bc: " << storedRadioTelegram->m_BroadcastIndex; + + if (storedRadioTelegram->m_RadioTelegram->isMovedToBroadcastList()) + { + dumpTelegram(m_logger, + storedRadioTelegram->m_BroadcastIndex, + storedRadioTelegram->m_RadioTelegram.get()); + DEBUG_LOG(m_logger) << "Removed Telegramm from radioList (place 2), id: " << storedRadioTelegram->m_Id; + doDeleteThisItem = true; + } + } + } + } + else + { + + if (storedRadioTelegram->m_ReadCounter > centralCounter) + centralCounter = storedRadioTelegram->m_ReadCounter; + delete storedRadioTelegram; + doDeleteThisItem = true; + } + + if (doDeleteThisItem) + radioIter = m_RadioList.erase(radioIter); + else + ++radioIter; + } + l.unlock(); + + + static const QString &table = toRadioTableName(); + updateTelegramsWriteCounter(table); + + + + updateTelegramsBroadcast(table); + + + deleteTelegramsFromDbById(table); + + return centralCounter; +} + +void PrtCnvDbThread::handleSqlCommandList() +{ + + std::vector sqlCommandList; + { + QMutexLocker l(&m_SqlCmdListMutex); + std::swap(m_SqlCommandList, sqlCommandList); + } + + if (sqlCommandList.empty()) + return; + NSqlQuery q(m_db); + for (const QString &sql : sqlCommandList) + { + DEBUG_LOG(m_logger) << "execute sql=" << sql; + q.exec(sql); + } +} + + + + + +void PrtCnvDbThread::storePermanent() +{ + m_StorePermanentPending = 0; + + TRACE_LOG(m_logger) << "storePermanent m_DoClean=" << m_DoClean << " m_DoWaitUntilSqlWritten=" << m_DoWaitUntilSqlWritten; + if (m_DoClean) + { + m_DoWaitUntilSqlWritten = false; + return; + } + + + + DBTransaction trans(m_db); + + + + storeCentralTelegrams(); + + + + const int32_t centralCounter = storeRadioTelegrams(); + + + + handleSqlCommandList(); + + + trans.commit(); + + + if (0 != centralCounter && centralCounter != m_OldCentralCounter) + { + m_OldCentralCounter = centralCounter; + emit permanentStored(centralCounter); + } + m_DoWaitUntilSqlWritten = false; + +} + + + + + + + + +void PrtCnvDbThread::addSqlCommand(const QString &sql) +{ + QMutexLocker l(&m_SqlCmdListMutex); + m_SqlCommandList.push_back(sql); + + sendStorePermanentSignal(); +} + + + + + + +void PrtCnvDbThread::cleanAndInit() +{ + + m_DoClean = true; + emit doClean(); + + while (m_DoClean) + QThread::sleep(1); + m_DoProceedCleanup = false; +} + + + + + +void PrtCnvDbThread::clean() +{ + NSqlQuery q(m_db); + INFO_LOG(m_logger) << "Delete CentralList"; + { + QMutexLocker l(&m_CentralListMutex); + for (PrtCnvStoredCentralTelegram *t : m_CentralList) + delete t; + m_CentralList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(toCentralTableName())); + } + m_OldCentralCounter = 0; + + INFO_LOG(m_logger) << "Delete RadioList"; + m_EnvironmentTelegram = nullptr; + { + QMutexLocker l(&m_RadioListMutex); + for (PrtCnvStoredRadioTelegram *t : m_RadioList) + delete t; + m_RadioList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(toRadioTableName())); + } + + INFO_LOG(m_logger) << "Delete BroadcastList"; + { + QMutexLocker l(&m_BroadcastMapMutex); + for (PrtCnvStoredRadioTelegram *t : m_BroadcastList) + delete t; + m_BroadcastList.clear(); + } + + + + { + QMutexLocker l(&m_SqlCmdListMutex); + m_MemberListByISSI.clear(); + { + QMutexLocker l2(&m_MemberListByIdMutex); + for (const auto &p : m_MemberListById) + delete p.second; + m_MemberListById.clear(); + } + INFO_LOG(m_logger) << "Delete SqlList"; + m_SqlCommandList.clear(); + q.exec(QStringLiteral("DELETE FROM %1;").arg(memberTableName())); + } + + + licenseMember(addMember(0, m_Config->getInteger(QStringLiteral("Radio"), QStringLiteral("BroadcastISSI"), 5000))); + + m_DoClean = false; +} + + + + + + + + +bool PrtCnvDbThread::resendCentralTelegrams(const int32_t a_lastSendCounter) +{ + const int centralAckCnt = m_CentralAckCounter; + if (a_lastSendCounter > centralAckCnt) + { + bool warnOnce = true; + QMutexLocker l(&m_CentralListMutex); + int iCount = 0; + std::vector::const_iterator iter = m_CentralList.begin(); + std::vector::const_iterator end = m_CentralList.end(); + for (; iter != end && iCount < 50; ++iter) + { + PrtCnvStoredCentralTelegram *storedTelegram = *iter; + if (!storedTelegram) + continue; + ++iCount; + if (storedTelegram->m_WriteCounter > centralAckCnt) + { + if (warnOnce) + { + WARNING_LOG(m_logger) << "Resend central-telegrams from wc=" << a_lastSendCounter + << " centralAckCounter=" << centralAckCnt; + warnOnce = false; + } + INFO_LOG(m_logger) << "Resend central-telegram with telId=" + << storedTelegram->m_CentralTelegram->telegramId() + << " wc=" << storedTelegram->m_WriteCounter; + storedTelegram->m_DoResend = true; + } + } + return true; + } + return false; +} + + + + + + + + +void PrtCnvDbThread::prepareCentralTelegramsForReconnection() +{ + INFO_LOG(m_logger) << "m_CentralAckCounter=" << m_CentralAckCounter; + waitUntilDbWritten(); + + INFO_LOG(m_logger) << "start"; + m_CentralAckCounter = 0; + m_OldCentralAckCounter = 0; + m_OldCentralCounter = 0; + QMutexLocker l(&m_CentralListMutex); + for (PrtCnvStoredCentralTelegram *storedTelegram : m_CentralList) + { + if (!storedTelegram) + continue; + if (storedTelegram->m_WriteCounter != 0) + { + INFO_LOG(m_logger) << "***Prepare central-telegram with id=" << storedTelegram->m_Id + << " telId=" << storedTelegram->m_CentralTelegram->telegramId() + << " wc=" << storedTelegram->m_WriteCounter << " wcChg=" + << storedTelegram->m_WriteCounterChanged + << " for resend after reconnection"; + storedTelegram->m_WriteCounter = 0; + storedTelegram->m_WriteCounterChanged = false; + storedTelegram->m_DoResend = false; + } + } + INFO_LOG(m_logger) << "Ready for reconnection"; +} + + + + + +void PrtCnvDbThread::waitUntilDbWritten() +{ + m_DoWaitUntilSqlWritten = true; + emit doStorePermanent(); + while (m_DoWaitUntilSqlWritten) + QThread::usleep(10000); + + + m_DoWaitUntilSqlWritten = true; + emit doStorePermanent(); + while (m_DoWaitUntilSqlWritten) + QThread::usleep(10000); +} + + + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::addMember(const int a_identity, const int a_ISSI) +{ + PrtCnvMember *newMember = new PrtCnvMember(a_identity, a_ISSI); + { + QMutexLocker lSql(&m_SqlCmdListMutex); + QMutexLocker lId(&m_MemberListByIdMutex); + m_MemberListById.insert(std::make_pair(a_identity, newMember)); + m_MemberListByISSI.insert(std::make_pair(a_ISSI, newMember)); + } + + DEBUG_LOG(m_logger) << "Adding member with eqId " << a_identity + << " and issi " << a_ISSI + << ", store in db: " << m_DoStorePermanent; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("INSERT INTO %1 (id, issi) VALUES(%2, %3)") + .arg(memberTableName()).arg(newMember->m_Id).arg(newMember->m_ISSI)); + + return newMember; +} + + + + + +void PrtCnvDbThread::removeMember(PrtCnv::PrtCnvMember *a_member) +{ + { + QMutexLocker lSql(&m_SqlCmdListMutex); + QMutexLocker lId(&m_MemberListByIdMutex); + auto iterId = m_MemberListById.find(a_member->m_Id); + if (iterId != m_MemberListById.end()) + m_MemberListById.erase(iterId); + else + ERROR_LOG(m_logger) << "Internal error: did not find the member by ID"; + auto iterIssi = m_MemberListByISSI.find(a_member->m_ISSI); + if (iterIssi != m_MemberListByISSI.end()) + m_MemberListByISSI.erase(iterIssi); + else + ERROR_LOG(m_logger) << "Internal error: did not find the member by ISSI"; + } + + DEBUG_LOG(m_logger) << "Removing member with eqId " << a_member->m_Id + << " and issi " << a_member->m_ISSI + << ", store in db: " << m_DoStorePermanent; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("DELETE FROM %1 WHERE id = %2 OR issi = %3") + .arg(memberTableName()).arg(a_member->m_Id).arg(a_member->m_ISSI)); + + delete a_member; +} + + + + + +bool PrtCnvDbThread::licenseMember(PrtCnvMember *a_member, const bool a_doLicense) +{ + if (!a_member) + return false; + a_member->m_Licensed = a_doLicense; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET licensed = %2 WHERE id = %3") + .arg(memberTableName()).arg(a_doLicense ? 1 : 0).arg(a_member->m_Id)); + return true; +} + +void PrtCnvDbThread::updateExerciseIdForMember(PrtCnvMember *a_member, int newExerciseId) +{ + if (!a_member) + return; + a_member->m_loggedInExerciseId = newExerciseId; + DEBUG_LOG(m_logger) << "Updating exerciseId member with eqId " << a_member->m_Id + << " and issi " << a_member->m_ISSI << " to " << newExerciseId + << ", store in db: " << m_DoStorePermanent; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET exercise_id = %2 WHERE id = %3") + .arg(memberTableName()).arg(newExerciseId).arg(a_member->m_Id)); +} + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::getMemberById(const uint16_t a_id) +{ + QMutexLocker l(&m_MemberListByIdMutex); + auto iter = m_MemberListById.find(a_id); + if (iter != m_MemberListById.end()) + return iter->second; + + return nullptr; +} + + + + + +PrtCnv::PrtCnvMember *PrtCnvDbThread::getMemberByISSI(const uint32_t a_ISSI) const +{ + auto iter = m_MemberListByISSI.find(a_ISSI); + if (iter != m_MemberListByISSI.end()) + return iter->second; + + return nullptr; +} + + + + + + +uint8_t PrtCnvDbThread::getResetCounter() const +{ + return m_ResetCounter; +} + + + + + +void PrtCnvDbThread::setResetCounter(uint8_t newVal) +{ + m_ResetCounter = newVal; + if (m_DoStorePermanent) + { + NSqlQuery q(m_db); + q.exec(QStringLiteral("UPDATE Status SET reset_counter = %1 WHERE id = 1") + .arg(int(newVal))); + } + INFO_LOG(m_logger) << "Update resetCounter=" << (int)m_ResetCounter << " doStorePermanent=" << m_DoStorePermanent; +} + + + + + + +uint8_t PrtCnvDbThread::getBattleFieldOperatingState() const +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + return m_BattleFieldOperatingState; +} + + + + + +void PrtCnvDbThread::setPause(const bool a_doSet) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + if (a_doSet) + m_BattleFieldOperatingState = m_BattleFieldOperatingState | 0x80; + else + m_BattleFieldOperatingState = m_BattleFieldOperatingState & 0x7F; + + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET ctas_operating_state = %2 WHERE id = 1") + .arg(statusTableName()).arg(int(m_BattleFieldOperatingState))); + + INFO_LOG(m_logger) << "Update battleFieldOperatingState=" << (int)m_BattleFieldOperatingState << " doStorePermanent=" << m_DoStorePermanent; +} + + + + +void PrtCnvDbThread::setPositionSendTime(unsigned int sendTime) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + if (sendTime > 31) + sendTime = 31; + if (sendTime < 1) + sendTime = 1; + + + m_BattleFieldOperatingState &= 0x83; + + m_BattleFieldOperatingState |= (sendTime << 2); +} + + + + +void PrtCnvDbThread::setAirLoad(PrtCnvRadioThread::E_TrafficLoad airLoad) +{ + QMutexLocker l(&m_BattleFieldOpStateMutex); + + + m_BattleFieldOperatingState &= 0xFC; + + m_BattleFieldOperatingState |= (static_cast(airLoad) & 0x03); +} + + + + + +bool PrtCnvDbThread::isEnvironmentResetCounterOld() const +{ + QMutexLocker l(&m_RadioListMutex); + + bool isOld = false; + if (m_EnvironmentTelegram) + isOld = getResetCounter() != m_EnvironmentTelegram->m_RadioTelegram->getPayloadDataUInt8(7); + return isOld; +} + + + + + +void PrtCnvDbThread::setResetCounterOnEnvironment() +{ + QMutexLocker l(&m_RadioListMutex); + + if (m_EnvironmentTelegram) + m_EnvironmentTelegram->m_RadioTelegram->setPayloadDataWithIndex(7, getResetCounter(), 1); +} + + + + +std::shared_ptr PrtCnvDbThread::getEnvironmentTelegram() +{ + QMutexLocker l(&m_RadioListMutex); + if (m_EnvironmentTelegram) + return std::make_shared(m_EnvironmentTelegram->m_RadioTelegram->data()); + return {}; +} + + + + + +std::map PrtCnvDbThread::getClaimStatistics() const +{ + std::map ret; + QMutexLocker l(&m_MemberListByIdMutex); + for (const auto &p : m_MemberListById) + { + if (p.first != 0) + ret.insert(std::make_pair(p.first, p.second->m_ClaimCount)); + } + return ret; +} + + + + + + +void PrtCnvDbThread::incClaimCount(int a_identity) +{ + QMutexLocker l(&m_MemberListByIdMutex); + auto iter = m_MemberListById.find(a_identity); + if (iter != m_MemberListById.end()) + { + iter->second->m_ClaimCount++; + if (m_DoStorePermanent) + addSqlCommand(QStringLiteral("UPDATE %1 SET claims = claims + 1 WHERE id = %2") + .arg(memberTableName()).arg(iter->second->m_Id)); + } + else + ERROR_LOG(m_logger) << "Internal error: did not find TNE with id=" << a_identity; +} + + + + + + + + +void PrtCnvDbThread::setMachineState(const int a_newMachineState) +{ + NSqlQuery q(m_db); + q.exec(QStringLiteral("UPDATE %1 SET machine_state = %2 WHERE id = 1") + .arg(statusTableName()).arg(a_newMachineState)); +} + + + + + + + +bool PrtCnvDbThread::mustProceedCleanup() const +{ + return m_DoProceedCleanup; +} + + + + + + + +void PrtCnvDbThread::sendStorePermanentSignal() +{ + if (m_StorePermanentPending.testAndSetOrdered(0, 1)) + emit doStorePermanent(); +} + +void PrtCnvDbThread::closeDb() +{ + if (m_db.isOpen()) + { + m_db.close(); + m_db = QSqlDatabase(); + QSqlDatabase::removeDatabase(QStringLiteral("PrtCnv")); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvDbThread.hpp b/TetraIF/PrtCnv/PrtCnvDbThread.hpp new file mode 100644 index 000000000..bad046a43 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvDbThread.hpp @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + +#pragma once + +#include +#include +#include +#include +#include "PrtCnvThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include +#include +#include + +namespace N_CoPrtCnv +{ + class CoPrtCnvCentralTelegram; + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + class PrtCnvStoredCentralTelegram; + class PrtCnvStoredRadioTelegram; + class PrtCnvMember; + + + class PrtCnvDbThread : public PrtCnvThread + { + Q_OBJECT + + public: + + + PrtCnvDbThread(const QString &dbDriver, + const QString &dbHostName, + const QString &dbDatabaseName, + const QString &schemaName, + const QString &dbUserName, + const QString &dbPassword, + PrtCnvThreadStarter* a_parent); + ~PrtCnvDbThread(); + + + + int32_t start() override; + + + int32_t stop() override; + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + void ackCentralTelegrams(int32_t a_counter); + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextCentralTelegram(PrtCnvStoredCentralTelegram *& a_handle); + + + + void centralTelegramSent(const int32_t a_counter, PrtCnvStoredCentralTelegram *a_handle); + + + + void centralTelegramCouldNotBeSent(PrtCnvStoredCentralTelegram *a_handle); + + + + void radioTelegramSent(const uint32_t a_sendCounter, PrtCnvStoredRadioTelegram *a_handle, const uint32_t a_broadcastIndex); + + + + std::shared_ptr getNextRadioTelegram(PrtCnvStoredRadioTelegram *&a_handle); + + + + std::shared_ptr getNextBroadcastTelegram(); + + + + void storeCentralTelegram(const std::shared_ptr &a_centralTelegram, + const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + + void storeRadioTelegram(const std::shared_ptr &a_telegram, const int32_t a_readCounter); + + + + void centralCounterReadyForAck(const int32_t a_centralCounter); + + + + void addSqlCommand(const QString &sql); + + + + + void cleanAndInit(); + + + + bool resendCentralTelegrams(const int32_t a_lastSendCounter); + + + + void prepareCentralTelegramsForReconnection(); + + + + void waitUntilDbWritten(); + + + + PrtCnvMember* getMemberByISSI(const uint32_t a_ISSI) const; + + + + PrtCnvMember* getMemberById(const uint16_t a_id); + + + + bool licenseMember(PrtCnvMember *a_member, const bool a_doLicense = true); + + + + void updateExerciseIdForMember(PrtCnvMember *a_member, int newExerciseId); + + + + PrtCnvMember* addMember(const int a_identity, const int a_ISSI); + + + + void removeMember(PrtCnvMember* a_member); + + + + uint8_t getResetCounter() const; + + + + void setResetCounter(uint8_t newVal); + + + + uint8_t getBattleFieldOperatingState() const; + + + + void setPause(const bool a_doSet = true); + + + + void setPositionSendTime(unsigned int sendTime); + + + + void setAirLoad(PrtCnvRadioThread::E_TrafficLoad airLoad); + + + + bool isEnvironmentResetCounterOld() const; + + + + std::shared_ptr getEnvironmentTelegram(); + + + + void setResetCounterOnEnvironment(); + + + + void incClaimCount(int a_identity); + + + + std::map getClaimStatistics() const; + + + + void setMachineState(const int a_newMachineState); + + + + bool mustProceedCleanup() const; + + protected: + void closeDb(); + + + + std::vector m_CentralList; + + + + mutable QMutex m_BattleFieldOpStateMutex; + + + + mutable QMutex m_MemberListByIdMutex; + + + + mutable QMutex m_CentralListMutex; + + + + QSqlDatabase m_db; + + + + QAtomicInt m_CentralAckCounter; + + + unsigned int m_OldCentralAckCounter; + + + std::list m_RadioList; + + + mutable QMutex m_RadioListMutex; + + + std::vector m_SqlCommandList; + + + mutable QMutex m_SqlCmdListMutex; + + + mutable QMutex m_BroadcastMapMutex; + + + std::list m_BroadcastList; + + + bool m_DoClean; + + + bool m_DoWaitUntilSqlWritten; + + + std::unordered_map m_MemberListById; + + + std::unordered_map m_MemberListByISSI; + + + bool m_DoStorePermanent; + + + uint8_t m_ResetCounter; + + + uint8_t m_BattleFieldOperatingState; + + + PrtCnvStoredRadioTelegram* m_EnvironmentTelegram; + + + bool m_DoProceedCleanup; + + + int32_t m_OldCentralCounter; + + + QBasicAtomicInt m_StorePermanentPending; + + + + uint32_t m_NbrOfAttempts; + + + + bool createDatabase(); + + + + void sendStorePermanentSignal(); + + + + void storeCentralTelegrams(); + + + + int32_t storeRadioTelegrams(); + + + + void handleSqlCommandList(); + + + + void deleteTelegramsFromDbById(const QString &table); + + + void updateTelegramsWriteCounter(const QString &table); + + + + void updateTelegramsBroadcast(const QString &table); + + + + void reinitDatabase(); + + QString toCentralTableName() const { return tableName(QStringLiteral("prtcnv_to_central")); } + QString toRadioTableName() const { return tableName(QStringLiteral("prtcnv_to_radio")); } + QString memberTableName() const { return tableName(QStringLiteral("prtcnv_member")); } + QString statusTableName() const { return tableName(QStringLiteral("prtcnv_status")); } + QString versionTableName() const { return tableName(QStringLiteral("prtcnv_version")); } + QString tableName(const QString &table) const { return m_dbSchemaName.isEmpty() ? table : m_dbSchemaName + QLatin1Char('.') + table; } + protected slots: + + + void storePermanent(); + + + void clean(); + + public: + signals: + + + void doStorePermanent(); + + + void permanentStored(int32_t a_centralCounter); + + + void doClean(); + + void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + + private: + + + + std::vector m_telegramsToDelete; + std::vector > m_telegramsToUpdateCounter; + std::vector > m_telegramsToUpdateBC; + std::vector > m_telegramsToInsert; + QString m_dbDriver; + QString m_dbHostName; + QString m_dbDatabaseName; + QString m_dbSchemaName; + QString m_dbUserName; + QString m_dbPassword; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp b/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp new file mode 100644 index 000000000..b8d586cbc --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionSocket.cpp @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + +#include "PrtCnvInjectionSocket.hpp" +#include +#include +#include "PrtCnvInjectionThread.hpp" +#include +#include + +namespace PrtCnv +{ + +PrtCnvInjectionSocket::PrtCnvInjectionSocket() + : m_Socket(nullptr) + , m_Server(nullptr) + , m_logger(getLogger("PrtCnvInjectionSocket")) +{} + +PrtCnvInjectionSocket::~PrtCnvInjectionSocket() +{ + delete m_Socket; +} + + + + +void PrtCnvInjectionSocket::disconnectClient() +{ + INFO_LOG(m_logger) << "A client has disconnected from the injection-server"; + emit disconnected(this); +} + + + + + +void PrtCnvInjectionSocket::processInputData() +{ + INFO_LOG(m_logger) << "Injection-server has data received"; + N_CoPrtCnv::CoPrtCnvInjectionHeader injectionHeader; + qint64 bytesRead = m_Socket->peek((char*)&injectionHeader, sizeof(injectionHeader)); + if (sizeof(injectionHeader) == bytesRead) + { + if (injectionHeader.isIdCorrect()) + { + + qint64 available = m_Socket->bytesAvailable(); + if (available < (injectionHeader.m_Size+sizeof(injectionHeader))) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data: " + << "headersize=" << sizeof(injectionHeader) << " id1=" + << injectionHeader.m_Id1 << " id2=" << injectionHeader.m_Id2 + << " kind=" << (int)injectionHeader.m_Kind << " size=" + << injectionHeader.m_Size; + return; + } + + m_Socket->read((char*)&injectionHeader, sizeof(injectionHeader)); + if (injectionHeader.isIdCorrect()) + { + + + + QByteArray data(injectionHeader.m_Size, Qt::Uninitialized); + m_Socket->read(data.data(), injectionHeader.m_Size); + + switch (injectionHeader.m_Kind) + { + case N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral: + case N_CoPrtCnv::CoPrtCnvInjectionHeader::eRadio: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = new N_CoPrtCnv::CoPrtCnvCentralTelegram(data); + + if (N_CoPrtCnv::CoPrtCnvInjectionHeader::eCentral == injectionHeader.m_Kind && + tele->telegramId() != TrainingAreaBase::TetraIcd::TelegramId::DATENVERKEHR_TDS_SRT) + { + INFO_LOG(m_logger) << "Got an injection-central-telegram with telId=" << tele->telegramId(); + m_Server->addToCentralList(tele); + } + else + { + INFO_LOG(m_logger) << "Got an injection-radio-telegram with telId=" << tele->telegramId(); + m_Server->addToRadioList(tele); + } + } + break; + + default: + ERROR_LOG(m_logger) << "Unknown kind (" << injectionHeader.m_Kind << ") of injection-telegram"; + break; + } + } + } + else + { + ERROR_LOG(m_logger) << "Corrupt injection-telegram received => reconnect"; + m_Socket->disconnectFromHost(); + } + } +} + + +void PrtCnvInjectionSocket::setSocket(QTcpSocket* a_socket, PrtCnvInjectionThread* a_server) +{ + m_Socket = a_socket; + m_Server = a_server; + connect(this, &PrtCnvInjectionSocket::disconnected, m_Server, &PrtCnvInjectionThread::disconnectClient, Qt::QueuedConnection); + if (m_Socket) + { + connect(m_Socket, &QTcpSocket::readyRead, this, &PrtCnvInjectionSocket::processInputData, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::disconnected, this, &PrtCnvInjectionSocket::disconnectClient, Qt::QueuedConnection); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp b/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp new file mode 100644 index 000000000..a5921191e --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionSocket.hpp @@ -0,0 +1,66 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include "logger.h" + +class QTcpSocket; + +namespace PrtCnv +{ + class PrtCnvInjectionThread; + + + class PrtCnvInjectionSocket : public QObject + { + Q_OBJECT + public: + + PrtCnvInjectionSocket(); + ~PrtCnvInjectionSocket(); + + + + void setSocket(QTcpSocket* a_socket, PrtCnvInjectionThread* a_server); + + protected: + QTcpSocket *m_Socket; + + PrtCnvInjectionThread *m_Server; + + + + NGL::INGLLogger &m_logger; + + protected slots: + + + void disconnectClient(); + + + + void processInputData(); + + + public: + signals: + + + void disconnected(PrtCnvInjectionSocket* a_injectSocket); + + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp b/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp new file mode 100644 index 000000000..98e06717d --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionThread.cpp @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvInjectionSocket.hpp" + +#include +#include +#include +#include + + +namespace PrtCnv +{ + +PrtCnvInjectionThread::PrtCnvInjectionThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvInjectionThread") + , m_Port(46666) + , m_Enabled(false) + , m_Server(nullptr) + , m_CentralListMutex(nullptr) + , m_RadioListMutex(nullptr) +{ + m_Name = QStringLiteral("Injection"); +} + +PrtCnvInjectionThread::~PrtCnvInjectionThread() +{ + delete m_CentralListMutex; + delete m_RadioListMutex; +} + + +int32_t PrtCnvInjectionThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvThread::create(settings); + + m_CentralListMutex = new QMutex; + m_RadioListMutex = new QMutex; + + m_Enabled = m_Config->getBoolean(getName(), QStringLiteral("Enable"), false); + + + if (m_Enabled) + { + m_Server = new QTcpServer(this); + if (m_Server) + connect(m_Server, &QTcpServer::newConnection, this, &PrtCnvInjectionThread::connectClient, Qt::QueuedConnection); + } + + return 0; +} + + + +int32_t PrtCnvInjectionThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvThread::init(); + m_Port = m_Config->getInteger(getName(), QStringLiteral("Port"), 46666); + + return 0; +} + + + + + + +int32_t PrtCnvInjectionThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvThread::start(); + + + if (m_Enabled) + { + m_Server->setMaxPendingConnections(1); + m_Server->listen(QHostAddress::Any, m_Port); + INFO_LOG(m_logger) << "Injection-Server is listening on port " << m_Port; + } + + return 0; +} + + + + + + +void PrtCnvInjectionThread::connectClient() +{ + INFO_LOG(m_logger) << "A client has connected to the injection-server"; + PrtCnvInjectionSocket* injectSocket = new PrtCnvInjectionSocket; + m_SocketList.insert(injectSocket); + INFO_LOG(m_logger) << "Now are " << m_SocketList.size() << " injection-client(s) connected"; + injectSocket->setSocket(m_Server->nextPendingConnection(), this); +} + + + + + + +void PrtCnvInjectionThread::disconnectClient(PrtCnvInjectionSocket *a_injectionSocket) +{ + auto it = m_SocketList.find(a_injectionSocket); + if (it != m_SocketList.end()) + m_SocketList.erase(it); + INFO_LOG(m_logger) << "Now are " << m_SocketList.size() << " injection-client(s) connected"; + delete a_injectionSocket; +} + + + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvInjectionThread::getNextCentralInjectionTelegram() +{ + QMutexLocker l(m_CentralListMutex); + + if (m_CentralTelegramList.empty()) + return nullptr; + auto centralTelegram = m_CentralTelegramList.front(); + m_CentralTelegramList.pop(); + return centralTelegram; +} + + + + + + + + + +N_CoPrtCnv::CoPrtCnvCentralTelegram *PrtCnvInjectionThread::getNextRadioInjectionTelegram() +{ + QMutexLocker l(m_RadioListMutex); + + if (m_RadioTelegramList.empty()) + return nullptr; + auto radioTelegram = m_RadioTelegramList.front(); + m_RadioTelegramList.pop(); + return radioTelegram; +} + + + +void PrtCnvInjectionThread::addToCentralList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + QMutexLocker l(m_CentralListMutex); + m_CentralTelegramList.push(a_telegram); +} + + + +void PrtCnvInjectionThread::addToRadioList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram) +{ + QMutexLocker l(m_RadioListMutex); + m_RadioTelegramList.push(a_telegram); +} + +} + diff --git a/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp b/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp new file mode 100644 index 000000000..52cf3ac1d --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvInjectionThread.hpp @@ -0,0 +1,101 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" +#include +#include + +class QTcpServer; +class QMutex; + +namespace N_CoPrtCnv +{ +class CoPrtCnvCentralTelegram; +} + +namespace PrtCnv +{ + class PrtCnvInjectionSocket; + + + class PrtCnvInjectionThread : public PrtCnvThread + { + Q_OBJECT + public: + + ~PrtCnvInjectionThread(); + + + + explicit PrtCnvInjectionThread(PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + + int32_t start() override; + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextCentralInjectionTelegram(); + + + + N_CoPrtCnv::CoPrtCnvCentralTelegram *getNextRadioInjectionTelegram(); + + + + void addToCentralList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + + + void addToRadioList(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_telegram); + + protected: + + uint16_t m_Port; + + + bool m_Enabled; + QTcpServer *m_Server; + + + std::queue m_CentralTelegramList; + QMutex *m_CentralListMutex; + + + std::queue m_RadioTelegramList; + QMutex *m_RadioListMutex; + + + std::set m_SocketList; + + + + public slots: + + + void connectClient(); + + + void disconnectClient(PrtCnvInjectionSocket* a_injectionSocket); + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvMain.cpp b/TetraIF/PrtCnv/PrtCnvMain.cpp new file mode 100644 index 000000000..627585784 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMain.cpp @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + +#include "PrtCnvApplication.hpp" +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#endif + + + + +static void daemonize() +{ +#ifndef WIN32 + pid_t pid, sid; + + + if ( getppid() == 1 ) + return; + + + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + + + + umask(0); + + + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + + + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } + + + freopen( "/dev/null", "r", stdin); + freopen( "/dev/null", "w", stdout); + freopen( "/dev/null", "w", stderr); +#endif +} + +class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser +{ +public: + CmdLineParser() + : LtsCommandLineParser(ProvideCommandLineParameterOptions(ExerciseId|CustomConfigFile)) + { + addOption( { QStringList() << QStringLiteral("d") << QStringLiteral("daemonize"), + QStringLiteral("Start in background") } ); + addOption( { QStringList() << QStringLiteral("c") << QStringLiteral("cleandb"), + QStringLiteral("Start over with clean database") } ); + } + + bool daemonize() const + { + return isSet(QStringLiteral("d")); + } + bool cleanDb() const + { + return isSet(QStringLiteral("c")); + } +}; + +int main(int argc, char** argv) +{ + QNetworkProxy::setApplicationProxy(QNetworkProxy()); + NGLCoreApplication app(argc, argv); + + CmdLineParser options; + if (!options.init()) + return -1; + app.createLogger("PrtCnv", options.exerciseId()); + + if (options.daemonize()) + daemonize(); + + PrtCnv::PrtCnvApplication prtCnvApp; + prtCnvApp.setCleanDb(options.cleanDb()); + prtCnvApp.setExerciseId(options.exerciseId()); + if (options.iniFileSet()) + prtCnvApp.setConfigFile(options.iniFile()); + + STARTUP_LOG(app.baseLogger()); + + prtCnvApp.startApp(); + int ret = app.exec(); + prtCnvApp.shutdownApp(); + + SHUTDOWN_LOG(app.baseLogger()); + + return ret; +} diff --git a/TetraIF/PrtCnv/PrtCnvMember.cpp b/TetraIF/PrtCnv/PrtCnvMember.cpp new file mode 100644 index 000000000..8be0b0767 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMember.cpp @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + +#include "PrtCnvMember.hpp" +#include + +namespace PrtCnv +{ + + + + +PrtCnvMember::PrtCnvMember(int a_id, int a_issi) + : m_ISSI(a_issi) + , m_ClaimCount(0) + , m_loggedInExerciseId(0) + , m_Id(a_id) + , m_Licensed(false) +{} + +PrtCnvMember::~PrtCnvMember() +{ + clearFragmentedList(); +} + + + + + +void PrtCnvMember::addFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + m_FragmentedTelegramList.insert(std::make_pair(a_radioTelegram.getFragmentCounter(), + new N_CoPrtCnv::CoPrtCnvRadioTelegram(a_radioTelegram))); +} + + + + + + + + +gef_telegramm_id_et PrtCnvMember::getFragmentedTelegramId() const +{ + + for (auto rit = m_FragmentedTelegramList.rbegin(); rit != m_FragmentedTelegramList.rend(); ++rit) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram *firstFragment = rit->second; + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment == firstFragment->getFragmentStatus()) + return firstFragment->getTelID(); + } + return GEF_BESTAETIGUNG; +} + + + + + + +void PrtCnvMember::clearFragmentedList() +{ + for (auto it : m_FragmentedTelegramList) + delete it.second; + m_FragmentedTelegramList.clear(); +} + + + + + + + +QByteArray PrtCnvMember::getUnfragmentedTelegramData() const +{ + return N_CoPrtCnv::CoPrtCnvRadioTelegram::getUnfragmentedData(m_FragmentedTelegramList); +} + + + + + +bool PrtCnvMember::isFragmentedListEmpty() const +{ + return m_FragmentedTelegramList.empty(); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvMember.hpp b/TetraIF/PrtCnv/PrtCnvMember.hpp new file mode 100644 index 000000000..ebe580760 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvMember.hpp @@ -0,0 +1,84 @@ + + + + + + + + + + + + + +#pragma once + +#include +#include +#include + + + + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + + + class PrtCnvMember final + { + public: + + + + enum E_MemberStatus + { + e_Ok, + e_AlreadyLoggedIn, + e_MasteringLogIn, + e_NotLoggedIn + }; + ~PrtCnvMember(); + + + + PrtCnvMember(int a_id, int a_issi); + + + + void addFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + gef_telegramm_id_et getFragmentedTelegramId() const; + + + void clearFragmentedList(); + + + QByteArray getUnfragmentedTelegramData() const; + + + bool isFragmentedListEmpty() const; + + public: + + int m_ISSI; + + int m_ClaimCount; + + int m_loggedInExerciseId; + + int m_Id; + + bool m_Licensed; + + private: + + std::multimap m_FragmentedTelegramList; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioThread.cpp b/TetraIF/PrtCnv/PrtCnvRadioThread.cpp new file mode 100644 index 000000000..3cfca6dd0 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioThread.cpp @@ -0,0 +1,2267 @@ + + + + + + + + + + + + + + +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvMember.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvDbThread.hpp" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace PrtCnv +{ + +static BiteError getBiteError(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, + size_t iOffset) +{ + BiteError ret; + ret.canDeviceNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 0); + ret.subdeviceNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 1); + ret.uniqueId = a_radioTelegram.getPayloadDataUInt32(iOffset + 2, 4); + ret.errorNumber = a_radioTelegram.getPayloadDataUInt8(iOffset + 6); + + return ret; +} + +PrtCnvRadioThread::PrtCnvRadioThread(int exerciseId, PrtCnvThreadStarter *a_parent) + : PrtCnvSocketThread(a_parent, "PrtCnvRadioThread"), + m_CentralThread(nullptr), + m_radioTrafficThread(nullptr), + m_SendCounter(0), + m_HostISSI(0), + START_COUNTER(0), + END_COUNTER(256), + m_EnvironmentTelegramTimer(nullptr), + m_BroadcastISSI(0), + m_LoginPathWithPrefix(QString()), + m_ExerciseId(exerciseId), + m_DoLicenseDespiteSelftestOrConfigFailure(false), + m_DoCheckIdentity(true), + m_DoDumpReceivedTelegrams(false), + m_DoDumpSentTelegrams(false), + m_DoUseSDSTL(false), + m_EmergencyCallISSI(0), + m_EnvironmentTelegram(nullptr), + m_SendLoad(E_TrafficLoad::Unknown), + m_SendQueueFullLoad(0), + m_SendQueueHighLoad(0), + m_SendTelegramsNormalLoad(100), + m_SendTelegramsHighLoad(50), + m_SendTelegramsFullLoad(10), + m_SentTelegrams(0), + m_SentBytes(0), + m_TickCounter(0), + m_TicksPerSecond(0), + m_AverageIndex(0), + m_ReceivedTelegrams(0), + m_ReceivedBytes(0), + m_bUseScrambling(false), + m_loggerStats(getLogger("PrtCnvRadioThread.statistic")), + m_exerciseEquipmentAssignmentMutex(QMutex::Recursive) +{ + m_Name = QStringLiteral("Radio"); + for (int i = 0; i < AVERAGE_COUNT; ++i) + { + m_SentBytesAverage[i] = 0; + m_ReceivedBytesAverage[i] = 0; + } + qRegisterMetaType("N_CoPrtCnv::E_LicensingKind"); +} + + + + +int32_t PrtCnvRadioThread::create(NGL::Settings *settings) +{ + INFO_LOG(m_logger) << "create"; + PrtCnvSocketThread::create(settings); + m_BroadcastManager.create(settings); + + m_CentralThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Central)); + connect(this, &PrtCnvRadioThread::checkSendToRadio, + this, &PrtCnvRadioThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::checkMemberForValidLogin, + this, &PrtCnvRadioThread::onCheckMemberForValidLogin, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::checkSendToCentral, + m_CentralThread, &PrtCnvCentralThread::checkSend, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::stopped, + m_CentralThread, &PrtCnvCentralThread::radioStopped, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::cleant, + m_CentralThread, &PrtCnvCentralThread::radioCleant, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::tetraConnectionState, + m_CentralThread, &PrtCnvCentralThread::onTetraConnectionState, Qt::QueuedConnection); + connect(this, &PrtCnvRadioThread::playerLicencedChanged, + m_CentralThread, &PrtCnvCentralThread::onPlayerLicencedChanged, Qt::QueuedConnection); + connect(&m_BroadcastManager, &PrtCnvBroadcastMgr::areaEffectSimulationDeactivated, + this, &PrtCnvRadioThread::areaEffectSimulationDeactivated); + connect(&m_BroadcastManager, &PrtCnvBroadcastMgr::areaEffectSimulationActivated, + this, &PrtCnvRadioThread::areaEffectSimulationActivated); + + auto mainApp = m_Parent->getMainApp(); + connect(mainApp, &PrtCnvApplication::outgoingBroadcastTelegramsRequest, + this, &PrtCnvRadioThread::onBroadcastTelegramsRequestFromCentral); + + connect(this, &PrtCnvRadioThread::warehouseMessageFromPtrCnv, + mainApp, &PrtCnvApplication::warehouseMessageFromPtrCnv); + + static_assert(sizeof(N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader) == 4, + "This code expects a size of 4 for CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader (otherwise it will not work correct)" + ); + return 0; +} + + + + + +int32_t PrtCnvRadioThread::destroy() +{ + INFO_LOG(m_logger) << "Destroy"; + PrtCnvSocketThread::destroy(); + delete m_EnvironmentTelegramTimer; m_EnvironmentTelegramTimer = nullptr; + return 0; +} + + + + + +int32_t PrtCnvRadioThread::init() +{ + INFO_LOG(m_logger) << "init"; + PrtCnvSocketThread::init(); + m_BroadcastManager.setDbThread(m_DbThread); + m_TickTimeout = m_Config->getInteger(QStringLiteral("Broadcast"), QStringLiteral("SendGap"), 500); + m_TicksPerSecond = 1000 / m_TickTimeout; + m_BroadcastManager.init(); + + N_CoPrtCnv::CoPrtCnvRadioTelegram::setEtsMode(m_Config->getBoolean(getName(), QStringLiteral("EtsMode"), false)); + + m_HostISSI = m_Config->getInteger(getName(), QStringLiteral("HostISSI"), 9998); + m_BroadcastISSI = m_Config->getInteger(getName(), QStringLiteral("BroadcastISSI"), 5000); + m_EmergencyCallISSI = m_Config->getInteger(getName(), QStringLiteral("EmergencyCallISSI"), 9000); + if (m_DoCleanDb) + m_DbThread->licenseMember(m_DbThread->addMember(0, m_BroadcastISSI)); + + QString groupString = m_Config->getString(getName(), QStringLiteral("ListenGroups"), QString()); + const QVector groups = groupString.splitRef(QLatin1Char(','), QString::SkipEmptyParts); + for (const QStringRef &sr : groups) + { + uint32_t group = sr.toUInt(); + if (group > 0) + m_ListenGroups.insert(group); + } + if (m_ListenGroups.size() > 5) + { + while (m_ListenGroups.size() > 5) + m_ListenGroups.erase(m_ListenGroups.end()); + WARNING_LOG(m_logger) << "More than 5 ListenGroups defined - ignoring all except the first 5"; + } + + m_LoginPathWithPrefix = m_Config->getString(QStringLiteral("Login"), QStringLiteral("LoginFilePathWithPrefix"), QStringLiteral("login")); + if (!QDir::isAbsolutePath(m_LoginPathWithPrefix)) + m_LoginPathWithPrefix = QCoreApplication::applicationDirPath() + QLatin1String("/../") + m_LoginPathWithPrefix; + + m_LoginPathWithPrefix = QDir::cleanPath(QDir::fromNativeSeparators(m_LoginPathWithPrefix)); + QString path = m_LoginPathWithPrefix.left(m_LoginPathWithPrefix.lastIndexOf(QLatin1Char('/'))); + QDir().mkpath(path); + + m_DoLicenseDespiteSelftestOrConfigFailure = m_Config->getBoolean(QStringLiteral("Login"), QStringLiteral("DoLicenseDespiteSelftestOrConfigFailure"), false); + initIdentityArray(); + + m_bUseScrambling = m_Config->getBoolean(getName(), QStringLiteral("UseScrambling"), false); + m_DoDumpReceivedTelegrams = m_Config->getBoolean(getName(), QStringLiteral("DumpReceivedTelegrams"), false); + m_DoDumpSentTelegrams = m_Config->getBoolean(getName(), QStringLiteral("DumpSentTelegrams"), false); + m_DoUseSDSTL = m_Config->getBoolean(getName(), QStringLiteral("UseSDS_TL"), false); + + const QString trafficControl(QStringLiteral("TrafficControl")); + m_SendQueueHighLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendQueueHighLoad"), 1000); + m_SendQueueFullLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendQueueFullLoad"), 2000); + m_SendTelegramsNormalLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsNormalLoad"), 100); + m_SendTelegramsHighLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsHighLoad"), 50); + m_SendTelegramsFullLoad = m_Config->getInteger(trafficControl, QStringLiteral("SendTelegramsFullLoad"), 10); + m_SendLoad = E_TrafficLoad::Unknown; + + if (!m_DoCleanDb) + m_BroadcastManager.restoreAfterCrash(); + + emit initDone(); + + return 0; +} + + + + + +int32_t PrtCnvRadioThread::start() +{ + INFO_LOG(m_logger) << "Start"; + PrtCnvSocketThread::start(); + connectSocket(); + return 0; +} + + + + + + +void PrtCnvRadioThread::connected() +{ + INFO_LOG(m_logger) << "Radio-Socket connected m_Socket=" << m_Socket; + m_ReceiveCounter = END_COUNTER - 1; + m_SendCounter = END_COUNTER; + m_SentTelegrams = 0; + m_SentBytes = 0; + m_ReceivedTelegrams = 0; + m_ReceivedBytes = 0; + m_TickCounter = 0; + for (int i = 0; i < AVERAGE_COUNT; i++) + { + m_SentBytesAverage[i] = 0; + m_ReceivedBytesAverage[i] = 0; + } + m_AverageIndex = 0; + doRegister(); + startTickTimer(); + m_ConnectionTimer->stop(); + m_State = PrtCnvSocketThread::e_REGISTERING; +} + + + + + + +void PrtCnvRadioThread::prepareCleanUp() +{ + m_DoCleanup = true; +} + + + + + +void PrtCnvRadioThread::doStop() +{ + m_DoCleanup = true; + if (m_EnvironmentTelegramTimer) + m_EnvironmentTelegramTimer->stop(); + m_TickTimer->stop(); + disconnectSocket(); +} + + + + +void PrtCnvRadioThread::onBroadcastTelegramsRequestFromCentral(int equipmentNumber, int broadcastIndex, int resetCounter) +{ + m_BroadcastManager.handleNachforderungBroadcastTelegram(equipmentNumber, broadcastIndex, resetCounter); +} + + + + +void PrtCnvRadioThread::doClean() +{ + INFO_LOG(m_logger) << "doClean"; + m_BroadcastManager.cleanAndInit(true); + m_DbThread->setResetCounter(m_DbThread->getResetCounter() + 1); + emit cleant(); +} + + + + + +void PrtCnvRadioThread::doStart() +{ + m_DoCleanup = false; + connectSocket(); + if (m_EnvironmentTelegramTimer && m_EnvironmentTelegramTimer->interval() > 0) + m_EnvironmentTelegramTimer->start(); +} + + + + + +void PrtCnvRadioThread::disconnected() +{ + INFO_LOG(m_logger) << "Radio-Socket disconnected m_Socket=" << m_Socket; + + + if (e_WORKING == m_State || e_REGISTERING == m_State) + { + m_Socket->disconnectFromHost(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + } + m_State = e_DISCONNECTING; + if (m_DoCleanup) + { + m_ConnectionTimer->stop(); + emit stopped(); + } + else + connectSocket(); + + emit tetraConnectionState(false); +} + + + + + +void PrtCnvRadioThread::readyRead() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + + while (true) + { + if (m_DoCleanup) + break; + + + qint64 bytesRead = m_Socket->peek(reinterpret_cast(&header), sizeof(header)); + + + if (0 == bytesRead) + break; + + + if (sizeof(header) != bytesRead) + break; + + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Reconnect because radio-Telegram does not begin with magic-number 0xA5: I got 0x" + << QString::number(header.m_MagicNumber, 16); + disconnectSocket(); + break; + } + + + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + WARNING_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length + << ", but I proceed with this telegram."; + + + uint16_t dataSize = header.m_Length + sizeof(header); + if (m_Socket->bytesAvailable() < dataSize) + { + INFO_LOG(m_logger) << "not enough bytes available - waiting for more data"; + break; + } + QByteArray buf(dataSize, Qt::Uninitialized); + + bytesRead = 0; + while (bytesRead < dataSize) + { + qint64 br = m_Socket->read(&buf.data()[bytesRead], dataSize - bytesRead); + bytesRead += br; + } + + if (!checkAndUpdateReceiveCounter(header.m_Counter, END_COUNTER, START_COUNTER)) + { + + m_LogThread->writeRadioTelegramLog(buf, true, 1); + ERROR_LOG(m_logger) << "Reconnect because frame-counter of received radio-telegram was wrong"; + disconnectSocket(); + break; + } + + + + handleReceivedTelegram(buf); + + + m_ReceivedTelegrams++; + m_ReceivedBytes += dataSize; + } +} + + + + + + + +void PrtCnvRadioThread::handleReceivedTelegram(const QByteArray &data) +{ + if (m_DoDumpReceivedTelegrams) + { + INFO_LOG(m_logger) << "Received radio-telegram:"; + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, data); + } + + switch (data.at(4)) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp: + handleRegisterRsp(data.at(5)); + m_State = e_WORKING; + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data, true); + emit checkSendToCentral(); + return; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq: + handleReportIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_StatusIndReq: + handleStatusIndReq(data); + break; + + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq: + handleAirInterfaceLoadReq(data); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirLoadHyterra: + break; + + default: + ERROR_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << data.at(4) + << " not implemented!"; + break; + } + m_LogThread->writeRadioTelegramLog(data, true, 1); +} + + + + + +void PrtCnvRadioThread::handleDataIndReq(const QByteArray &data, bool bIsMaybeScrambled) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(data); + const uint32_t dstISSI = radioTelegram.getDestISSI(); + + if (m_bUseScrambling && bIsMaybeScrambled && m_EmergencyCallISSI != dstISSI) + { + if (!unscrambleContent(radioTelegram)) + return; + } + + + m_LogThread->writeRadioTelegramLog(radioTelegram.data(), true, 1); + + + if (radioTelegram.isNormalTelegram() && radioTelegram.getTelID() == GEF_ESW_MELDUNG) + return; + + if (m_HostISSI == dstISSI || m_ListenGroups.find(dstISSI) != m_ListenGroups.end()) + { + if (!m_radioTrafficThread) + m_radioTrafficThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_RadioTraffic)); + if (m_radioTrafficThread) + m_radioTrafficThread->newTelegramArrived(radioTelegram.getPayloadSize()); + + + PrtCnvMember *member = m_DbThread->getMemberByISSI(radioTelegram.getSrcISSI()); + if (radioTelegram.isLoginTelegram() || (member != nullptr)) + { + switch (radioTelegram.getFragmentStatus()) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment: + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment: + + if (member->m_Licensed) + handleFragmentedTelegram(radioTelegram); + else + { + + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, + N_CoPrtCnv::E_LicensingKind::Unlicense, + N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment == radioTelegram.getFragmentStatus() ? + radioTelegram.getTelID() : GEF_BESTAETIGUNG); + WARNING_LOG(m_logger) << "TNE with id=" << member->m_Id + << " tries to send a fragmented telegramm without beeing licensed"; + } + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_NotFragmented: + if (radioTelegram.isLoginTelegram()) + handleLoginTelegram(radioTelegram); + else if (radioTelegram.isNormalTelegram()) + { + if (radioTelegram.isCrcOk()) + { + radioTelegram.fixupTelegramIdForEts(false); + + gef_telegramm_id_et telId = radioTelegram.getTelID(); + + bool bIsBite = (GEF_BITE_MELDUNG2 == telId); + + if (member->m_Licensed || bIsBite) + { + + if (radioTelegram.isContentValid()) + { + + if (m_BroadcastManager.handleRadioTelegram(radioTelegram)) + { + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + + + + if (sendAnswer(radioTelegram)) + { + + + m_DbThread->storeCentralTelegram(centralTelegram, radioTelegram); + } + } + } + } + else + { + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::InvalidByteCount, + telId); + ERROR_LOG(m_logger) << "The content of received telegram is wrong => thrown away"; + } + } + else + { + + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, + N_CoPrtCnv::E_LicensingKind::Unlicense, + N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + telId); + WARNING_LOG(m_logger) << "TNE with id=" << member->m_Id + << " tries to send a telegramm without beeing licensed"; + } + } + else + { + ERROR_LOG(m_logger) << "CRC of received telegram is wrong => thrown away"; + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::WrongCrc, + radioTelegram.getTelID()); + } + } + else + { + ERROR_LOG(m_logger) << "Unknown non-fragmented telegram-type: 0x" + << QString::number(radioTelegram.getFragmentCounter(), 16); + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + radioTelegram.getTelID()); + } + break; + default: + ERROR_LOG(m_logger) << "Unknown payload-status: " << radioTelegram.getFragmentStatus(); + sendFehlermeldungGefechtsfeldToCentral(radioTelegram.getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + radioTelegram.getTelID()); + break; + } + } + else + { + ERROR_LOG(m_logger) << "The TPU with id=" << radioTelegram.getIdentity() + << " and ISSI=" << radioTelegram.getSrcISSI() + << " has sent a telegram without be logged in"; + + bool hasId = !(radioTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_MiddleFragment || radioTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment); + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, hasId ? radioTelegram.getIdentity() : 0, radioTelegram.getSrcISSI()); + } + } + else + { + if (m_EmergencyCallISSI == dstISSI) + { + + + uint32_t arr[10]; + + for (int i = 0; i < 10; ++i) + arr[i] = static_cast(radioTelegram.getPayloadDataUInt8(i - 1)); + for (int i = 0; i < 10; ++i) + DEBUG_LOG(m_logger) << "arr[" << i << "] = 0x" << QString::number(arr[i], 16); + + uint32_t x, y; + x = (arr[0] << 24) + (arr[1] << 16) + (arr[2] << 8) + arr[3]; + x = (x >> 3) & 0x1FFFFFF; + y = (arr[3] << 24) + (arr[4] << 16) + (arr[5] << 8) + arr[6]; + y = (y >> 3) & 0xFFFFFF; + + TrainingAreaBase::TetraIcd::EmergencyCall data; + double longitude = x * (360 / pow(2, 25)); + double latitude = y * (180 / pow(2, 24)); + data.absPosition.lon = longitude * (M_PI / 180.0); + data.absPosition.lat = latitude * (M_PI / 180.0); + data.issi = radioTelegram.getSrcISSI(); + data.timeStamp = QDateTime::currentMSecsSinceEpoch(); + auto tele(std::make_shared(data)); + + DEBUG_LOG(m_logger) << "Notruf lon: " << data.absPosition.lon << ", lat: " << data.absPosition.lat << ", issi: " << data.issi; + + m_DbThread->storeCentralTelegram(tele, radioTelegram); + } + else + { + ERROR_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << QString::number(data.at(4)) + << " and telId=" << radioTelegram.getTelID() + << " is for another host: " << radioTelegram.getDestISSI() + << " (we are " << m_HostISSI << ")"; + + } + } +} + + + + + +void PrtCnvRadioThread::handleLoginTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram) +{ + using namespace N_CoPrtCnv; + + uint16_t identity = a_loginTelegram.getIdentity(); + uint32_t issi = a_loginTelegram.getSrcISSI(); + + if (CoPrtCnvRadioTelegram::e_LoginRequest != (a_loginTelegram.getPayloadDataUInt8(2) & CoPrtCnvRadioTelegram::e_LoginStatusMask)) + { + ERROR_LOG(m_logger) << QStringLiteral("Unexpected login-status: 0x%1").arg(a_loginTelegram.getPayloadDataUInt8(2), 2, 16, QLatin1Char('0')); + return; + } + + + if (0 == identity || m_BroadcastISSI == issi) + { + sendLoginResponse(CoPrtCnvRadioTelegram::e_LoginReject, identity, issi); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorLoginEquipmentNumber); + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: New TPU with Id=%1 and ISSI=%2 tries to use broadcast-id or -issi => rejected").arg(identity).arg(issi)); + return; + } + + const bool bIsMasteringFlag = (a_loginTelegram.getPayloadDataUInt8(2) & CoPrtCnvRadioTelegram::e_LoginMastering) == CoPrtCnvRadioTelegram::e_LoginMastering; + PrtCnvMember *member = m_DbThread->getMemberById(identity); + PrtCnvMember *issiMember = m_DbThread->getMemberByISSI(issi); + DEBUG_LOG(m_logger) << "TPU with id=" << identity << " and ISSI=" + << issi << " tries to log in, mastering: " << bIsMasteringFlag; + + if (bIsMasteringFlag && member != issiMember) + { + removeMasteringMember(a_loginTelegram, member, issiMember, identity, issi); + member = nullptr; + issiMember = nullptr; + } + + const int tpuExId = exerciseIdForIdentity(identity); + TRACE_LOG(m_logger) << "Exercise Id for EqId " << identity << " is: " << tpuExId; + + + if (member || issiMember) + { + + + if (member && (issi == uint32_t(member->m_ISSI))) + { + + + + if (member->m_Licensed) + m_DbThread->licenseMember(member, false); + m_DbThread->updateExerciseIdForMember(member, m_ExerciseId); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + } + else + { + if (bIsMasteringFlag) + { + + m_DbThread->addMember(identity, issi); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::InfoLoginMasteringFlag); + } + else + { + + + int rejectCause = 0; + if (issiMember) + rejectCause |= CoPrtCnvRadioTelegram::e_LoginOtherISSI; + else if (member) + rejectCause |= CoPrtCnvRadioTelegram::e_LoginOtherEqId; + else + rejectCause |= CoPrtCnvRadioTelegram::e_LoginMastering; + rejectCause |= CoPrtCnvRadioTelegram::e_LoginReject; + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(rejectCause), + identity, issi); + sendFehlermeldungGefechtsfeldToCentral(identity, TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorLoginEquipmentNumber); + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: Another TPU with Id=%1 and ISSI=%2 without mastering tried to log in => rejected").arg(identity).arg(issi)); + } + } + } + else + { + + + m_DbThread->addMember(identity, issi); + m_DbThread->updateExerciseIdForMember(issiMember, m_ExerciseId); + + sendLoginAccept(identity, issi, tpuExId, bIsMasteringFlag); + } +} + + + + + +void PrtCnvRadioThread::handleFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_fragmentedTelegram) +{ + PrtCnvMember *member = m_DbThread->getMemberByISSI(a_fragmentedTelegram.getSrcISSI()); + if (member) + { + if (a_fragmentedTelegram.isCrcOk()) + { + bool doAddFragment = true; + if (a_fragmentedTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_FirstFragment) + { + + + if (!member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Did not get the last radio-telegram-fragment"; + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + member->clearFragmentedList(); + } + } + else if (a_fragmentedTelegram.getFragmentStatus() == N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment) + { + + + if (member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Got a lonely last radio-telegram-fragment"; + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + } + else + { + + member->addFragmentedTelegram(a_fragmentedTelegram); + const QByteArray unfragmentedRadioTelegramData = member->getUnfragmentedTelegramData(); + if (!unfragmentedRadioTelegramData.isEmpty()) + { + + + handleDataIndReq(unfragmentedRadioTelegramData, false); + } + else + sendFehlermeldungGefechtsfeldToCentral(member->m_Id, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + member->getFragmentedTelegramId()); + } + member->clearFragmentedList(); + doAddFragment = false; + } + else + { + + + if (member->isFragmentedListEmpty()) + { + ERROR_LOG(m_logger) << "Did not get the first radio-telegram-fragment"; + + member->clearFragmentedList(); + doAddFragment = false; + } + } + + + if (doAddFragment) + { + member->addFragmentedTelegram(a_fragmentedTelegram); + } + } + else + ERROR_LOG(m_logger) << "CRC of received fragmented telegram is wrong => thorw away"; + } + else + ERROR_LOG(m_logger) << "Internal error: Did not found the TNE with ISSI=" << a_fragmentedTelegram.getSrcISSI() << " in member-list"; +} + + + + + +bool PrtCnvRadioThread::handleBITEEXT_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram) +{ + auto anmeldeart = static_cast(a_BITE_RadioTelegram.getPayloadDataUInt32(7, 1)); + uint32_t ergebnisCAN = a_BITE_RadioTelegram.getPayloadDataUInt32(8, 3); + uint32_t ergebnisAusstattung = a_BITE_RadioTelegram.getPayloadDataUInt8(11); + uint32_t konfigurationsvergleich = a_BITE_RadioTelegram.getPayloadDataUInt8(23); + uint32_t aktuelleKonfiguration = a_BITE_RadioTelegram.getPayloadDataUInt32(24, 3); + + QList fehlerListe; + const auto nonDynamic = getBiteError(a_BITE_RadioTelegram, 12); + if (nonDynamic.errorNumber != 0 || + nonDynamic.canDeviceNumber != 0 || + nonDynamic.subdeviceNumber != 0 || + nonDynamic.uniqueId != 0) + fehlerListe.append(nonDynamic); + + const uint8_t fehlerLen = a_BITE_RadioTelegram.getPayloadDataUInt8(19); + for (uint8_t i = 0; i < fehlerLen; ++i) + { + const uint8_t iPos = 27 + i * 7; + fehlerListe.append(getBiteError(a_BITE_RadioTelegram, iPos)); + } + + return handleBITE_Telegram(a_BITE_RadioTelegram, + anmeldeart, + ergebnisCAN, + ergebnisAusstattung, + aktuelleKonfiguration, + konfigurationsvergleich, + fehlerListe + ); +} + +bool PrtCnvRadioThread::handleBITE_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram, + TrainingAreaBase::TetraIcd::BiteReport::LoginType anmeldeart, + uint32_t ergebnisCAN, + uint32_t ergebnisAusstattung, + uint32_t aktuelleKonfiguration, + uint32_t konfigurationsvergleich, + const QList &fehlerListe + ) +{ + switch (anmeldeart) + { + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::InvalidLogin: + return true; + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::NoLogin: + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin: + case TrainingAreaBase::TetraIcd::BiteReport::LoginType::Relogin: + { + const uint16_t identity = a_BITE_RadioTelegram.getIdentity(); + bool doForwardBiteMeldung = true; + QString logText(QStringLiteral("Licensing: The TPU with Id=%1 and ISSI=%2").arg(identity).arg(a_BITE_RadioTelegram.getSrcISSI())); + + + PrtCnvMember *member = m_DbThread->getMemberById(identity); + if (member) + { + + + if (a_BITE_RadioTelegram.getSrcISSI() == uint32_t(member->m_ISSI)) + { + + + if (isIdentityValid(identity)) + { + m_DbThread->updateExerciseIdForMember(member, m_ExerciseId); + + if (!member->m_Licensed) + { + m_DbThread->licenseMember(member); + if (TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin == anmeldeart) + logText += QStringLiteral(" is now licensed"); + else + logText += QStringLiteral(" is now licensed (WIEDER_ANMELDUNG instead NEUE_ANMELDUNG used!)"); + } + else + { + if (TrainingAreaBase::TetraIcd::BiteReport::LoginType::NewLogin == anmeldeart) + logText += QStringLiteral(" is now relicensed (NEUE_ANMELDUNG instead WIEDER_ANMELDUNG used!)"); + else + logText += QStringLiteral(" is now relicensed"); + } + + N_CoPrtCnv::E_LicensingErrorCode errorCode = N_CoPrtCnv::E_LicensingErrorCode::Ok; + + if (ergebnisAusstattung != 1) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Battery; + logText += QStringLiteral(", has battery-Warning"); + } + if ((ergebnisCAN & aktuelleKonfiguration) != aktuelleKonfiguration) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Selftest; + logText += QStringLiteral(", but selftest is failed"); + } + if (konfigurationsvergleich != 0) + { + + errorCode = N_CoPrtCnv::E_LicensingErrorCode::Configuration; + logText += QStringLiteral(", but has configuration-failure: "); + } + bool selftestOrConfigError = (errorCode == N_CoPrtCnv::E_LicensingErrorCode::Configuration || errorCode == N_CoPrtCnv::E_LicensingErrorCode::Selftest); + bool doLicense = !(selftestOrConfigError && !m_DoLicenseDespiteSelftestOrConfigFailure); + + prepareWareHouseMessage(identity, doLicense, ergebnisCAN, ergebnisAusstattung, aktuelleKonfiguration, konfigurationsvergleich, fehlerListe); + if (anmeldeart == TrainingAreaBase::TetraIcd::BiteReport::LoginType::NoLogin) + return true; + + + sendLizenzierungTneToRadio(identity, member->m_ISSI, + doLicense ? N_CoPrtCnv::E_LicensingKind::Success : N_CoPrtCnv::E_LicensingKind::Rejected, + errorCode); + + + if (doLicense) + m_DoNeedActPosResp.insert(identity); + if (selftestOrConfigError) + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorConfigSelfTest, + a_BITE_RadioTelegram.getTelID()); + + + + if (selftestOrConfigError && !m_DoLicenseDespiteSelftestOrConfigFailure) + { + logText = QStringLiteral("Licensing: The TPU with Id=%1 and ISSI=%2").arg(identity).arg(a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" could not be licensed, because "); + if (errorCode == N_CoPrtCnv::E_LicensingErrorCode::Configuration) + logText += QStringLiteral("of configuration-failure"); + else + logText += QStringLiteral("selftest failed"); + } + } + else + { + + sendLizenzierungTneToRadio(identity, member->m_ISSI, N_CoPrtCnv::E_LicensingKind::Rejected, N_CoPrtCnv::E_LicensingErrorCode::IdentityDenied); + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorSendingNamelist, + a_BITE_RadioTelegram.getTelID()); + logText += QStringLiteral(" could not be licensed because PlayerID is not allowed"); + } + } + else + { + + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, identity, a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" could not be licensed because ISSI is wrong"); + doForwardBiteMeldung = false; + } + } + else + { + + sendLoginResponse(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginReject, identity, a_BITE_RadioTelegram.getSrcISSI()); + logText += QStringLiteral(" wants to be licensed but is not logged in"); + doForwardBiteMeldung = false; + } + writeLoginLog(a_BITE_RadioTelegram, logText); + return doForwardBiteMeldung; + } + } + ERROR_LOG(m_logger) << "BITE-Meldung contains unknown anmeldeart: " << static_cast(anmeldeart); + return true; +} + + + + + +void PrtCnvRadioThread::checkSend() +{ + + if (m_DoCleanup) + return; + if (PrtCnvSocketThread::e_WORKING != m_State) + return; + + if (isSendLimitReached()) + return; + + PrtCnvStoredRadioTelegram *handle = nullptr; + const auto radioTelegram = m_DbThread->getNextRadioTelegram(handle); + if (radioTelegram) + { + + + if (radioTelegram->isNormalTelegram()) + { + switch (radioTelegram->getTelID()) + { + case GEF_UMGEBUNGS_MELDUNG2: + { + const int exerciseId = radioTelegram->getPayloadDataUInt32(5, 2); + if (m_ExerciseId != exerciseId) + { + ERROR_LOG(m_logger) << "Started with exercise Id " << m_ExerciseId << " but got environment telegram for exercise " << exerciseId; + exit(5); + } + + if (m_ExerciseId > 0 && !m_EnvironmentTelegramTimer) + { + m_EnvironmentTelegramTimer = new QTimer(this); + connect(m_EnvironmentTelegramTimer, &QTimer::timeout, this, &PrtCnvRadioThread::timeoutEnvironmentTelegram, Qt::QueuedConnection); + } + + if (m_EnvironmentTelegramTimer) + { + INFO_LOG(m_logger) << "I got the Umgebungsmeldung-Telegram => I start now sending Umgebungsmeldung periodically"; + m_EnvironmentTelegramTimer->setInterval(m_Config->getInteger(getName(), QStringLiteral("CyclicEnvironmentTime"), 30) * 1000); + m_EnvironmentTelegramTimer->start(); + } + + radioTelegram->setPayloadDataWithIndex(7, m_DbThread->getResetCounter(), 1); + break; + } + case GEF_WIRKFELD_STATUS_MINENSPERRE: + { + uint16_t wirkfeldKennung = radioTelegram->getPayloadDataUInt32(5, 2); + if (m_BroadcastManager.isEffectSimulationIdDeactivated(wirkfeldKennung)) + { + WARNING_LOG(m_logger) << "Special Handling for GEF_WIRKFELD_STATUS_MINENSPERRE with id " << wirkfeldKennung + << " -> do not send to CTA"; + m_DbThread->radioTelegramSent(m_SendCounter, handle, 0); + return; + } + break; + } + default: + + break; + } + } + + sendTelegram(radioTelegram, handle); + + emit checkSendToRadio(); + } +} + + + + + + +void PrtCnvRadioThread::timeoutTick() +{ + + + + + + if (m_DoCleanup) return; + startTickTimer(); + + checkSend(); + if (!isSendLimitReached()) + { + time_t currentTime = time(nullptr); + auto broadcastTelegram = m_BroadcastManager.getNextBroadcastTelegramToSend(0, currentTime); + while (broadcastTelegram) + { + uint16_t broadcastIndex = broadcastTelegram->getBroadcastIndex(); + sendTelegram(broadcastTelegram, nullptr, false); + + if (isSendLimitReached()) + broadcastTelegram = nullptr; + else + broadcastTelegram = m_BroadcastManager.getNextBroadcastTelegramToSend(broadcastIndex, currentTime); + } + } + else + INFO_LOG(m_logger) << "send limit reached"; + + m_BroadcastManager.incTickAndSetTrafficLoad(E_TrafficLoad::HighLoad == m_SendLoad, E_TrafficLoad::FullLoad == m_SendLoad); + if (!isSendLimitReached()) + { + auto radioTelegram = m_BroadcastManager.getNextNachforderungTelegramToSend(); + if (radioTelegram) + sendTelegram(radioTelegram, nullptr, false); + } + + + try + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *radioInjectTelegram; + while ((radioInjectTelegram = m_InjectionThread->getNextRadioInjectionTelegram())) + { + if (radioInjectTelegram->telegramId() == TrainingAreaBase::TetraIcd::TelegramId::NACHFORDERUNG_BROADCAST_TELEGRAMME) + { + const auto tele = TrainingAreaBase::TetraIcd::RequestBroadcastTelegrams::fromJson(radioInjectTelegram->jsonData()); + onBroadcastTelegramsRequestFromCentral(tele.header.equipmentNumber, tele.broadcastIndex, tele.resetCounter); + delete radioInjectTelegram; + continue; + } + std::shared_ptr + radioTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(radioInjectTelegram)); + if (radioTelegram) + sendTelegram(radioTelegram, nullptr, false); + delete radioInjectTelegram; + } + } + catch (std::exception &e) + { + ERROR_LOG(m_logger) << "Catched an unexpected exception: " << e.what() << " => could not inject radio-telegram, but we proceed..."; + } + + + if (m_DbThread->isEnvironmentResetCounterOld()) + timeoutEnvironmentTelegram(); + computeAndLogTrafficStatistics(); +} + + + + + +void PrtCnvRadioThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "timeoutAliveAndConnection socketState=" << m_Socket->state() << " m_State=" << m_State; + switch (m_State) + { + case e_CONNECTING: + connectSocket(); + break; + case e_REGISTERING: + case e_WORKING: + break; + case e_DISCONNECTING: + m_Socket->abort(); + break; + default: + ERROR_LOG(m_logger) << "timeoutAlive for m_State=" << m_State << " not implemented"; + } +} + + + + + + + + + + + +void PrtCnvRadioThread::sendTelegram(const std::shared_ptr &a_telegram, + PrtCnvStoredRadioTelegram *a_handle, + const bool a_doCheckWhetherExpired) +{ + uint16_t broadcastIndex = 0; + + bool isSpecialTelegram = !a_telegram->isNormalTelegram(); + bool isLicensing = false; + PrtCnvMember *member = nullptr; + if (!isSpecialTelegram) + { + member = m_DbThread->getMemberById(a_telegram->getIdentity()); + isLicensing = (GEF_LIZENSIERUNG_TNE == a_telegram->getTelID()); + } + + if (member || isSpecialTelegram || isLicensing) + { + + if (!a_telegram->needsLicensing() || (member && member->m_Licensed)) + { + if (!a_telegram->hasExpired() || !a_doCheckWhetherExpired) + { + if (a_telegram->isContentValid()) + { + + if (a_telegram->mustBeFragmented()) + sendFragmentedTelegram(a_telegram); + else + broadcastIndex = sendToSocket(a_telegram); + + m_LogThread->writeRadioTelegramLog(a_telegram->data(), false, a_telegram->getPriority()); + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::WrongParameter, + a_telegram->getTelID()); + INFO_LOG(m_logger) << "Telegram with telId=" << a_telegram->getTelID() << " is invalid => thrown away"; + } + } + else + { + if (a_telegram->getBroadcastIndex() == 0) + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::TelegramOutdated, + a_telegram->getTelID()); + INFO_LOG(m_logger) << "Telegram with telId=" << a_telegram->getTelID() << " has expired => thrown away"; + } + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLicensed, + a_telegram->getTelID()); + ERROR_LOG(m_logger) << "Central tries to send a telegram with telId=" << a_telegram->getTelID() << " to TNE with id=" << a_telegram->getIdentity() << ", but the TNE is not licensed!"; + } + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorNotLoggedIn, + a_telegram->getTelID()); + ERROR_LOG(m_logger) << "Central tries to send a telegram to TNE with id=" << a_telegram->getIdentity() << ", but the TNE is not logged in!"; + + } + + if (a_handle) + m_DbThread->radioTelegramSent(m_SendCounter, a_handle, broadcastIndex); + + if (broadcastIndex >= MAX_BROADCAST_INDEX) + { + m_BroadcastManager.handleOverrunOfBroadcastCounter(); + sendFehlermeldungGefechtsfeldToCentral(0, TrainingAreaBase::TetraIcd::CtaDataError::Reason::BroadcastCounterOverflow); + timeoutEnvironmentTelegram(); + } +} + + + + + +void PrtCnvRadioThread::doRegister() +{ + auto registerIndTelegram(std::make_shared(m_HostISSI)); + sendTelegram(registerIndTelegram, nullptr); + INFO_LOG(m_logger) << "Send Radio-Telegram Register-Ind with hostISSI=" << m_HostISSI; +} + + + + + +void PrtCnvRadioThread::registerGroups() +{ + if (m_ListenGroups.empty()) + return; + auto registerGroupIndTelegram(std::make_shared(m_HostISSI, m_ListenGroups)); + sendTelegram(registerGroupIndTelegram, nullptr); +} + + + + +void PrtCnvRadioThread::handleRegisterRsp(const uint8_t a_regsitrationStatus) +{ + INFO_LOG(m_logger) << "Got Radio-Telegram Register-Rsp with status=" << std::to_string(a_regsitrationStatus); + std::stringstream logText; + switch (a_regsitrationStatus) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered: + emit tetraConnectionState(true); + registerGroups(); + return; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DuplicateISSI: + logText << "TETRA: Register-Response: Status=Duplicate ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidISSI: + logText << "TETRA: Register-Response: Status=Invalid ISSI"; + break; + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_InvalidIpAddress: + logText << "TETRA: Register-Response: Status=Invalid IP address => Configure TETRA for accepting our IP-address ("; + { + const QList ipList = QNetworkInterface::allAddresses(); + for (const QHostAddress &addr : ipList) + logText << addr.toString().toStdString() << ", "; + logText << ")..."; + } + break; + default: + logText << "Unknown registration status: " << std::to_string(a_regsitrationStatus); + break; + } + emit tetraConnectionState(false); + + FATAL_LOG(m_logger) << logText.str(); + std::cerr << logText.str() << std::endl; + exit(1); +} + +std::ostream &operator<<(std::ostream &os, const PrtCnvRadioThread::E_TrafficLoad tl) +{ + switch (tl) + { + case PrtCnvRadioThread::E_TrafficLoad::FullLoad: + os << "E_TrafficLoad::FullLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::HighLoad: + os << "E_TrafficLoad::HighLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::NormalLoad: + os << "E_TrafficLoad::NormalLoad"; + return os; + case PrtCnvRadioThread::E_TrafficLoad::Unknown: + os << "E_TrafficLoad::Unknown"; + return os; + } + Q_ASSERT(false); + os << std::to_string(static_cast(tl)); + return os; +} + + + + + + + + +bool PrtCnvRadioThread::sendAnswer(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram) +{ + switch (a_radioTelegram.getTelID()) + { + case GEF_BITE_MELDUNG2: + return handleBITEEXT_Telegram(a_radioTelegram); + case GEF_DEAKTIVIERUNG_EINZELMINE: + { + + + auto radioTelegram(std::make_shared(GEF_DEAKTIVIERUNG_EINZELMINE, 13, 0)); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayloadData(a_radioTelegram.getPayloadDataPtr(5), 8); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + break; + } + case GEF_POSITIONS_MELDUNG: + case GEF_POSITIONS_MELDUNG_LFZ: + case GEF_POSITIONS_MELDUNG_MIT_TEILNEHMER: + case GEF_IPS_POSITIONSDATEN: + { + auto it = m_DoNeedActPosResp.find(a_radioTelegram.getIdentity()); + if (it != m_DoNeedActPosResp.end()) + { + auto radioTelegram(std::make_shared(GEF_ALLGEMEINE_NACHRICHT, 9, a_radioTelegram.getIdentity())); + radioTelegram->setPayload2Byte(0); + radioTelegram->setPayload1Byte(3); + radioTelegram->setPayload1Byte(0); + radioTelegram->setPayload2Byte(8); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + m_DoNeedActPosResp.erase(it); + } + break; + } + default: + + break; + } + return true; +} + + + + + +uint32_t PrtCnvRadioThread::getDestinationISSI(const uint16_t a_TNE_Id) const +{ + + PrtCnvMember *member = m_DbThread->getMemberById(a_TNE_Id); + if (member) + return member->m_ISSI; + ERROR_LOG(m_logger) << "TPU with id=" << a_TNE_Id << " not logged in."; + return 0; +} + + + + + +void PrtCnvRadioThread::timeoutEnvironmentTelegram() +{ + + if (m_DoCleanup) return; + if (PrtCnvSocketThread::e_WORKING != m_State) return; + + auto envTelegram = m_DbThread->getEnvironmentTelegram(); + if (envTelegram) + { + INFO_LOG(m_logger) << "It is time to send the Umgebungsmeldung"; + sendTelegram(envTelegram, nullptr); + } + else + { + WARNING_LOG(m_logger) << "Got no Umgebungsmeldung from DB-Thread..."; + } +} + + + + + +void PrtCnvRadioThread::sendFehlermeldungGefechtsfeldToCentral(const uint16_t a_identity, + const TrainingAreaBase::TetraIcd::CtaDataError::Reason a_errorCause, + const gef_telegramm_id_et a_telegramId) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram radioTelegram(GEF_FEHLERMELDUNG_GFD, 9, a_identity); + radioTelegram.setPayload4Byte(time(nullptr)); + radioTelegram.setPayload1Byte(static_cast(a_errorCause)); + radioTelegram.setPayload1Byte(a_telegramId); + + std::shared_ptr + centralTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(&radioTelegram)); + if (centralTelegram) + { + m_DbThread->storeCentralTelegram(centralTelegram, radioTelegram); + emit checkSendToCentral(); + } +} + + + + + +void PrtCnvRadioThread::writeLoginLog(uint32_t identity, uint32_t issi, const QString &a_prosaText) +{ + const QDateTime dtCur(QDateTime::currentDateTimeUtc()); + QString txt = + QString::number(dtCur.toSecsSinceEpoch()) + QLatin1Char(';') + + QString::number(issi) + QLatin1Char(';') + + QString::number(identity) + QLatin1Char(';') + + QLatin1Char(';') + + a_prosaText + QLatin1Char(';') + dtCur.toString(); + writeLoginLog(nullptr, txt); +} + +void PrtCnvRadioThread::writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, const QString &a_prosaText) +{ + writeLoginLog(&a_radioTelegram, a_prosaText); +} + +void PrtCnvRadioThread::writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const QString &a_prosaText) +{ + QByteArray logData; + if (a_radioTelegram) + { + + int len = 3; + if (a_radioTelegram->getTelID() == GEF_BITE_MELDUNG2) + len = 27; + QStringList sl; + sl.reserve(len); + for (int i = 0; i < len; i++) + { + uint8_t data = a_radioTelegram->getPayloadDataUInt8(i); + sl += QStringLiteral("0x%1").arg(data, 2, 16, QLatin1Char('0')); + } + + const QDateTime dtCur(QDateTime::currentDateTimeUtc()); + + logData = + QByteArray::number(dtCur.toSecsSinceEpoch()) + ";" + + QByteArray::number(a_radioTelegram->getSrcISSI()) + ";" + + QByteArray::number(a_radioTelegram->getIdentity()) + ";" + + sl.join(QLatin1Char(',')).toUtf8() + ";" + + a_prosaText.toUtf8() + ";" + dtCur.toString().toUtf8(); + } + else + { + logData = a_prosaText.toUtf8(); + } + logData += "\n"; + + INFO_LOG(m_logger) << logData; + + + QString date = QDate::currentDate().toString(QLatin1String("yyyyMMdd")); + QString fileName = m_LoginPathWithPrefix + date + QLatin1Char('_') + QString::number(m_ExerciseId) + QLatin1String(".log"); + + + QFile file(fileName); + file.open(QIODevice::Append); + file.write(logData); + file.close(); +} + + + + + +void PrtCnvRadioThread::sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI) +{ + auto answerTelegram(std::make_shared(a_loginTelegramStatus, a_identity, a_ISSI)); + storeRadioTelegram(answerTelegram, 0); + emit checkSendToRadio(); +} + +void PrtCnvRadioThread::sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI, const TrainingAreaBase::TetraIcd::GroupIssiInformation &group) +{ + using namespace N_CoPrtCnv; + + auto answerTelegram(std::make_shared(a_loginTelegramStatus, a_identity, a_ISSI)); + if ((a_loginTelegramStatus & CoPrtCnvRadioTelegram::e_LoginOtherExercise) == CoPrtCnvRadioTelegram::e_LoginOtherExercise) + { + NOTICE_LOG(m_logger) << "sendLoginResponse for " << a_identity << " with issi " << a_ISSI + << " and groups " << group.serverIssi << "/" << group.broadcastIssi1 + << "/" << group.broadcastIssi2; + answerTelegram->setLoginIssis(group.serverIssi, group.broadcastIssi1, group.broadcastIssi2); + } + storeRadioTelegram(answerTelegram, 0); + emit checkSendToRadio(); +} + + + + + + + +void PrtCnvRadioThread::sendLizenzierungTneToRadio(const uint16_t a_identity, const uint32_t a_issi, + const N_CoPrtCnv::E_LicensingKind a_licensingKind, + const N_CoPrtCnv::E_LicensingErrorCode a_errorCause) +{ + auto radioTelegram(std::make_shared(GEF_LIZENSIERUNG_TNE, 7, a_identity)); + radioTelegram->setPayload1Byte(static_cast(a_licensingKind)); + radioTelegram->setPayload1Byte(static_cast(a_errorCause)); + radioTelegram->setPayload2Byte(0x0013); + radioTelegram->setDestISSI(a_issi); + storeRadioTelegram(radioTelegram, 0); + emit checkSendToRadio(); + emit playerLicencedChanged(a_identity, a_licensingKind); +} + + + + + + +void PrtCnvRadioThread::initIdentityArray() +{ + const QString loginGroup(QStringLiteral("login")); + + if (m_Config->getBoolean(loginGroup, QStringLiteral("DoCheckPlayerId"), true)) + { + + m_AllowedIdentities.clear(); + + QString identifyFileName = m_Config->getString(loginGroup, QStringLiteral("PlayerIdFilePath"), QString()); + if (identifyFileName.isEmpty()) + { + + uint32_t lowest = m_Config->getInteger(loginGroup, QStringLiteral("LowestPlayerId"), 1); + uint32_t highest = m_Config->getInteger(loginGroup, QStringLiteral("HighestPlayerId"), MAX_IDENTITY); + for (uint32_t i = lowest; i <= highest; i++) + setIdentityVaild(i); + INFO_LOG(m_logger) << "PlayerIds from " << lowest << " .. " << highest << " will be used."; + } + else + { + + INFO_LOG(m_logger) << "PlayerId-file '" << identifyFileName << "' will be used."; + + + QString path = identifyFileName; + if (!QDir::isAbsolutePath(path)) + path = QCoreApplication::applicationDirPath() + QLatin1Char('/') + path; + + + QFile file(path); + if (file.open(QIODevice::ReadOnly)) + { + uint32_t lineCount = 0; + while (!file.atEnd()) + { + lineCount++; + QByteArray line(file.readLine()); + int hashPos = line.indexOf('#'); + if (-1 != hashPos) + line = line.left(hashPos); + if (!line.trimmed().isEmpty()) + { + int pos = line.indexOf('-'); + if (-1 == pos) + { + + setIdentityVaild(readIdentity(line, lineCount, identifyFileName)); + } + else + { + + QByteArray playerId = line.left(pos).trimmed(); + uint16_t left = readIdentity(playerId, lineCount, identifyFileName); + playerId = line.right(line.length() - pos - 1).trimmed(); + uint16_t right = readIdentity(playerId, lineCount, identifyFileName); + for (int i = left; i <= right; i++) + setIdentityVaild(i); + } + } + } + file.close(); + } + else + { + ERROR_LOG(m_logger) << "Could not open the PlayerId-file '" << identifyFileName << "'!"; + std::cout << std::endl << "Error: Could not open the PlayerId-file '" << qPrintable(identifyFileName) << "'!" << std::endl; + exit(-1); + } + } + } + else + { + + for (uint32_t i = 0; i <= MAX_IDENTITY; i++) + setIdentityVaild(i); + } +} + + + + + + +uint16_t PrtCnvRadioThread::readIdentity(const QByteArray &a_idAsText, const uint32_t a_line, const QString &a_fileName) +{ + ulong playerId = a_idAsText.toULong(); + if (0 == playerId || playerId > MAX_IDENTITY) + { + + if (0 == playerId) + { + FATAL_LOG(m_logger) << a_fileName << ":" << a_line << ": could not read playerID - '" + << a_idAsText << "'"; + } + else + { + FATAL_LOG(m_logger) << a_fileName << ":" << a_line << ": PlayerID too big - '" + << a_idAsText << "'"; + } + exit(1); + } + return playerId; +} + + + + + +bool PrtCnvRadioThread::isIdentityValid(uint16_t a_identity) const +{ + return m_AllowedIdentities.find(a_identity) != m_AllowedIdentities.end(); +} + + + + +void PrtCnvRadioThread::setIdentityVaild(uint16_t a_identity) +{ + m_AllowedIdentities.insert(a_identity); +} + + + + +void PrtCnvRadioThread::sendFragmentedTelegram(const std::shared_ptr &a_telegram) +{ + + uint8_t fragmentCounter = 0; + N_CoPrtCnv::CoPrtCnvRadioTelegram::E_FragmentStatus fragmentStatus; + do + { + bool error = false; + auto fragmentedTelegram(std::make_shared(a_telegram, fragmentCounter++, error)); + if (!error) + { + fragmentedTelegram->setDestISSI(getDestinationISSI(a_telegram->getIdentity())); + + sendTelegram(fragmentedTelegram, nullptr); + fragmentStatus = fragmentedTelegram->getFragmentStatus(); + } + else + { + sendFehlermeldungGefechtsfeldToCentral(a_telegram->getIdentity(), + TrainingAreaBase::TetraIcd::CtaDataError::Reason::FragmentationError, + a_telegram->getTelID()); + return; + } + } + while (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LastFragment != fragmentStatus); +} + + + + + + +uint16_t PrtCnvRadioThread::sendToSocket(const std::shared_ptr &a_telegram) +{ + + if (++m_SendCounter >= END_COUNTER) + m_SendCounter = START_COUNTER; + a_telegram->setZaehler(m_SendCounter); + + a_telegram->setSrcISSI(m_HostISSI); + uint16_t broadcastIndex = 0; + gef_telegramm_id_et telId = a_telegram->isNormalTelegram() ? a_telegram->getTelID() : GEF_BESTAETIGUNG; + if (a_telegram->isNormalTelegram()) + { + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq == a_telegram->getPDU_Type()) + { + if (GEF_LIZENSIERUNG_TNE != a_telegram->getTelID()) + a_telegram->setDestISSI(getDestinationISSI(a_telegram->getIdentity())); + } + if (GEF_TEILNEHMERMODE_SETZEN == telId && a_telegram->getDestISSI() != m_BroadcastISSI) + { + DEBUG_LOG(m_logger) << "Got MODE with bci: " << a_telegram->getBroadcastIndex(); + if (a_telegram->getBroadcastIndex()<= 0) + a_telegram->setBroadcastIndex(m_BroadcastManager.getBroadcastIndex()); + DEBUG_LOG(m_logger) << "MODE with bci is now: " << a_telegram->getBroadcastIndex(); + } + + if (GEF_UMGEBUNGS_MELDUNG2 == telId) + { + + a_telegram->setBroadcastIndex(m_BroadcastManager.getBroadcastIndex()); + a_telegram->setPayloadDataWithIndex(7, m_DbThread->getResetCounter(), 1); + a_telegram->setPayloadDataWithIndex(8, m_DbThread->getBattleFieldOperatingState(), 1); + a_telegram->setPayloadDataWithIndex(16, (uint32_t)time(nullptr), 4); + m_DbThread->setResetCounterOnEnvironment(); + } + else + { + + + if (GEF_INIT != telId && + a_telegram->mustBroadcastBeSet()) + { + broadcastIndex = m_BroadcastManager.getNextBroadcastIndex(); + a_telegram->setBroadcastIndex(broadcastIndex); + } + } + a_telegram->fixupTelegramIdForEts(true); + } + + + DEBUG_LOG(m_logger) << "Send telegram to radio: telId=" << telId << " wcounter=" << int(a_telegram->zaehler()) << " size=" << a_telegram->getSize(); + if (m_DoUseSDSTL && N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq == a_telegram->getPDU_Type()) + { + a_telegram->setProtocolIdentifier(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_SimpleTextMessagingUsingSDS_TL); + a_telegram->setMessageReference(telId); + } + + if (m_DoDumpSentTelegrams) + { + INFO_LOG(m_logger) << "Send radio-telegram with size " << a_telegram->getSize() + << " and payload size " << a_telegram->getPayloadSize(); + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Info, a_telegram->data()); + } + + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + + if (m_bUseScrambling && a_telegram->getPDU_Type() == N_CoPrtCnv::CoPrtCnvRadioTelegram::E_PDU_Type::e_DataIndReq) + sendScrambledContent(a_telegram); + else + m_Socket->write(a_telegram->data()); + + + m_SentTelegrams++; + m_SentBytes += a_telegram->getSize(); + + if (a_telegram->isNormalTelegram()) + a_telegram->fixupTelegramIdForEts(false); + return broadcastIndex; +} + + +static inline void scramble(const unsigned char *dataIn, unsigned char *dataOut, size_t len, uint32_t initial, uint32_t polynom) +{ + uint32_t lfsr = initial; + for (size_t j = 0; j < len; ++j) + { + for (int i = 0; i < 8; ++i) + { + unsigned char lsbBit = (lfsr & 0x01); + lfsr >>= 1; + if (lsbBit) + lfsr ^= polynom; + } + dataOut[len - j - 1] = dataIn[len - j - 1] ^ static_cast(lfsr); + } +} + + +void PrtCnvRadioThread::sendScrambledContent(const std::shared_ptr &a_telegram) const +{ + const uint32_t initial = (a_telegram->getSrcISSI() % 0xFFFF) + 1; + constexpr uint32_t polynom = 0x8016; + unsigned char dataOut[N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH]; + const uint32_t payloadOffset = N_CoPrtCnv::CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH - 1; + const uint32_t scrambleLen = a_telegram->getSize() - payloadOffset; + const unsigned char *dataIn = reinterpret_cast(a_telegram->getData() + payloadOffset); + + scramble(dataIn, dataOut, scrambleLen, initial, polynom); + + QByteArray tmp (reinterpret_cast(dataOut), scrambleLen); + + DEBUG_LOG(m_logger) << "Raw scrambled data: " << tmp.toHex(' '); + + m_Socket->write(a_telegram->getData(), payloadOffset); + m_Socket->write(reinterpret_cast(dataOut), scrambleLen); +} + + +bool PrtCnvRadioThread::unscrambleContent(N_CoPrtCnv::CoPrtCnvRadioTelegram &a_telegram) const +{ + const uint32_t initial = (a_telegram.getSrcISSI() % 0xFFFF) + 1; + constexpr uint32_t polynom = 0x8016; + const uint32_t payloadOffset = N_CoPrtCnv::CoPrtCnvRadioTelegram::DATA_IND_REQ_HEADER_LENGTH - 1; + const uint32_t scrambleLen = a_telegram.getSize() - payloadOffset; + unsigned char *dataIn = reinterpret_cast(a_telegram.getData() + payloadOffset); + unsigned char dataOut[N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH]; + + if (scrambleLen > N_CoPrtCnv::CoPrtCnvRadioTelegram::MAX_RADIO_TELEGRAM_PAYLOAD_LENGTH) + { + ERROR_LOG(m_logger) << "Telegram length does not match - can't unscramble content, len: " << scrambleLen; + NGL::NGLLoggerHelper::hexDumpHelper(m_logger, NGL::LogLevel::Error, a_telegram.data()); + Q_ASSERT(false); + return false; + } + + + + + scramble(dataIn, dataOut, scrambleLen, initial, polynom); + + memcpy(dataIn, dataOut, scrambleLen); + + + + + return true; +} + + + + + +void PrtCnvRadioThread::handleReportIndReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + + uint32_t srcISSI = *(uint32_t *)&a_data[5]; + uint32_t destISSI = *(uint32_t *)&a_data[9]; + if (m_HostISSI == destISSI) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report delivery = (N_CoPrtCnv::CoPrtCnvRadioTelegram::E_DeliveryStatusForTL_Report)a_data[16]; + switch (delivery) + { + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DeliveryFailed: + { + uint8_t messageReference = a_data[14]; + uint16_t identity = 0; + PrtCnvMember *member = m_DbThread->getMemberByISSI(srcISSI); + if (member) + identity = member->m_Id; + sendFehlermeldungGefechtsfeldToCentral(identity, + TrainingAreaBase::TetraIcd::CtaDataError::Reason::ErrorSendingToExerciseControl, + static_cast(messageReference)); + break; + } + default: + ERROR_LOG(m_logger) << "reaction to delivery " << (int)a_data[16] << " not implemented"; + break; + } + } + else + ERROR_LOG(m_logger) << "Radio-Ack-Telegram from " << srcISSI << " is for another host: " << destISSI << " (we are " << m_HostISSI << ")"; +} + +void PrtCnvRadioThread::prepareWareHouseMessage(qint32 equipNr, bool doLicence, qint64 ergebnisCAN, qint64 ergebnisAusstattung, qint64 aktuelleKonfiguration, qint64 konfigurationsvergleich, const QList &fehlerListe) +{ + QJsonObject obj; + obj.insert(QStringLiteral("equipNo"), equipNr); + obj.insert(QStringLiteral("doLicence"), doLicence); + obj.insert(QStringLiteral("biteState"), ergebnisCAN); + obj.insert(QStringLiteral("batteryState"), ergebnisAusstattung); + obj.insert(QStringLiteral("configState"), aktuelleKonfiguration); + obj.insert(QStringLiteral("configError"), konfigurationsvergleich); + QJsonArray errorArr; + + for (const auto &error: fehlerListe) + { + QJsonObject errorObj; + errorObj.insert(QStringLiteral("errorNumber"), error.errorNumber); + errorObj.insert(QStringLiteral("canDeviceNumber"), error.canDeviceNumber); + errorObj.insert(QStringLiteral("subdeviceNumber"), error.subdeviceNumber); + errorObj.insert(QStringLiteral("uniqueId"), error.uniqueId); + errorArr.append(errorObj); + } + obj.insert(QStringLiteral("biteError"), errorArr); + + + QJsonDocument doc(obj); + emit warehouseMessageFromPtrCnv(doc.toJson()); +} + + + + + +void PrtCnvRadioThread::handleStatusIndReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + uint32_t srcISSI = *(uint32_t *)&a_data[5]; + uint32_t dstISSI = *(uint32_t *)&a_data[9]; + uint16_t status = *(uint16_t *)&a_data[13]; + INFO_LOG(m_logger) << "Received Status from " << srcISSI << " for " + << dstISSI << " - status: " << status; +} + + + + +void PrtCnvRadioThread::handleAirInterfaceLoadReq(const QByteArray &data) +{ + const uint8_t *a_data = reinterpret_cast(data.data()); + + + uint16_t nbrOfReports = *(uint16_t *)&a_data[5]; + INFO_LOG(m_logger) << "Number of AirInterface-reports: " << nbrOfReports; + + uint16_t sdsQueueLength = 0; + uint16_t index = 7; + for (int i = 0; i < nbrOfReports; i++) + { + uint8_t networkIndex = a_data[index++]; + uint16_t baseStationID = *(uint16_t *)&a_data[index]; + index += 2; + uint8_t channelID = a_data[index++]; + uint8_t queueLength = a_data[index++]; + INFO_LOG(m_logger) << "AirInterface-report[" << i << "]: networkIndex=" << (int)networkIndex << " baseStationID=" << baseStationID << " channelID=" << (int)channelID << " queueLength=" << (int)queueLength; + if (1 == networkIndex) + sdsQueueLength = queueLength; + } + E_TrafficLoad newLoad; + + if (sdsQueueLength > m_SendQueueFullLoad) + { + newLoad = E_TrafficLoad::FullLoad; + INFO_LOG(m_logger) << "Set send-load to Full"; + } + else if (sdsQueueLength > m_SendQueueHighLoad) + { + newLoad = E_TrafficLoad::HighLoad; + INFO_LOG(m_logger) << "Set send-load to High"; + } + else + { + newLoad = E_TrafficLoad::NormalLoad; + INFO_LOG(m_logger) << "Set send-load to Normal"; + } + + m_SendLoad = newLoad; +} + + + + +void PrtCnvRadioThread::computeAndLogTrafficStatistics() +{ + if (++m_TickCounter >= m_TicksPerSecond) + { + m_TickCounter = 0; + m_SentBytesAverage[m_AverageIndex] = m_SentBytes; + m_ReceivedBytesAverage[m_AverageIndex] = m_ReceivedBytes; + if (++m_AverageIndex >= AVERAGE_COUNT) m_AverageIndex = 0; + uint32_t sendAverage = 0; + uint32_t receiveAverage = 0; + for (int i = 0; i < AVERAGE_COUNT; i++) + { + sendAverage += m_SentBytesAverage[i]; + receiveAverage += m_ReceivedBytesAverage[i]; + } + DEBUG_LOG(m_loggerStats) << "Send-Statistics: " << m_SentTelegrams << " telegrams (" << m_SentBytes << "/" << sendAverage << " bytes) sent; " << (sendAverage / 10) << " kB/s"; + DEBUG_LOG(m_loggerStats) << "Receive-Statistics: " << m_ReceivedTelegrams << " telegrams (" << m_ReceivedBytes << "/" << receiveAverage << " bytes) received; " << (receiveAverage / 10) << " kB/s"; + m_SentBytes = 0; + m_SentTelegrams = 0; + m_ReceivedBytes = 0; + m_ReceivedTelegrams = 0; + } +} + + + + + + + +bool PrtCnvRadioThread::isSendLimitReached() const +{ + switch (m_SendLoad) + { + case E_TrafficLoad::NormalLoad: + return m_SentTelegrams >= m_SendTelegramsNormalLoad; + case E_TrafficLoad::HighLoad: + return m_SentTelegrams >= m_SendTelegramsHighLoad; + case E_TrafficLoad::FullLoad: + return m_SentTelegrams >= m_SendTelegramsFullLoad; + case E_TrafficLoad::Unknown: + return false; + } + Q_ASSERT(false); + return false; +} + + + + + +void PrtCnvRadioThread::sendEnvironmentTelegramTimerNow() +{ + + QTimer::singleShot(0, this, &PrtCnvRadioThread::onSendEnvironmentTelegramTimerNow); +} + +void PrtCnvRadioThread::onSendEnvironmentTelegramTimerNow() +{ + if (!m_EnvironmentTelegramTimer || !m_EnvironmentTelegramTimer->isActive()) + return; + timeoutEnvironmentTelegram(); +} + +template +void removeFromContainer(T &cont, int id) +{ + auto it = cont.find(id); + if (it != cont.end()) + cont.erase(it); +} + +void PrtCnvRadioThread::exerciseEquipmentChanged(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data) +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + m_exerciseEquipmentAssignments = data.exerciseEquipmentAssignments; + for (const auto &info : data.groupIssiInformation) + m_groupIssiInformation[info.exerciseId] = info; + + emit checkMemberForValidLogin(-1, -1); +} + +void PrtCnvRadioThread::onCheckMemberForValidLogin(int identity, int issi) +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + if (identity == -1) + { + const auto knownIdentities = m_DbThread->getClaimStatistics(); + for (const auto &p : knownIdentities) + { + if (p.first <= 0) + continue; + onCheckMemberForValidLogin(p.first, -1); + } + } + else + { + if (isIdentityInCurrentExercise(identity)) + { + DEBUG_LOG(m_logger) << "onCheckMemberForValidLogin: eqid: " << identity << " is in current exercise " << m_ExerciseId; + return; + } + PrtCnv::PrtCnvMember *member = m_DbThread->getMemberById(identity); + if (!member) + return; + issi = member->m_ISSI; + + const int newExerciseId = exerciseIdForIdentity(identity); + if (newExerciseId != 0 && newExerciseId != member->m_loggedInExerciseId) + sendLoginAccept(identity, issi, newExerciseId, false); + } +} + +void PrtCnvRadioThread::sendLoginAccept(int identity, int issi, int exerciseId, bool bWithMastering) +{ + using namespace N_CoPrtCnv; + auto response = 0; + if (bWithMastering) + response |= CoPrtCnvRadioTelegram::e_LoginMastering; + + PrtCnvMember *member = m_DbThread->getMemberById(identity); + const auto it = m_groupIssiInformation.find(exerciseId); + if (it == m_groupIssiInformation.end() || exerciseId == 0) + { + + QString log; + if (exerciseId == 0) + log = QStringLiteral("Denied Login of TPU with Id=%1 and ISSI=%2 - Id is not assigned in any exercise.") + .arg(identity).arg(issi); + else + log = QStringLiteral("TPU with Id=%1 and ISSI=%2 should be in exercise %3 but could not find valid group information for this exercise!") + .arg(identity).arg(issi).arg(exerciseId); + if (bWithMastering) + log += QStringLiteral(" Mastering-Bit is set"); + WARNING_LOG(m_logger) << log; + writeLoginLog(identity, issi, log); + if (m_ExerciseId != exerciseId) + response |= CoPrtCnvRadioTelegram::e_LoginNoExerciseAssignment; + response |= CoPrtCnvRadioTelegram::e_LoginReject; + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(response), identity, issi); + if (m_ExerciseId == 0) + m_DbThread->updateExerciseIdForMember(member, exerciseId); + else + m_DbThread->removeMember(member); + return; + } + + const TrainingAreaBase::TetraIcd::GroupIssiInformation &gi = it->second; + QString log; + if (m_ExerciseId != exerciseId) + log = QStringLiteral("TPU with Id=%1 and ISSI=%2 should switch to exercise %3 (%4/%5).") + .arg(identity).arg(issi).arg(exerciseId).arg(gi.broadcastIssi1).arg(gi.broadcastIssi2); + else + log = QStringLiteral("(Re)Login of TPU with Id=%1 and ISSI=%2.") + .arg(identity).arg(issi); + if (bWithMastering) + log += QStringLiteral(" Mastering-Bit is set"); + DEBUG_LOG(m_logger) << log; + writeLoginLog(identity, issi, log); + + if (m_ExerciseId != exerciseId) + response |= CoPrtCnvRadioTelegram::e_LoginOtherExercise; + response |= CoPrtCnvRadioTelegram::e_LoginAccept; + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(response), identity, issi, gi); + if (m_ExerciseId == 0) + m_DbThread->updateExerciseIdForMember(member, exerciseId); +} + +bool PrtCnvRadioThread::isIdentityInCurrentExercise(int identity) const +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + if (m_exerciseEquipmentAssignments.empty()) + return true; + const auto it = m_exerciseEquipmentAssignments.find(m_ExerciseId); + if (it == m_exerciseEquipmentAssignments.end()) + return false; + const auto itIdentity = it->second.find(identity); + return (itIdentity != it->second.end()); +} + +int PrtCnvRadioThread::exerciseIdForIdentity(int identity) const +{ + QMutexLocker l(&m_exerciseEquipmentAssignmentMutex); + for (const auto &s : m_exerciseEquipmentAssignments) + { + auto it = s.second.find(identity); + if (it != s.second.end()) + return s.first; + } + return 0; +} + +void PrtCnvRadioThread::removeMasteringMember(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram, + PrtCnvMember *member, + PrtCnvMember *issiMember, + int masterIdentity, + int masterIssi) +{ + using namespace N_CoPrtCnv; + + + if (member) + { + m_DbThread->updateExerciseIdForMember(member, 0); + + if (member->m_Licensed) + { + sendLizenzierungTneToRadio(member->m_Id, member->m_ISSI, N_CoPrtCnv::E_LicensingKind::Unlicense, N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + INFO_LOG(m_logger) << "Unlicense TPU with already used ID. Id=" + << member->m_Id << " ISSI=" << member->m_ISSI; + } + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(CoPrtCnvRadioTelegram::e_LoginReject | CoPrtCnvRadioTelegram::e_LoginOtherEqId), + member->m_Id, member->m_ISSI); + INFO_LOG(m_logger) << "Reject TPU with already used ID. Id=" + << member->m_Id << " ISSI=" << member->m_ISSI; + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: TPU with Id=%1 and ISSI=%2 was removed from TETRA due to Mastering-Bit from Id=%3 and ISSI=%4") + .arg(member->m_Id).arg(member->m_ISSI).arg(masterIdentity).arg(masterIssi)); + m_DbThread->removeMember(member); + } + + + if (issiMember) + { + m_DbThread->updateExerciseIdForMember(issiMember, 0); + + if (issiMember->m_Licensed) + { + sendLizenzierungTneToRadio(issiMember->m_Id, issiMember->m_ISSI, N_CoPrtCnv::E_LicensingKind::Unlicense, N_CoPrtCnv::E_LicensingErrorCode::Unlicense); + INFO_LOG(m_logger) << "Unlicense TPU with already used ISSI. Id=" + << issiMember->m_Id << " ISSI=" << issiMember->m_ISSI; + } + + sendLoginResponse(CoPrtCnvRadioTelegram::E_LoginStatus(CoPrtCnvRadioTelegram::e_LoginReject | CoPrtCnvRadioTelegram::e_LoginOtherISSI), + issiMember->m_Id, issiMember->m_ISSI); + INFO_LOG(m_logger) << "Reject TPU with already used ISSI. Id=" + << issiMember->m_Id << " ISSI=" << issiMember->m_ISSI; + writeLoginLog(a_loginTelegram, + QStringLiteral("Login-failure: TPU with Id=%1 and ISSI=%2 was removed from TETRA due to Mastering-Bit from Id=%3 and ISSI=%4") + .arg(issiMember->m_Id).arg(issiMember->m_ISSI).arg(masterIdentity).arg(masterIssi)); + m_DbThread->removeMember(issiMember); + } +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioThread.hpp b/TetraIF/PrtCnv/PrtCnvRadioThread.hpp new file mode 100644 index 000000000..94dfaae1b --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioThread.hpp @@ -0,0 +1,419 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvBroadcastMgr.hpp" +#include +#include +#include +#include +#include + +#define MAX_IDENTITY 65535 + +namespace PrtCnv +{ +struct BiteError +{ + int errorNumber = 0; + int canDeviceNumber = 0; + int subdeviceNumber = 0; + int uniqueId = 0; +}; + + class PrtCnvCentralThread; + class PrtCnvMember; + class PrtCnvRadioTrafficThread; + class PrtCnvStoredRadioTelegram; + + + class PrtCnvRadioThread : public PrtCnv::PrtCnvSocketThread + { + Q_OBJECT + +public: + + PrtCnvRadioThread(int exerciseId, PrtCnvThreadStarter* a_parent); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t destroy() override; + + + int32_t init() override; + + + int32_t start() override; + + + + void prepareCleanUp(); + + + + void sendEnvironmentTelegramTimerNow(); + + void exerciseEquipmentChanged(const TrainingAreaBase::TetraIcd::ExerciseEquipmentAssignmentComplete &data); + protected: + void onCheckMemberForValidLogin(int identity, int issi); + void sendLoginAccept(int identity, int issi, int exerciseId, bool bWithMastering); + bool isIdentityInCurrentExercise(int identity) const; + int exerciseIdForIdentity(int identity) const; + void removeMasteringMember(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram, PrtCnvMember *member, + PrtCnvMember *issiMember, + int masterIdentity, + int masterIssi); + + protected: + + + PrtCnvCentralThread *m_CentralThread; + + + + PrtCnvRadioTrafficThread *m_radioTrafficThread; + +public: + + Q_SIGNALS: + + + void checkSendToCentral(); + + + void checkSendToRadio(); + + + void cleant(); + + + void stopped(); + + + + void checkMemberForValidLogin(int identity, int issi); + + + + void tetraConnectionState(bool connected); + + + void areaEffectSimulationActivated(int wirkfeldKennung); + void areaEffectSimulationDeactivated(int wirkfeldKennung); + + + void initDone(); + + + void playerLicencedChanged(int equipNo, N_CoPrtCnv::E_LicensingKind kind); + void warehouseMessageFromPtrCnv(const QByteArray &jsonData); + protected: + + + uint32_t m_SendCounter; + + + uint32_t m_HostISSI; + + + const uint32_t START_COUNTER; + + + const uint32_t END_COUNTER; + + + QTimer *m_EnvironmentTelegramTimer; + + + uint32_t m_BroadcastISSI; + + + QString m_LoginPathWithPrefix; + + + int m_ExerciseId; + + + std::set m_AllowedIdentities; + + + bool m_DoLicenseDespiteSelftestOrConfigFailure; + + + bool m_DoCheckIdentity; + PrtCnvBroadcastMgr m_BroadcastManager; + + + bool m_DoDumpReceivedTelegrams; + + + bool m_DoDumpSentTelegrams; + + + bool m_DoUseSDSTL; + + + + std::set m_DoNeedActPosResp; + + + + uint32_t m_EmergencyCallISSI; + + + + void sendTelegram(const std::shared_ptr &a_telegram, + PrtCnvStoredRadioTelegram *a_handle, + const bool a_doCheckWhetherExpired = true); + + + + + void doRegister(); + + + + void registerGroups(); + + + + void handleRegisterRsp(const uint8_t a_regsitrationStatus); + + public: + + + + enum class E_TrafficLoad + { + Unknown = -1, + NormalLoad = 0, + HighLoad, + FullLoad + }; + protected: + + + N_CoPrtCnv::CoPrtCnvRadioTelegram *m_EnvironmentTelegram; + + + + E_TrafficLoad m_SendLoad; + + uint32_t m_SendQueueFullLoad; + uint32_t m_SendQueueHighLoad; + uint32_t m_SendTelegramsNormalLoad; + uint32_t m_SendTelegramsHighLoad; + uint32_t m_SendTelegramsFullLoad; + + + uint32_t m_SentTelegrams; + + + uint32_t m_SentBytes; + + + uint32_t m_TickCounter; + + + uint32_t m_TicksPerSecond; + + + static const int AVERAGE_COUNT = 10; + + + uint32_t m_SentBytesAverage[AVERAGE_COUNT]; + + + uint8_t m_AverageIndex; + + + uint32_t m_ReceivedTelegrams; + + + uint32_t m_ReceivedBytes; + + + uint32_t m_ReceivedBytesAverage[AVERAGE_COUNT]; + + + + std::set m_ListenGroups; + + + + bool m_bUseScrambling; + + + NGL::INGLLogger &m_loggerStats; + + + std::unordered_map> m_exerciseEquipmentAssignments; + std::unordered_map m_groupIssiInformation; + mutable QMutex m_exerciseEquipmentAssignmentMutex; + + private: + + + bool sendAnswer(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram); + + + void handleReceivedTelegram(const QByteArray &data); + + + void handleDataIndReq(const QByteArray &data, bool bIsMaybeScrambled); + + + void handleLoginTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_loginTelegram); + + + void handleFragmentedTelegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_fragmentedTelegram); + + + void sendFehlermeldungGefechtsfeldToCentral(const uint16_t a_identity, + const TrainingAreaBase::TetraIcd::CtaDataError::Reason a_errorCause, + const gef_telegramm_id_et a_telegramId = GEF_BESTAETIGUNG); + + + uint32_t getDestinationISSI(const uint16_t a_TNE_Id) const; + + + bool handleBITEEXT_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram); + bool handleBITE_Telegram(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_BITE_RadioTelegram, + TrainingAreaBase::TetraIcd::BiteReport::LoginType anmeldeart, + uint32_t ergebnisCAN, + uint32_t ergebnisAusstattung, + uint32_t aktuelleKonfiguration, + uint32_t konfigurationsvergleich, + const QList &fehlerListe + ); + + + + void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, const uint16_t a_identity, const uint32_t a_ISSI); + void sendLoginResponse(const N_CoPrtCnv::CoPrtCnvRadioTelegram::E_LoginStatus a_loginTelegramStatus, + const uint16_t a_identity, const uint32_t a_ISSI, const TrainingAreaBase::TetraIcd::GroupIssiInformation &group); + + + + void sendLizenzierungTneToRadio(const uint16_t a_identity, const uint32_t a_issi, + const N_CoPrtCnv::E_LicensingKind a_licensingKind, + const N_CoPrtCnv::E_LicensingErrorCode a_errorCause); + + + + void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram &a_radioTelegram, const QString &a_prosaText); + void writeLoginLog(const N_CoPrtCnv::CoPrtCnvRadioTelegram *a_radioTelegram, const QString &a_prosaText); + void writeLoginLog(uint32_t identity, uint32_t issi, const QString &a_prosaText); + + + void initIdentityArray(); + + + uint16_t readIdentity(const QByteArray& a_idAsText, const uint32_t a_line, const QString& a_fileName); + + + bool isIdentityValid(uint16_t a_identity) const; + + + + void setIdentityVaild(uint16_t a_identity); + + + + void sendFragmentedTelegram(const std::shared_ptr &a_telegram); + + + + uint16_t sendToSocket(const std::shared_ptr &a_telegram); + + + + void handleReportIndReq(const QByteArray &data); + void prepareWareHouseMessage(qint32 equipNr, + bool doLicence, + qint64 ergebnisCAN, + qint64 ergebnisAusstattung, + qint64 aktuelleKonfiguration, + qint64 konfigurationsvergleich, + const QList &fehlerListe); + + protected Q_SLOTS: + + + void onSendEnvironmentTelegramTimerNow(); + + + void timeoutAliveAndConnection() override; + + + void timeoutTick() override; + + + void checkSend(); + + + void readyRead() override; + + + void disconnected() override; + + + void connected() override; + + + void timeoutEnvironmentTelegram(); + + + void doClean(); + + + void doStart(); + + + void doStop(); + + + + void onBroadcastTelegramsRequestFromCentral(int equipmentNumber, int broadcastIndex, int resetCounter); + + private: + + + void handleStatusIndReq(const QByteArray &data); + + + + void handleAirInterfaceLoadReq(const QByteArray &data); + + + + void computeAndLogTrafficStatistics(); + + + + bool isSendLimitReached() const; + + + void sendScrambledContent(const std::shared_ptr &a_telegram) const; + bool unscrambleContent(N_CoPrtCnv::CoPrtCnvRadioTelegram &a_telegram) const; + + + friend class PrtCnvCentralThread; + }; + + std::ostream &operator<<(std::ostream &os, const PrtCnvRadioThread::E_TrafficLoad tl); +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp new file mode 100644 index 000000000..78359487f --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.cpp @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include +#include +#include +#include + +namespace PrtCnv +{ + +PrtCnvRadioTrafficThread::PrtCnvRadioTrafficThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvRadioTrafficThread") + , m_receiveLoad(PrtCnvRadioThread::E_TrafficLoad::Unknown) + , m_fullLoad(100) + , m_highLoad(50) + , m_hystLoad(5) + , m_calcTimeout(1000) + , m_cleanupTimeout(5000) + , m_mutex(QMutex::Recursive) +{} + +void PrtCnvRadioTrafficThread::newTelegramArrived(unsigned int size) +{ + time_t curTime = time(nullptr); + + QMutexLocker l(&m_mutex); + DEBUG_LOG(m_logger) << "newTelegramArrived with size " << size << " at " << curTime; + m_data[curTime] += size; + m_telegrams[curTime]++; +} + +int32_t PrtCnvRadioTrafficThread::start() +{ + + const QString trafficControlGroup(QStringLiteral("TrafficControl")); + int highLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueHighLoad"), 60); + int fullLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueFullLoad"), 80); + int hystLoad = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveQueueHysteresis"), 5); + int avgTime = m_Config->getInteger(trafficControlGroup, QStringLiteral("ReceiveAveragingTime"), 5); + float trafficPerReceiverKB = m_Config->getFloat(trafficControlGroup, QStringLiteral("ReceiveThroughput"), 3.6f); + int cntTransceiver = m_Config->getInteger(trafficControlGroup, QStringLiteral("TransceiverCount"), 6); + + + if (highLoad < 0 || highLoad > 100) + highLoad = 60; + if (fullLoad < highLoad || fullLoad > 100) + fullLoad = 80; + if (hystLoad < 0 || hystLoad > 10) + hystLoad = 5; + if (avgTime <= 0 || avgTime > 60) + avgTime = 5; + if (trafficPerReceiverKB < 1 || trafficPerReceiverKB > 1000) + trafficPerReceiverKB = 3.6f; + if (cntTransceiver < 1 || cntTransceiver > 100) + cntTransceiver = 6; + + float maxTrafficBytes = trafficPerReceiverKB * cntTransceiver * 1024; + + m_fullLoad = maxTrafficBytes * fullLoad / 100.f; + m_highLoad = maxTrafficBytes * highLoad / 100.f; + m_hystLoad = maxTrafficBytes * hystLoad / 100.f; + m_cleanupTimeout = avgTime * 1000; + + DEBUG_LOG(m_logger) << "Read config ReceiveQueueHighLoad: " << highLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveQueueFullLoad: " << fullLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveQueueHysteresis: " << hystLoad; + DEBUG_LOG(m_logger) << "Read config ReceiveAveragingTime: " << avgTime; + DEBUG_LOG(m_logger) << "Read config ReceiveThroughput: " << trafficPerReceiverKB; + DEBUG_LOG(m_logger) << "Read config TransceiverCount: " << cntTransceiver; + + INFO_LOG(m_logger) << "Using to following limits: high - " << m_highLoad + << " full - " << m_fullLoad + << " hyst - " << m_hystLoad + << " avg. time - " << m_cleanupTimeout / 1000; + + QTimer::singleShot(m_calcTimeout, this, &PrtCnvRadioTrafficThread::onCalculateTrafficLoad); + QTimer::singleShot(m_cleanupTimeout, this, &PrtCnvRadioTrafficThread::onCleanupTimeout); + return 0; +} + +void PrtCnvRadioTrafficThread::onCalculateTrafficLoad() +{ + const time_t curTime = time(nullptr); + + unsigned int payload = 0; + { + QMutexLocker l(&m_mutex); + + for (int i = 1; i <= m_cleanupTimeout / 1000; ++i) + payload += m_data.value(curTime - i); + } + + + payload /= (m_cleanupTimeout / 1000); + + INFO_LOG(m_logger) << "Average Payload in the last " + << m_cleanupTimeout << " Milliseconds: " + << payload << " Bytes/sec, last sec: " + << m_data[curTime - 1] << " Bytes, #telegrams: " << m_telegrams[curTime - 1]; + + PrtCnvRadioThread::E_TrafficLoad newReceiveLoad; + if (payload >= m_fullLoad) + { + + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::FullLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::HighLoad) + { + + + if(payload < m_fullLoad + m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + } + } + else if (payload >= m_highLoad) + { + + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::NormalLoad) + { + + + if (payload < m_highLoad + m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::NormalLoad; + } + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::FullLoad) + { + + + if (payload >= m_fullLoad - m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::FullLoad; + } + } + else + { + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::NormalLoad; + + if (m_receiveLoad == PrtCnvRadioThread::E_TrafficLoad::HighLoad) + { + + + if(payload >= m_highLoad - m_hystLoad) + newReceiveLoad = PrtCnvRadioThread::E_TrafficLoad::HighLoad; + } + } + if (m_receiveLoad != newReceiveLoad) + { + m_receiveLoad = newReceiveLoad; + + unsigned int wartezeit_posmldg = (static_cast(m_receiveLoad) * 10) + 1; + + INFO_LOG(m_logger) << "New traffic load: " << m_receiveLoad; + PrtCnvDbThread *dbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + if (dbThread) + { + dbThread->setAirLoad(m_receiveLoad); + dbThread->setPositionSendTime(wartezeit_posmldg); + + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + } + else + ERROR_LOG(m_logger) << "Could not get PrtCnvDbThread!"; + } + + QTimer::singleShot(m_calcTimeout, this, &PrtCnvRadioTrafficThread::onCalculateTrafficLoad); +} + +void PrtCnvRadioTrafficThread::onCleanupTimeout() +{ + const time_t curTime = time(nullptr); + { + QMutexLocker l(&m_mutex); + QMap::iterator it = m_data.begin(); + while (it != m_data.end()) + { + const time_t key = it.key(); + + if (key < curTime - m_cleanupTimeout - 10) + { + m_data.erase(it++); + m_telegrams.remove(key); + continue; + } + break; + } + } + + QTimer::singleShot(m_cleanupTimeout, this, &PrtCnvRadioTrafficThread::onCleanupTimeout); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp new file mode 100644 index 000000000..84953cfb7 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvRadioTrafficThread.hpp @@ -0,0 +1,82 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include +#include + +namespace PrtCnv +{ + + +class PrtCnvRadioTrafficThread final : public PrtCnvThread +{ + Q_OBJECT +public: + explicit PrtCnvRadioTrafficThread(PrtCnvThreadStarter* a_parent); + + + + void newTelegramArrived(unsigned int size); + + + + int32_t start() override; + +protected Q_SLOTS: + + + void onCalculateTrafficLoad(); + + + + void onCleanupTimeout(); + +protected: + + + PrtCnvRadioThread::E_TrafficLoad m_receiveLoad; + + + + unsigned int m_fullLoad; + + + + unsigned int m_highLoad; + + + + unsigned int m_hystLoad; + + + + int m_calcTimeout; + + + + int m_cleanupTimeout; + + + + QMutex m_mutex; + + + + QMap m_data; + QMap m_telegrams; +}; +} diff --git a/TetraIF/PrtCnv/PrtCnvSocketThread.cpp b/TetraIF/PrtCnv/PrtCnvSocketThread.cpp new file mode 100644 index 000000000..0b8584273 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvSocketThread.cpp @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + +#include "PrtCnvSocketThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvInjectionThread.hpp" + +#include +#include + +namespace PrtCnv +{ + + + + +PrtCnvSocketThread::PrtCnvSocketThread(PrtCnv::PrtCnvThreadStarter* a_parent, const char *loggerName) + : PrtCnvThread(a_parent, loggerName) + , m_ConnectionTimer(nullptr) + , m_Socket(nullptr) + , m_TickTimer(nullptr) + , m_ReceiveCounter(0) + , m_ReceiveAckCounter(0) + , m_State(PrtCnvSocketThread::e_INITIAL) + , m_DbThread(nullptr) + , m_ConnectTimeout(2000) + , m_DisconnectTimeout(10000) + , m_AliveTimeout(3000) + , m_TickTimeout(900) + , m_DoCleanup(false) + , m_LogThread(nullptr) + , m_InjectionThread(nullptr) + , m_currentHostAdressIndex(0) +{} + + + +PrtCnvSocketThread::~PrtCnvSocketThread() +{ + cleanup(); +} + + + + +int32_t PrtCnvSocketThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + createNewSocket(); + + m_ConnectionTimer = new QTimer(this); + connect(m_ConnectionTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutAliveAndConnection); + + m_TickTimer = new QTimer(this); + connect(m_TickTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutTick); + + m_DbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); + m_LogThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Log)); + m_InjectionThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Injection)); + + return 0; +} + + + + + +void PrtCnvSocketThread::createNewSocket() +{ + INFO_LOG(m_logger) << "createNewSocket m_oldSocket=" << m_Socket; + Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); + + if (m_Socket) + { + m_Socket->disconnectFromHost(); + m_Socket->disconnect(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + m_Socket->deleteLater(); + } + + m_Socket = new QTcpSocket(this); + qRegisterMetaType("QAbstractSocket::SocketError"); + qRegisterMetaType("QAbstractSocket::SocketState"); + + connect(m_Socket, &QTcpSocket::connected, this, &PrtCnvSocketThread::connected, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::disconnected, this, &PrtCnvSocketThread::disconnected, Qt::QueuedConnection); + connect(m_Socket, QOverload::of(&QTcpSocket::error), this, &PrtCnvSocketThread::error, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::hostFound, this, &PrtCnvSocketThread::hostFound, Qt::QueuedConnection); + connect(m_Socket, &QTcpSocket::stateChanged, this, &PrtCnvSocketThread::stateChanged); + connect(m_Socket, &QTcpSocket::readyRead, this, &PrtCnvSocketThread::readyRead, Qt::QueuedConnection); +} + + + + +int32_t PrtCnvSocketThread::destroy() +{ + PrtCnvThread::destroy(); + cleanup(); + return 0; +} + +void PrtCnvSocketThread::cleanup() +{ + delete m_Socket; m_Socket = nullptr; + delete m_ConnectionTimer; m_ConnectionTimer = nullptr; + delete m_TickTimer; m_TickTimer = nullptr; + +} + + + + +int32_t PrtCnvSocketThread::init() +{ + INFO_LOG(m_logger) << "PrtCnvSocketThread::init()"; + PrtCnvThread::init(); + m_State = e_INITIAL; + + m_ConnectTimeout = m_Config->getInteger(getName(), QStringLiteral("ConnectTimeout"), 2000); + m_DisconnectTimeout = m_Config->getInteger(getName(), QStringLiteral("DisconnectTimeout"), 10000); + m_AliveTimeout = m_Config->getInteger(getName(), QStringLiteral("AliveTimeout"), 3000); + + return 0; +} + + + + + +void PrtCnvSocketThread::connectSocket() +{ + int sockState = m_Socket ? m_Socket->state() : -1; + INFO_LOG(m_logger) << "connectSocket m_Socket=" << m_Socket << " state=" << m_State << " socketState=" << sockState; + if (e_WORKING != m_State && e_REGISTERING != m_State) + { + if (m_Socket) + { + m_Socket->disconnectFromHost(); + if (m_Socket->state() != QAbstractSocket::UnconnectedState) + m_Socket->waitForDisconnected(); + } + + createNewSocket(); + + if(m_hostAdresses.isEmpty()) + readHostAdresses(); + const QString hostname = m_hostAdresses.at(m_currentHostAdressIndex).first; + const uint16_t port = m_hostAdresses.at(m_currentHostAdressIndex).second; + m_currentHostAdressIndex = ((m_currentHostAdressIndex + 1) % m_hostAdresses.size()); + INFO_LOG(m_logger) << "Connecting to " << hostname << ":" << port << " m_Socket=" << m_Socket; + m_Socket->connectToHost(hostname, port); + m_State = e_CONNECTING; + startConnectionTimer(); + } + else + { + WARNING_LOG(m_logger) << getName() << ": connectSocket called, but m_State is " << m_State; + } +} + + + + +void PrtCnvSocketThread::disconnectSocket() +{ + m_Socket->disconnectFromHost(); + startDisconnectionTimer(); + m_State = e_DISCONNECTING; +} + + + + + + +void PrtCnvSocketThread::connected() +{ + INFO_LOG(m_logger) << "connected (implement connected() in inherited class, if you want use this signal...)"; +} + + + + + +void PrtCnvSocketThread::disconnected() +{ + INFO_LOG(m_logger) << "got signal 'disconnected' (implement disconnected() in inherited class, if you want use this signal...)"; +} + + + + + +void PrtCnvSocketThread::readyRead() +{ + INFO_LOG(m_logger) << "got signal 'newData' (implement newData() in inherited class, if you want use this signal...)"; +} + + + + + + +void PrtCnvSocketThread::timeoutAliveAndConnection() +{ + INFO_LOG(m_logger) << "got signal 'reconnectTimeout' (implement reconnectTimeout() in inherited class, if you want use this signal...)"; +} + + + + +void PrtCnvSocketThread::error(QAbstractSocket::SocketError a_socketError) +{ + switch (a_socketError) + { + case QAbstractSocket::ConnectionRefusedError: + ERROR_LOG(m_logger) << getName() << ": ConnectionRefusedError m_State=" << m_State; + break; + case QAbstractSocket::RemoteHostClosedError: + ERROR_LOG(m_logger) << getName() << ": RemoteHostClosedError"; + break; + case QAbstractSocket::HostNotFoundError: + + break; + default: + ERROR_LOG(m_logger) << getName() << ": got signal 'error(QAbstractSocket::SocketError=" << a_socketError << ")'"; + } +} + + + + + +void PrtCnvSocketThread::hostFound() +{ + +} + + + + + +void PrtCnvSocketThread::stateChanged(QAbstractSocket::SocketState a_socketState) +{ + Q_UNUSED(a_socketState); + +} + + + + + +void PrtCnvSocketThread::storeRadioTelegram(const std::shared_ptr &a_telegram, + const uint32_t a_readCounter) +{ + m_DbThread->storeRadioTelegram(a_telegram, a_readCounter); +} + + + + + +void PrtCnvSocketThread::startAliveTimer() +{ + m_ConnectionTimer->setInterval(m_AliveTimeout); + m_ConnectionTimer->start(); +} + + + + + +void PrtCnvSocketThread::startConnectionTimer() +{ + m_ConnectionTimer->setInterval(m_ConnectTimeout); + m_ConnectionTimer->start(); +} + + + + + + +void PrtCnvSocketThread::startDisconnectionTimer() +{ + m_ConnectionTimer->setInterval(m_DisconnectTimeout); + m_ConnectionTimer->start(); +} + + + + + + +void PrtCnvSocketThread::startTickTimer() +{ + + m_TickTimer->setInterval(m_TickTimeout); + m_TickTimer->start(); +} + + + + + + + + +bool PrtCnvSocketThread::checkAndUpdateReceiveCounter(const uint32_t a_counter, const uint32_t a_maxCounter, const uint32_t a_startCounter) +{ + TRACE_LOG(m_logger) << "checkAndUpdateReceiveCounter: " << a_counter << ", " << m_ReceiveCounter; + + if (a_maxCounter == ++m_ReceiveCounter) + { + m_ReceiveCounter = a_startCounter; + } + + if (m_ReceiveCounter != a_counter) + { + + { + if (m_ReceiveCounter > a_counter) + { + ERROR_LOG(m_logger) << "It seems, the telegram with counter " << a_counter << " was resent from " + << getName() << "! Expected: " << m_ReceiveCounter; + } + else + { + ERROR_LOG(m_logger) << "It seems, we lost one or several telegrams from " << getName() + << ": receive-counter of received telegram: " << a_counter << "; Expected: " << m_ReceiveCounter; + } + } +#if 0 + m_ReceiveCounter--; + return false; +#else + m_ReceiveCounter = a_counter; + return true; +#endif + } + return true; +} + +void PrtCnvSocketThread::readHostAdresses() +{ + QString host = m_Config->getString(getName(), QStringLiteral("HostName"), QStringLiteral("127.0.0.1")); + uint16_t port = m_Config->getInteger(getName(), QStringLiteral("Port"), 4934); + m_hostAdresses.push_back(qMakePair(host, port)); + for (int i = 1; i < 10; ++i) { + const QString hostName = QLatin1String("HostName") + QString::number(i); + const QString portName = QLatin1String("Port") + QString::number(i); + host = m_Config->getString(getName(), hostName, QString()); + port = m_Config->getInteger(getName(), portName, 0); + if (host.isEmpty() || port == 0) + continue; + m_hostAdresses.push_back(qMakePair(host, port)); + } + for (const auto &p : qAsConst(m_hostAdresses)) { + INFO_LOG(m_logger) << "Read Host Adress " << p.first + << ":" << p.second + << " from settings"; + } +} + + +} diff --git a/TetraIF/PrtCnv/PrtCnvSocketThread.hpp b/TetraIF/PrtCnv/PrtCnvSocketThread.hpp new file mode 100644 index 000000000..7cb436fe1 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvSocketThread.hpp @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" + +#include +#include + +class QTimer; +class QTcpSocket; + +namespace N_CoPrtCnv +{ + class CoPrtCnvRadioTelegram; +} + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + class PrtCnvDbThread; + class PrtCnvTelegramLogThread; + class PrtCnvInjectionThread; + + + class PrtCnvSocketThread : public PrtCnvThread + { + Q_OBJECT + public: + + + + enum E_State + { + e_INITIAL, + e_CONNECTING, + e_REGISTERING, + e_WORKING, + e_DISCONNECTING, + e_REINIT + }; + + + PrtCnvSocketThread(PrtCnvThreadStarter* a_parent, const char *loggerName); + ~PrtCnvSocketThread(); + + + int32_t create(NGL::Settings *settings) override; + + + + void createNewSocket(); + + + + int32_t init() override; + + + int32_t destroy() override; + void cleanup(); + + protected: + + + QTimer *m_ConnectionTimer; + + + + + QTcpSocket *m_Socket; + + + + void readHostAdresses(); + + protected slots: + + + virtual void connected(); + + + virtual void readyRead(); + + + virtual void timeoutAliveAndConnection(); + + + virtual void timeoutTick() {} + + + virtual void error(QAbstractSocket::SocketError a_socketError); + + + virtual void hostFound(); + + + virtual void stateChanged(QAbstractSocket::SocketState a_socketState); + + protected: + + + QTimer *m_TickTimer; + + + uint32_t m_ReceiveCounter; + + + uint32_t m_ReceiveAckCounter; + + + PrtCnvSocketThread::E_State m_State; + + + PrtCnvDbThread *m_DbThread; + + + + int32_t m_ConnectTimeout; + + + int32_t m_DisconnectTimeout; + + + int32_t m_AliveTimeout; + + + int32_t m_TickTimeout; + + + QAtomicInt m_DoCleanup; + + + PrtCnvTelegramLogThread *m_LogThread; + + PrtCnvInjectionThread *m_InjectionThread; + + + + QVector > m_hostAdresses; + + + + int m_currentHostAdressIndex; + + + + virtual void disconnected(); + + + void startAliveTimer(); + + + void startConnectionTimer(); + + + void startDisconnectionTimer(); + + + + void connectSocket(); + + + void disconnectSocket(); + + + + void startTickTimer(); + + + + bool checkAndUpdateReceiveCounter(const uint32_t a_counter, const uint32_t a_maxCounter, const uint32_t a_startCounter); + + + + void storeRadioTelegram(const std::shared_ptr &a_telegram, const uint32_t a_readCounter); + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp new file mode 100644 index 000000000..23b8e634a --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredCentralTelegram.hpp @@ -0,0 +1,39 @@ + + + +#pragma once + +#include "PrtCnvStoredTelegram.hpp" +#include + +namespace PrtCnv +{ +class PrtCnvStoredCentralTelegram : public PrtCnv::PrtCnvStoredTelegram +{ +public: + PrtCnvStoredCentralTelegram(const std::shared_ptr &a_centralTelegram, + const std::shared_ptr &a_radioTelegram) + : PrtCnvStoredTelegram(a_radioTelegram) + , m_CentralTelegram(a_centralTelegram) + {} + + int writeCounter() const { return m_WriteCounter; } + + + + std::shared_ptr m_CentralTelegram; + + + uint32_t m_Attempts = 0; + + + int m_WriteCounter = 0; + + + bool m_DoResend = false; + + + bool m_DoDelete = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp new file mode 100644 index 000000000..92a114971 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredRadioTelegram.hpp @@ -0,0 +1,32 @@ + + + +#pragma once + +#include "PrtCnvStoredTelegram.hpp" + +namespace PrtCnv +{ +class PrtCnvStoredRadioTelegram : public PrtCnv::PrtCnvStoredTelegram +{ +public: + using PrtCnv::PrtCnvStoredTelegram::PrtCnvStoredTelegram; + + + + int32_t m_ReadCounter = 0; + + + uint16_t m_BroadcastIndex = 0; + + + uint8_t m_WriteCounter = 0; + + + bool m_DoDelete = false; + + + bool m_IsSent = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp b/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp new file mode 100644 index 000000000..55c421840 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvStoredTelegram.hpp @@ -0,0 +1,23 @@ + + + +#pragma once + +#include +#include + +namespace PrtCnv +{ +class PrtCnvStoredTelegram +{ +public: + explicit PrtCnvStoredTelegram(const std::shared_ptr &a_telegram) + : m_RadioTelegram(a_telegram) + {} + + std::shared_ptr m_RadioTelegram; + int64_t m_Id = 0; + bool m_WriteCounterChanged = false; +}; + +} diff --git a/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp new file mode 100644 index 000000000..d70c034df --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.cpp @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + +#include "PrtCnvTelegramLogThread.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include + +static int gettimeofday(struct timeval *__p, void *__t) +{ + union { + unsigned long long ns100; + FILETIME ft; + } now; + + constexpr long long SECONDS_SINCE_1601 = 11644473600LL; + constexpr long long USEC_IN_SEC = 1000000LL; + + GetSystemTimeAsFileTime(&now.ft); + __p->tv_usec = (long)((now.ns100 / 10LL) % USEC_IN_SEC); + __p->tv_sec = (long)(((now.ns100 / 10LL) / USEC_IN_SEC) - SECONDS_SINCE_1601); + + return (0); +} +#else +#include +#endif + +namespace PrtCnv +{ + + +PrtCnvTelegramLogThread::PrtCnvTelegramLogThread(PrtCnvThreadStarter* a_parent) + : PrtCnvThread(a_parent, "PrtCnvTelegramLogThread") + , m_DoLogCentralTelegram(true) + , m_DoLogWlsTelegram(true) + , m_DoLogRadioTelegram(true) +{ + m_Name = QStringLiteral("TelegramLog"); +} + + +int32_t PrtCnvTelegramLogThread::create(NGL::Settings *settings) +{ + PrtCnvThread::create(settings); + + connect(this, &PrtCnvTelegramLogThread::telegramLogReceived, + this, &PrtCnvTelegramLogThread::writeTelegramLog, + Qt::QueuedConnection); + + return 0; +} + + + +int32_t PrtCnvTelegramLogThread::init() +{ + PrtCnvThread::init(); + m_DoLogCentralTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogCentralTelegrams"), true); + m_DoLogWlsTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogWlsTelegrams"), true); + m_DoLogRadioTelegram = m_Config->getBoolean(QStringLiteral("Common"), QStringLiteral("LogRadioTelegrams"), true); + QString path = m_Config->getString(QStringLiteral("Common"), QStringLiteral("LogTelegramPath"), QStringLiteral(".")); + if (!QDir::isAbsolutePath(path)) + path = QCoreApplication::applicationDirPath() + QStringLiteral("/../") + path; + + m_LogTelegramPathWithPrefix = path + QLatin1Char('/') + m_Config->getString(QStringLiteral("Common"), QStringLiteral("LogTelegramPrefix"), QStringLiteral("PrtCnv_")); + if (!m_LogTelegramPathWithPrefix.endsWith(QLatin1Char('_'))) + m_LogTelegramPathWithPrefix += QLatin1Char('_'); + + + QFileInfo fileInfo(m_LogTelegramPathWithPrefix); + QDir dir; + dir.mkpath(fileInfo.absolutePath()); + + INFO_LOG(m_logger); + + return 0; +} + +static inline int setSend(int protocol, bool bIsSend) +{ + return (protocol | (bIsSend ? N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend : N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive)); +} + + + + +void PrtCnvTelegramLogThread::writeCentralTelegramLog(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_centralTelegram, bool a_isSend, int a_priority) +{ + if (!m_DoLogCentralTelegram) + return; + + emit telegramLogReceived(a_centralTelegram->data(), + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeWlsTelegramLog(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool a_isSend, int a_priority) +{ + if (!m_DoLogWlsTelegram) + return; + + N_CoPrtCnv::CoPrtCnvCentralTelegram central(*tele); + emit telegramLogReceived(central.data(), + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolWls, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeRadioTelegramLog(const QByteArray &tele, bool a_isSend, int a_priority) +{ + if (!m_DoLogRadioTelegram) + return; + + emit telegramLogReceived(tele, + setSend(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolTetra, a_isSend), + a_priority); +} + + + + + +void PrtCnvTelegramLogThread::writeTelegramLog(const QByteArray &a_data, int a_protocolType, int a_priority) +{ + + timeval tv; + gettimeofday(&tv, nullptr); + uint64_t exactTime = tv.tv_sec; + exactTime = exactTime << 32; + exactTime += tv.tv_usec; + + + QString fileName = QStringLiteral("%1%2.krlog") + .arg(m_LogTelegramPathWithPrefix, QDateTime::fromSecsSinceEpoch(tv.tv_sec).toString(QStringLiteral("yyMMdd_hh"))); + + + QFile telegramFile(fileName); + telegramFile.open(QIODevice::WriteOnly | QIODevice::Append); + + + N_CoPrtCnv::CoPrtCnvLogHeader lh; + lh.m_Length = a_data.size() + sizeof(N_CoPrtCnv::CoPrtCnvLogHeader); + lh.m_Version = 3; + lh.m_Priority = a_priority; + lh.m_Protocol = a_protocolType; + lh.m_Time = exactTime; + lh.m_Reserved = 0; + telegramFile.write(reinterpret_cast(&lh), sizeof(N_CoPrtCnv::CoPrtCnvLogHeader)); + + + telegramFile.write(a_data); + telegramFile.close(); +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp new file mode 100644 index 000000000..95cdc1cf9 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvTelegramLogThread.hpp @@ -0,0 +1,87 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvThread.hpp" + +namespace N_CoPrtCnv +{ +class CoPrtCnvCentralTelegram; +} + +namespace TrainingAreaBase +{ +namespace TetraIcd +{ +struct TrainingAreaTelegram; +} +} + +namespace PrtCnv +{ + + + class PrtCnvTelegramLogThread final : public PrtCnvThread + { + Q_OBJECT + + public: + + + explicit PrtCnvTelegramLogThread(PrtCnvThreadStarter* a_parent); + + int32_t create(NGL::Settings *settings) override; + + int32_t init() override; + + public slots: + + + void writeCentralTelegramLog(N_CoPrtCnv::CoPrtCnvCentralTelegram *a_centralTelegram, bool a_isSend, int a_priority); + + + + void writeWlsTelegramLog(const TrainingAreaBase::TetraIcd::TrainingAreaTelegram *tele, bool a_isSend, int a_priority); + + + + void writeRadioTelegramLog(const QByteArray &tele, bool a_isSend, int a_priority); + + private: + signals: + + + void telegramLogReceived(const QByteArray &a_data, int a_protocolType, int a_priority); + + private slots: + + + void writeTelegramLog(const QByteArray &a_data, int a_protocolType, int a_priority); + + protected: + + + QString m_LogTelegramPathWithPrefix; + + + bool m_DoLogCentralTelegram; + + + bool m_DoLogWlsTelegram; + + + bool m_DoLogRadioTelegram; + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvThread.cpp b/TetraIF/PrtCnv/PrtCnvThread.cpp new file mode 100644 index 000000000..ebd26852b --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThread.cpp @@ -0,0 +1,74 @@ + + + + + + + + + + + + + +#include "PrtCnvThread.hpp" +#include + +namespace PrtCnv +{ + + +bool PrtCnvThread::m_DoCleanDb = false; + + + + +PrtCnvThread::PrtCnvThread(PrtCnv::PrtCnvThreadStarter* a_parent, const char *loggerName) + : m_Parent(a_parent) + , m_currentThreadId(nullptr) + , m_logger(getLogger(loggerName)) +{} + +int32_t PrtCnvThread::create(NGL::Settings *settings) +{ + m_currentThreadId = QThread::currentThreadId(); + m_Config = settings; + + INFO_LOG(m_logger) << "create " << m_Name + << " - current thread id is " << m_currentThreadId; + return 0; +} + + +int32_t PrtCnvThread::init() +{ + INFO_LOG(m_logger) << "init " << m_Name; + return 0; +} + + +int32_t PrtCnvThread::start() +{ + INFO_LOG(m_logger) << "start " << m_Name; + return 0; +} + + +int32_t PrtCnvThread::stop() +{ + return 0; +} + + +int32_t PrtCnvThread::deinit() +{ + return 0; +} + + +int32_t PrtCnvThread::destroy() +{ + return 0; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvThread.hpp b/TetraIF/PrtCnv/PrtCnvThread.hpp new file mode 100644 index 000000000..134f40134 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThread.hpp @@ -0,0 +1,71 @@ + + + + + + + + + + + + + +#pragma once + +#include "IAppComponent.hpp" +#include "logger.h" +#include + + +namespace PrtCnv +{ + class PrtCnvThreadStarter; + + + class PrtCnvThread : public QObject, public N_AppComponent::IAppComponent + { + Q_OBJECT +protected: + + + NGL::Settings* m_Config; + + + PrtCnvThreadStarter *m_Parent; + + + Qt::HANDLE m_currentThreadId; + + + NGL::INGLLogger &m_logger; + + public: + + + static bool m_DoCleanDb; + + + PrtCnvThread(PrtCnvThreadStarter* a_parent, const char *loggerName); + + + int32_t create(NGL::Settings *settings) override; + + + int32_t init() override; + + + int32_t start() override; + + + int32_t stop() override; + + + int32_t deinit() override; + + + int32_t destroy() override; + + }; + +} diff --git a/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp b/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp new file mode 100644 index 000000000..b4ad8008c --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThreadStarter.cpp @@ -0,0 +1,125 @@ + + + + + + + + + + + + + +#include "PrtCnvThreadStarter.hpp" +#include "PrtCnvCentralThread.hpp" +#include "PrtCnvRadioThread.hpp" +#include "PrtCnvDbThread.hpp" +#include "PrtCnvTelegramLogThread.hpp" +#include "PrtCnvInjectionThread.hpp" +#include "PrtCnvRadioTrafficThread.hpp" +#include "PrtCnvApplication.hpp" + +namespace PrtCnv +{ + + + + +PrtCnvThreadStarter::PrtCnvThreadStarter(const PrtCnv::PrtCnvApplication::E_ThreadId a_id, + const QString &configFileName, + PrtCnv::PrtCnvApplication* a_mainApp) + : m_Thread(nullptr) + , m_Application(a_mainApp) + , m_Id(a_id) + , m_settings(new NGL::Settings(configFileName)) + , m_logger(getLogger("PrtCnvThreadStarter")) +{ + DEBUG_LOG(m_logger) << "Using Config file '" << configFileName << "'"; +} + + +PrtCnvThreadStarter::~PrtCnvThreadStarter() +{ + delete m_settings; +} + + + + + + +void PrtCnvThreadStarter::run() +{ + INFO_LOG(m_logger) << "Entering event loop for thread " << this << ", id: " << m_Id; + + switch (m_Id) + { + case PrtCnvApplication::e_Central: + m_Thread = new PrtCnvCentralThread(this); + break; + + case PrtCnvApplication::e_Radio: + m_Thread = new PrtCnvRadioThread(m_Application->exerciseId(), this); + break; + + case PrtCnvApplication::e_Db: + m_Thread = new PrtCnvDbThread(m_Application->databaseDriver(), + m_Application->databaseHostName(), + m_Application->databaseName(), + m_Application->databaseSchemaName(), + m_Application->databaseUserName(), + m_Application->databasePassword(), + this); + break; + + case PrtCnvApplication::e_Log: + m_Thread = new PrtCnvTelegramLogThread(this); + break; + + case PrtCnvApplication::e_Injection: + m_Thread = new PrtCnvInjectionThread(this); + break; + + case PrtCnvApplication::e_RadioTraffic: + m_Thread = new PrtCnvRadioTrafficThread(this); + break; + + case PrtCnvApplication::e_ThreadIdMax: + break; + } + + if (!m_Thread) + { + ERROR_LOG(m_logger) << "Unknown threadId: " << m_Id; + return; + } + + while (!m_Application) + sleep(1); + + m_Application->waitForCreate(m_Id); + m_Thread->create(m_settings); + m_Application->waitForInit(m_Id); + m_Thread->init(); + m_Application->waitForStart(m_Id); + m_Thread->start(); + m_Application->waitForExec(m_Id); + + exec(); + + INFO_LOG(m_logger) << "Leaving event loop for thread " << this << ", id: " << m_Id; + delete m_Thread; + m_Thread = nullptr; +} + + + + + +PrtCnvThread *PrtCnvThreadStarter::getOtherThread(PrtCnvApplication::E_ThreadId a_threadId) const +{ + return m_Application->getThreadStarter(a_threadId)->m_Thread; +} + +} diff --git a/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp b/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp new file mode 100644 index 000000000..1b03103b6 --- /dev/null +++ b/TetraIF/PrtCnv/PrtCnvThreadStarter.hpp @@ -0,0 +1,68 @@ + + + + + + + + + + + + + +#pragma once + +#include "PrtCnvApplication.hpp" +#include + +namespace NGL { + class Settings; +} + +namespace PrtCnv +{ + class PrtCnvThread; + + + class PrtCnvThreadStarter : public QThread + { + Q_OBJECT +protected: + + + PrtCnvThread *m_Thread; + + + PrtCnvApplication *m_Application; + + + PrtCnvApplication::E_ThreadId m_Id; + + + NGL::Settings *m_settings; + + + NGL::INGLLogger &m_logger; + + public: + + + PrtCnvThreadStarter(const PrtCnvApplication::E_ThreadId a_id, + const QString &settingsFile, + PrtCnvApplication *a_mainApp); + + ~PrtCnvThreadStarter(); + + PrtCnvThread *getThread() const { return m_Thread; } + PrtCnvApplication *getMainApp() const { return m_Application; } + + + PrtCnvThread *getOtherThread(PrtCnvApplication::E_ThreadId a_threadId) const; + protected: + + + void run() override; + }; + +} diff --git a/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt b/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt new file mode 100644 index 000000000..b70ddfb5a --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/CMakeLists.txt @@ -0,0 +1,29 @@ +SET(tts_SRCS + main.cpp + server.cpp + worker.cpp + + log4cxx_tetratestserver.props +) + +SET(tts_HDRS + server.h + worker.h +) + +NGL_ADD_EXECUTABLE(AAR SV tts ${tts_SRCS} ${tts_HDRS}) +NGL_TARGET_LINK_LIBRARIES(tts + CoPrtCnv + NGLLogger + LtsCommandLineParser + nglsettings + nglcoreapplication + Qt5::Network +) +NGL_INSTALL_TARGET(tts) + +SET(LOG4CXX_PROPS_FILE log4cxx_tetratestserver.props) +NGL_INSTALL(FILES SV ${CMAKE_CURRENT_SOURCE_DIR}/${LOG4CXX_PROPS_FILE} DESTINATION "bin") + + + diff --git a/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props b/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props new file mode 100644 index 000000000..fff09ffca --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/log4cxx_tetratestserver.props @@ -0,0 +1,81 @@ +log4j.reset=true +log4j.rootLogger=WARN, stdout +#log4j.rootLogger=WARN, file, stdout + +log4j.logger.TTWorker=INFO +log4j.logger.TTServer=INFO + + + +# Appnd_File +########################################################### +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}_TetraTestServer.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 %-5p %c{1} |#| %m (%-.30F:%L) %n + +#log4j.appender.stdout.layout.ConversionPattern= %d %-5p %-30c |#| %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=FATAL +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 +# + diff --git a/TetraIF/PrtCnv/TetraTestServer/main.cpp b/TetraIF/PrtCnv/TetraTestServer/main.cpp new file mode 100644 index 000000000..39608ac96 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/main.cpp @@ -0,0 +1,188 @@ + + + +#include +#include +#include +#include +#include +#include + +#include + +#include "server.h" + +int main(int argc, char **argv) +{ + QCoreApplication::setApplicationName(QLatin1String("TTS")); + QCoreApplication::setOrganizationName(QLatin1String("RME")); + NGLCoreApplication app(argc, argv); + + app.createLogger("tts", "log4cxx_tetratestserver.props"); + NGL::INGLLogger &logger = app.baseLogger(); + QScopedPointer settings(new QSettings(app.organizationName(), app.applicationName())); + + ERROR_LOG(logger) << "Settings Directory: " << settings->fileName(); + + LtsCommandLineParser::LtsCommandLineParser options(LtsCommandLineParser::LtsCommandLineParser::CustomConfigFile); + + options.addOption({ QStringList() << QLatin1String("p") << QLatin1String("player") + , QLatin1String("number of players to be simulated.") + , QLatin1String("Default value") + , QLatin1String("5") + }); + + options.addOption({ QStringList() << QLatin1String("n") << QLatin1String("northing") + , QLatin1String("initial position UTM north.") + , QLatin1String("Default value") + , QLatin1String("77777") + }); + + options.addOption({ QStringList() << QLatin1String("e") << QLatin1String("easting") + , QLatin1String("initial position UTM east.") + , QLatin1String("Default value") + , QLatin1String("99999") + }); + + options.addOption({ QStringList() << QLatin1String("f") << QLatin1String("first-id") + , QLatin1String("first equipment ID to use.") + , QLatin1String("Default value") + , QLatin1String("1101") + }); + + options.addOption({ QStringList() << QLatin1String("r") << QLatin1String("pprow") + , QLatin1String("players per row.") + , QLatin1String("Default value") + , QLatin1String("25") + }); + + options.addOption({ QStringList() << QLatin1String("s") << QLatin1String("pspacing") + , QLatin1String("utm based spacing between the players.") + , QLatin1String("Default value") + , QLatin1String("100") + }); + + options.addOption({ QStringList() << QLatin1String("z") << QLatin1String("issi") + , QLatin1String("DestinationIssi / HostISSI") + , QLatin1String("Default value") + , QLatin1String("2") + }); + + options.addOption({ QStringList() << QLatin1String("m") << QLatin1String("movements") + , QLatin1String("how many movements per milliseconds to make.") + , QLatin1String("Default value") + , QLatin1String("2000") + }); + + options.addOption({ QStringList() << QLatin1String("d") << QLatin1String("death") + , QLatin1String("minimum times, after the movements timer is triggered, a dead player can revive.") + , QLatin1String("Default value") + , QLatin1String("100") + }); + + options.addOption({ QStringList() << QLatin1String("o") << QLatin1String("death-offset") + , QLatin1String("maximum times, after the movements timer is triggered, a dead player can revive.") + , QLatin1String("(0 -> identical to min)") + , QLatin1String("0") + }); + + options.addOption({ QStringList() << QLatin1String("t") << QLatin1String("pattern") + , QLatin1String("pattern the player has to walk [enter pattern by hand or pattern alias-name from settings file]\r\nfor more info, enter '--pattern-help'.") + , QLatin1String("Default value") + , QLatin1String("3,30,20#3,30,-20#3,-30,-20#3,-30,20") + }); + + options.addOption({ QStringList() << QLatin1String("demand-old-broadcast-telegrams") + , QLatin1String("player demand old broadcast telegrams starting at BCI ") + , QLatin1String("Default value") + , QLatin1String("0") + }); + + options.addOption({ QStringList() << QLatin1String("deactivate-single-mines") + , QLatin1String("the first player deactivates single mines with ids from minimum-mine-id to maximum-mine-id") + }); + + options.addOption({ QStringList() << QLatin1String("minimum-mine-id") + , QLatin1String("sets the value for minimum-mine-id used within deactivate-single-mines command") + , QLatin1String("Default value") + , QLatin1String("minimum-mine-id 2048") + }); + + options.addOption({ QStringList() << QLatin1String("maximum-mine-id") + , QLatin1String("sets the value for maximum-mine-Id used within deactivate-single-mines command") + , QLatin1String("Default value") + , QLatin1String("maximum-mine-id 2100") + }); + + options.addOption({ QStringList() << QLatin1String("pattern-help") + , QLatin1String("help for the pattern interpreter.") + }); + + + if (!options.init()) + { + options.showHelp(); + return -1; + } + QSettings serverSettings(app.applicationDirPath() + QLatin1String("/") + options.iniFile(), QSettings::IniFormat); + + TTSArgs ttsArgs; + + ttsArgs.destIssi = options.isSet(QLatin1String("issi")) ? options.value(QLatin1String("issi")).toInt() : 2; + ttsArgs.cntPlayer = options.isSet(QLatin1String("player")) ? options.value(QLatin1String("player")).toInt() : 0; + int northPos_arg = options.isSet(QLatin1String("northing")) ? options.value(QLatin1String("northing")).toInt() : 77777; + int eastPos_arg = options.isSet(QLatin1String("easting")) ? options.value(QLatin1String("easting")).toInt() : 90000; + ttsArgs.position = QPointF(eastPos_arg, northPos_arg); + ttsArgs.eqIdStart = options.isSet(QLatin1String("first-id")) ? options.value(QLatin1String("first-id")).toInt() : 1101; + ttsArgs.pprow = options.isSet(QLatin1String("pprow")) ? options.value(QLatin1String("pprow")).toInt() : 25; + ttsArgs.pspacing = options.isSet(QLatin1String("pspacing")) ? options.value(QLatin1String("pspacing")).toInt() : 100; + ttsArgs.movs_per_msec = options.isSet(QLatin1String("movements")) ? options.value(QLatin1String("movements")).toInt() : 2000; + ttsArgs.minimumDeathTicks = options.isSet(QLatin1String("death")) ? options.value(QLatin1String("death")).toInt() : 10; + ttsArgs.maximumDeathTicks = options.isSet(QLatin1String("death-offset")) ? options.value(QLatin1String("death-offset")).toInt() : 20; + ttsArgs.demandOldBraodcastTelegrams = options.isSet(QLatin1String("demand-old-broadcast-telegrams")) ? true : false; + if (ttsArgs.demandOldBraodcastTelegrams) + ttsArgs.demandOldBraodcastTelegramsCounter = options.value(QLatin1String("demand-old-broadcast-telegrams")).toInt(); + ttsArgs.deactivationSingleMines = options.isSet(QLatin1String("deactivate-single-mines")) ? true : false; + ttsArgs.minimumMineId = options.isSet(QLatin1String("minimum-mine-id")) ? options.value(QLatin1String("minimum-mine-id")).toInt() : 2048; + ttsArgs.maximumMineId = options.isSet(QLatin1String("maximum-mine-id")) ? options.value(QLatin1String("maximum-mine-id")).toInt() : 2100; + ttsArgs.pattern = options.isSet(QLatin1String("pattern")) ? options.value(QLatin1String("pattern")) : QLatin1String("3,30,20#3,30,-20#3,-30,-20#3,-30,20"); + + if (options.isSet(QLatin1String("pattern-help"))) + { + options.showHelp(); + return -1; + } + + + if (ttsArgs.maximumDeathTicks == 0) + ttsArgs.maximumDeathTicks = ttsArgs.minimumDeathTicks; + + WARNING_LOG(logger) << "Simulating " << ttsArgs.cntPlayer << " players"; + WARNING_LOG(logger) << " ... DestinationIssi/HostIssi: " << ttsArgs.destIssi; + WARNING_LOG(logger) << " ... on Position n/e: " << ttsArgs.position.y() << "/" << ttsArgs.position.x(); + WARNING_LOG(logger) << " ... first equipmentID is: " << ttsArgs.eqIdStart; + WARNING_LOG(logger) << " ... player is reborn randomly after minimum " << ttsArgs.minimumDeathTicks + << " ticks and maximum " << ttsArgs.maximumDeathTicks << " ticks"; + WARNING_LOG(logger) << " ... pattern = " << ttsArgs.pattern; + WARNING_LOG(logger) << " ... max. " << ttsArgs.pprow << " players per row"; + WARNING_LOG(logger) << " ... spacing of '" << ttsArgs.pspacing << " UTM east' between players"; + WARNING_LOG(logger) << " ... one player will be moved after " << ttsArgs.movs_per_msec << " msecs"; + + TTServer *s = new TTServer(ttsArgs); + + if (!s->listen(QHostAddress::Any, serverSettings.value(QLatin1String("Radio/Port"), 4200).toInt())) + { + ERROR_LOG(logger) << "Error listening on localhost:" << serverSettings.value(QLatin1String("Radio/Port"), 52010).toInt() << ": " + << s->errorString(); + delete s; + return -1; + } + + DEBUG_LOG(logger) << "Starting Server"; + + int ret = app.exec(); + + delete s; + + return ret; +} diff --git a/TetraIF/PrtCnv/TetraTestServer/server.cpp b/TetraIF/PrtCnv/TetraTestServer/server.cpp new file mode 100644 index 000000000..2acb4883b --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/server.cpp @@ -0,0 +1,38 @@ + + +#include "server.h" + +#include +#include + +#include "worker.h" + +TTServer::TTServer(const TTSArgs &ttsArgs) + : m_ttsArgs(ttsArgs) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTServer")) +{ + connect(this, &TTServer::newConnection, + this, &TTServer::onNewConnection); +} + +void TTServer::onNewConnection() +{ + QTcpSocket *sock = nextPendingConnection(); + if (!sock) + return; + NOTICE_LOG(m_logger) << "New incoming connection from " + << sock->peerName() << ":" + << sock->peerPort(); + + TTWorker *ttw = new TTWorker(sock, m_ttsArgs); + if (!ttw->init()) + exit(5); + + connect(sock, &QTcpSocket::disconnected, + this, &TTServer::onDisconnect); +} + +void TTServer::onDisconnect() +{ + NOTICE_LOG(m_logger) << "Disconnected"; +} diff --git a/TetraIF/PrtCnv/TetraTestServer/server.h b/TetraIF/PrtCnv/TetraTestServer/server.h new file mode 100644 index 000000000..9ae8a3087 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/server.h @@ -0,0 +1,54 @@ + + + +#pragma once + +#include +#include +#include +#include +#include + + +struct runningPattern +{ + int steps = 0; + int ethering = 0; + int northering = 0; +}; + +struct TTSArgs +{ + QPointF position; + QString pattern; + QSettings *settings = nullptr; + int destIssi = 0; + unsigned int cntPlayer = 0; + unsigned int eqIdStart = 0; + unsigned int minimumDeathTicks = 0; + unsigned int maximumDeathTicks = 0; + unsigned int pprow = 0; + unsigned int pspacing = 0; + unsigned int movs_per_msec = ~0U; + unsigned int minimumMineId = 0; + unsigned int maximumMineId = 0; + bool demandOldBraodcastTelegrams = false; + int demandOldBraodcastTelegramsCounter = 0; + bool deactivationSingleMines = false; +}; + +class TTServer : public QTcpServer +{ + Q_OBJECT +public: + explicit TTServer(const TTSArgs &m_ttsArgs); + +protected Q_SLOTS: + void onNewConnection(); + void onDisconnect(); + +protected: + TTSArgs m_ttsArgs; + + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/TetraTestServer/tts.txt b/TetraIF/PrtCnv/TetraTestServer/tts.txt new file mode 100644 index 000000000..2c05b75d4 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/tts.txt @@ -0,0 +1,111 @@ +TTS Tetra Test Server: +Das Testprogramm tts wird als Ersatz des Tetra-Server gestartet. Es dient dazu, Lasttests im Gesamtsystem zu starten. +----------------------------------------------- +Teilnehmer anlegen: + +In der Opperator-App in die Übung einloggen +Vorplanung->Teilnehmer Truppe->Bearbeite Teilnehmer +Einen Zug selektieren und Erstellen +Eine Anfangs-Ausstattungsnummer wählen und mit Enter jede Menge Teilnehmer mit aufsteigender Ausstattungsnummererzeugen. +----------------------------------------------- +Verschlüsselung abschalten: +auf dem Server EXCTDS01 die Datei /etc/lts-cc.conf öffnen + +[TrainingAreaBase] +UseTetraScrambling=false + +----------------------------------------------- +Tabelle pdm.pdm_radio_group aendern: +Dazu vorher den Namen der Gruppe herausfinden: +Als Administrator in der Operator App Vorplanung->Übungen->Übungen den Namen der Tetra Gruppe von der aktuellen Übung nehmen. + +Die Einstellungen, die geändert werden vorher aufschreiben, um wieder zum Betrieb mit dem Gefechtsfeld zurückzukommen. +In der Tabelle pdm.pdm_radio_group den Namen "radiohost" auf localhost und issi auf 2 einstellen +In der Tabelle pdm.pdm_radio_group den radio_port auf 4200 einstellen +----------------------------------------------- +Servernamen in PrtCnv.dat ändern +Auf dem Server (EXCTDS01) ala user ctc_sv im Verzeichnis bin die Datei PrtCnv.dat öffnen +[Central] +HostName=localhost +----------------------------------------------- +Serversoftware neu starten +----------------------------------------------- +tts starten: +Auf dem Server (EXCTDS01) ala user ctc_sv im Verzeichnis bin +./tts -p 800 -f 1200 + + Bedeutung: + -p 800 Positionsmeldungen für 800 Teilnehmer erzeugen + -f 1200 Anfangsausstattungsnummer vom Teilnehmer anlegen hier eingeben. + + +----------------------------------------------- +----------------------------------------------- +Relevante Tabellen sind: + 1) tab_prtcnv_member + 2) ex_nn.prtcnv_to_radio + Hier werden die Telegramme (Rtg Gefechtsfeld) zwischengespeichert, bis sie quittiert sind. + +Bei Problemen hat es sich als sinnvoll erwiesen, diese Tabellen zu löschen +----------------------------------------------- +----------------------------------------------- + +----------------------------------------------- +Optionen mit tts --help anzeigen lassen: + +./tts --help +Could not find log4cxx configuration file tetra_log4cxx.props +Using default logging to stdout +2020-09-03 13:19:15.300 ERROR tts |#| Settings Directory: /shd/CTC/TOOLS/.config/RME/TTS.conf (TDS-source/TetraIF/PrtCnv/TetraTestServer/main.cpp:30) +Usage: ./tts [options] + +Options: + -i, --ini Default: /etc/lts-cc.conf + -h, --help Displays this help. + -v, --version Displays version + information. + -p, --player number of players to be + simulated. + -n, --northing initial position UTM north. + -e, --easting initial position UTM east. + -f, --first-id first equipment ID to use. + -r, --pprow players per row. + -s, --pspacing utm based spacing between + the players. + -m, --movements how many movements per + milliseconds to make. + -d, --death minimum times, after the + movements timer is + triggered, a dead player can + revive. + -o, --death-offset <(0 -> identical to min)> maximum times, after the + movements timer is + triggered, a dead player can + revive. + -t, --pattern pattern the player has to + walk [enter pattern by hand + or pattern alias-name from + settings file] + for more info, enter + '--pattern-help'. + --demand-old-broadcast-telegrams player demand old broadcast + telegrams starting at BCI + + --deactivate-single-mines the first player + deactivates single mines + with ids from + minimum-mine-id to + maximum-mine-id + --minimum-mine-id sets the value for + minimum-mine-id used within + deactivate-single-mines + command + --maximum-mine-id sets the value for + maximum-mine-Id used within + deactivate-single-mines + command + --pattern-help help for the pattern + interpreter. + + + diff --git a/TetraIF/PrtCnv/TetraTestServer/worker.cpp b/TetraIF/PrtCnv/TetraTestServer/worker.cpp new file mode 100644 index 000000000..d975df8d4 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/worker.cpp @@ -0,0 +1,645 @@ + + + +#include "worker.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +TTWorker::TTWorker(QTcpSocket *socket, const TTSArgs &ttsArgs) + : m_socket(socket) + , m_timer(new QTimer(this)) + , m_counter(0) + , m_toogle(true) + , m_ttsArgs(ttsArgs) + , m_patternList(interpretPattern(ttsArgs.pattern)) + , m_generalPosition(ttsArgs.position) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTWorker")) +{ + qsrand(time(nullptr)); +} + +bool TTWorker::init() +{ + connect(m_socket, &QTcpSocket::disconnected, + this, &TTWorker::deleteLater); + connect(m_socket, QOverload::of(&QTcpSocket::error), + this, &TTWorker::onSocketError); + connect(m_socket, &QTcpSocket::readyRead, + this, &TTWorker::onReadyRead); + connect(m_timer, &QTimer::timeout, + this, &TTWorker::onSendPlayerPositions); + + if (m_ttsArgs.movs_per_msec < 200) + { + ERROR_LOG(m_logger) << "Invalid value for 'movements per milliseconds'! Please choose a number greater than 200 msecs or equal. Program stopped."; + return false; + } + return true; +} + +void TTWorker::startExecution() +{ + + m_timer->start(m_ttsArgs.movs_per_msec); + NOTICE_LOG(m_logger) << "Start Exe login all Player"; + + for (unsigned int i = 0; i < m_ttsArgs.cntPlayer; i++) + { + int eqId = m_ttsArgs.eqIdStart + i; + int issi = m_ttsArgs.eqIdStart + i + 2000; + QPointF posUTM((m_generalPosition.x() + (i / m_ttsArgs.pprow) * m_ttsArgs.pspacing), + (m_generalPosition.y() + (i % m_ttsArgs.pprow) * m_ttsArgs.pspacing)); + Player *p = new Player(eqId, issi, m_ttsArgs.minimumDeathTicks, m_ttsArgs.maximumDeathTicks, posUTM); + m_playerList.append(p); + + sendLogin(p->eqId, p->issi); + } + + if (m_ttsArgs.deactivationSingleMines) + QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); + + if (m_ttsArgs.demandOldBraodcastTelegrams) + QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); + + + + } + +QVector TTWorker::interpretPattern(QString pattern) const +{ + if (pattern.isEmpty()) + { + ERROR_LOG(m_logger) << "INVALID PATTERN - pattern-size < 1"; + exit(8); + } + + if (pattern.at(0) == QLatin1Char('%')) + { + pattern.remove(0, 1); + + QString patternAlias = pattern; + + pattern = m_ttsArgs.settings->value(QLatin1String("pattern/") + patternAlias).toString(); + + if (pattern.isEmpty()) + { + ERROR_LOG(m_logger) << "INVALID PATTERN - alias '" << patternAlias << "' is not available in settings file! Program halted."; + exit(9); + } + } + + + + if (pattern.at(pattern.count() - 1) == QLatin1Char('#')) + pattern.remove(pattern.count() - 1, 1); + + QVector newPatternList; + runningPattern rp; + QStringList strings = pattern.split(QLatin1Char('#')); + QStringList stringy; + int i; + + for (i = 0; i < strings.count(); i++) + { + stringy = strings.at(i).split(QLatin1Char(',')); + + if (stringy.count() != 3) + break; + + bool ok = true; + + rp.steps = stringy.at(0).toInt(&ok); if (!ok) break; + rp.ethering = stringy.at(1).toInt(&ok); if (!ok) break; + rp.northering = stringy.at(2).toInt(&ok); if (!ok) break; + + newPatternList.append(rp); + + if (i == strings.count() - 1) + return newPatternList; + } + + ERROR_LOG(m_logger) << "INVALID PATTERN: '" << strings.at(i) << "'. Cannot start without correct pattern!"; + + exit(5); + + return QVector(); +} + +void TTWorker::sendLogin(uint32_t eqId, uint32_t issi) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram *tele = new N_CoPrtCnv::CoPrtCnvRadioTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest, eqId, issi); + + DEBUG_LOG(m_logger) << "SEND LOGIN FOR ISSI=" << issi << ", eqId=" << eqId; + sendTelegram(tele, issi); +} + +void TTWorker::onReadyRead() +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; + qint64 bytesRead = m_socket->peek((char *)&header, sizeof(header)); + if (sizeof(header) != bytesRead) + { + DEBUG_LOG(m_logger) << "To few bytes to read from socket"; + return; + } + + if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) + { + ERROR_LOG(m_logger) << "Disconnect because radio-Telegram does not begin with magic-number A5: I got " + << header.m_MagicNumber; + m_socket->disconnectFromHost(); + return; + } + + if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) + { + WARNING_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length + << " - but I proceed with this telegram."; + } + + + uint16_t dataSize = header.m_Length + sizeof(header); + if (m_socket->bytesAvailable() < dataSize) + { + DEBUG_LOG(m_logger) << "not enough bytes available - waiting for more data"; + return; + } + QByteArray buf(dataSize, Qt::Uninitialized); + + bytesRead = 0; + while (bytesRead < dataSize) + { + qint64 br = m_socket->read(&buf.data()[bytesRead], dataSize - bytesRead); + bytesRead += br; + } + handleReceivedTelegram(buf); + + if (m_socket->bytesAvailable()) + QTimer::singleShot(0, this, &TTWorker::onReadyRead); +} + +void TTWorker::handleReceivedTelegram(const QByteArray &data) +{ + INFO_LOG(m_logger) << data.size(); + + switch (data.at(4)) + { + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: + handleRegisterInd(); + startExecution(); + break; + + case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: + handleDataIndReq(data); + + break; + default: + INFO_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << (int)data[4] + << " not implemented!"; + break; + } +} + +void TTWorker::sendTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram, uint32_t issi) +{ + radioTelegram->setZaehler(m_counter++); + radioTelegram->setDestISSI(m_ttsArgs.destIssi); + radioTelegram->setSrcISSI(issi); + + m_socket->write(radioTelegram->data()); + m_socket->flush(); + delete radioTelegram; +} + +void TTWorker::onSendNachforderungBroadcastTelegramm() +{ + Player *p = m_playerList.at(0); + + if (p->isLogin) + { + N_CoPrtCnv::CoPrtCnvRadioTelegram tel(GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME, + 10, p->eqId); + tel.setZaehler(0); + tel.setBroadcastIndex(0); + tel.setDestISSI(m_ttsArgs.destIssi); + tel.setSrcISSI(p->issi); + tel.setPayload4Byte(0); + tel.setPayload1Byte(0); + tel.setPayload2Byte(m_ttsArgs.demandOldBraodcastTelegramsCounter); + m_socket->write(tel.data()); + } + else + QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); +} + +void TTWorker::onSendDeaktivierungEinzelminen() +{ + if (m_playerList.isEmpty()) + { + ERROR_LOG(m_logger) << "No player for onSendDeaktivierungEinzelminen..."; + return; + } + Player *p = m_playerList.at(0); + static unsigned int mineId = m_ttsArgs.minimumMineId; + + NOTICE_LOG(m_logger) << "onSendDeaktivierungEinzelminen " << p->isLogin; + if (p->isLogin) + { + TrainingAreaBase::TetraIcd::MineTriggered tele; + tele.header.equipmentNumber = p->eqId; + tele.header.timeStamp = time(nullptr) * 1000; + tele.mineIndex = mineId++; + tele.mineAreaId = 0; + + sendTelegram(tele, p->issi); + } + + if (mineId <= m_ttsArgs.maximumMineId) + QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void TTWorker::sendTaktischerStatus(uint32_t eqId, uint32_t issi, TrainingAreaBase::TetraIcd::VulnerabilityState vbg) +{ + TrainingAreaBase::TetraIcd::StateChange tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + + tele.tasVitality = 90; + tele.tasVulnerabilityKindId = 459008; + tele.vulnerabilityBits = 0; + + for (Player *p : qAsConst(m_playerList)) + { + if (p->eqId == eqId) + { + p->vbg = vbg; + tele.vulnerabilityState = vbg; + DEBUG_LOG(m_logger) << "Player (" << p->eqId << ") - VBG: " << int(vbg); + break; + } + } + + sendTelegram(tele, issi); +} + +void TTWorker::sendSanitationReport(uint32_t eqId, uint32_t issi) +{ + m_toogle = false; + return; + TrainingAreaBase::TetraIcd::SanitaryMaterialStockReport tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + int matCount = 14; + tele.sanitaryMaterialCount = matCount; + std::vector mat; + mat.reserve(matCount); + for (int i = 1; i <= matCount; i++) + mat.emplace_back(i); + tele.sanitaryMaterialStock = mat; + sendTelegram(tele, issi); + +} + + + + + + + + + + + + + + + + +void TTWorker::sendBITE(uint32_t eqId, uint32_t issi) +{ + TrainingAreaBase::TetraIcd::BiteReport tele; + tele.header.equipmentNumber = eqId; + tele.header.timeStamp = time(nullptr) * 1000; + tele.loginType = TrainingAreaBase::TetraIcd::BiteReport::LoginType::Relogin; + tele.configError = false; + sendTelegram(tele, issi); + sendTaktischerStatus(eqId, issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); +} + +void TTWorker::handleDataIndReq(const QByteArray &data) +{ + QScopedPointer radioTelegram(new N_CoPrtCnv::CoPrtCnvRadioTelegram(data)); + int telID = radioTelegram->getTelID(); + + switch (telID) + { +#if 0 + TODO + case GEF_AUSLOESUNG_DUS_TREFFER: + { + + + DEBUG_LOG(mLogger) << "handleAusloeserDUSTreffer: eqId=" << radioTelegram->getIdentity() << + " issi=" << radioTelegram->getDestISSI(); + + + XDR_Wrapper_it *wrapper = nullptr; + if (!N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(wrapper, radioTelegram.data())) + if (!wrapper) + return; + const ausloesung_dus_treffer_rt &rt_data = static_cast(wrapper)->get_rt(); + + if (rt_data.bek_wirkung > 90) + sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), TOTALAUSFALL); + else + sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), ANNAEHENDER_TREFFER); + delete wrapper; + return; + } +#endif + case GEF_TAKTISCHER_STATUS: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); + TrainingAreaBase::TetraIcd::StateChange sc = TrainingAreaBase::TetraIcd::StateChange::fromJson(tele->jsonData()); + delete tele; + DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; + + sc.header.timeStamp = time(nullptr) * 1000; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + + ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; + sendTelegram(sc, issi); + return; + } + case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: + { + N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); + TrainingAreaBase::TetraIcd::Sanitation sc = TrainingAreaBase::TetraIcd::Sanitation::fromJson(tele->jsonData()); + delete tele; + + DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got procedure: " << sc.proceduresTaken; + + sc.header.timeStamp = time(nullptr) * 1000; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + + ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << sc.proceduresTaken; + sendTelegram(sc, issi); + return; + } + case GEF_TREFFER_AUSLOESUNG: + case GEF_INIT: + { + TrainingAreaBase::TetraIcd::StateChange tele; + uint32_t issi = 0; + for (int i = 0; i < m_playerList.count(); i++) + { + if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) + { + issi = m_playerList.at(i)->issi; + break; + } + } + TrainingAreaBase::TetraIcd::VulnerabilityState state = (telID == GEF_TREFFER_AUSLOESUNG) + ? static_cast(radioTelegram->getPayloadDataUInt8(7)) + : TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady; + + tele.originatorType = TrainingAreaBase::TetraIcd::OriginatorType::Initialisation; + tele.header.equipmentNumber = radioTelegram->getIdentity(); + tele.header.timeStamp = time(nullptr) * 1000; + uint32_t vulcomplete = radioTelegram->getPayloadDataUInt32(8, 2); + uint32_t vitality = vulcomplete &= 0xF000; + vitality >>= 12; + + tele.tasVulnerabilityKindId = vulcomplete &= 0x0FFF; + + tele.tasVulnerabilityKindId <<= 16; + tele.tasVulnerabilityKindId |= 0xB1; + + tele.tasVitality = (vitality - 1) * 10; + if (tele.tasVitality < 0) + tele.tasVitality = 100; + + if (state == TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && vitality > 0) + tele.vulnerabilityState = TrainingAreaBase::TetraIcd::VulnerabilityState::MediumDamage; + else + tele.vulnerabilityState = state; + + sendTelegram(tele, issi); + return; + } + + + + + + + + + + + + } + + + + if (radioTelegram->isLoginTelegram()) + { + + DEBUG_LOG(m_logger) << "player cont: " << m_playerList.count(); + for (int i = 0; i < m_playerList.count(); i++) + { + Player *p = m_playerList.at(i); + if (radioTelegram->getDestISSI() == p->issi) + { + if (p->isLogin) + return; + DEBUG_LOG(m_logger) << "Player #" << i << " with eqId=" << p->eqId << " and issi=" << p->issi << " is now logged in."; + p->isLogin = true; + sendBITE(p->eqId, p->issi); + return; + } + } + + ERROR_LOG(m_logger) << "Invalid player was logged in. issi: '" << radioTelegram->getDestISSI() << "'"; + return; + } + + + DEBUG_LOG(m_logger) << "Received unused or invalid telegram with Telegram-ID: " << telID; +} + +static void fillHeader(char *data, int len) +{ + N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *hdr + = (N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *)data; + hdr->m_MagicNumber = N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER; + hdr->m_Counter = 0; + hdr->m_Length = len; +} + +void TTWorker::handleRegisterInd() +{ + m_counter = 1; + + QByteArray buf; + buf.resize(6); + fillHeader(buf.data(), 2); + buf[4] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp; + buf[5] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered; + + m_socket->write(buf); + + +} + +void TTWorker::movePlayer(Player *p) +{ + + + if (p->patternInList > m_patternList.count() - 1) + p->patternInList = 0; + else + { + if (p->stepInPattern > m_patternList.at(p->patternInList).steps) + { + p->stepInPattern = 1; + if (p->patternInList == m_patternList.count() - 1) + p->patternInList = 0; + else + p->patternInList++; + } + } + + p->posUTM.setX(p->posUTM.x() + + m_patternList.at(p->patternInList).northering); + p->posUTM.setY(p->posUTM.y() + + m_patternList.at(p->patternInList).ethering); + + p->stepInPattern++; +} + +void TTWorker::onSendPlayerPositions() +{ + + qint64 bytesSent = 0; + int playerCount = 0; + TrainingAreaBase::TetraIcd::PositionReport tele; + for (int i = 0; i < m_playerList.count(); i++) + { + Player *p = m_playerList.at(i); + + if (!p->isLogin) + { + INFO_LOG(m_logger) << "Player with eqId=" << p->eqId << " and issi=" << p->issi << " is not logged in."; + break; + } + playerCount++; + + + if (p->vbg != TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && p->isEndOfTicks()) + sendTaktischerStatus(p->eqId, p->issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); + + tele.header.equipmentNumber = p->eqId; + if (m_toogle) + sendSanitationReport(p->eqId, p->issi); + + + movePlayer(p); + tele.relPosition.offsetY = p->posUTM.y(); + tele.relPosition.offsetX = p->posUTM.x(); + + tele.header.timeStamp = time(nullptr) * 1000; + + N_CoPrtCnv::CoPrtCnvCentralTelegram ct(tele); + N_CoPrtCnv::CoPrtCnvRadioTelegram *tel = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(&ct); + tel->setZaehler(m_counter++); + tel->setDestISSI(m_ttsArgs.destIssi); + tel->setSrcISSI(p->issi); + m_socket->write(tel->data()); + bytesSent += tel->getPayloadSize(); + delete tel; + } + bool bFlushed = m_socket->flush(); + INFO_LOG(m_logger) << "Sent " << bytesSent << "bytes (" << playerCount << " players), bFlushed=" << bFlushed; +} + +void TTWorker::onSocketError() +{ + if (m_socket) + m_socket->disconnectFromHost(); +} diff --git a/TetraIF/PrtCnv/TetraTestServer/worker.h b/TetraIF/PrtCnv/TetraTestServer/worker.h new file mode 100644 index 000000000..d59704648 --- /dev/null +++ b/TetraIF/PrtCnv/TetraTestServer/worker.h @@ -0,0 +1,128 @@ + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "server.h" + + +class QTcpSocket; +class QTimer; + +class Player +{ +private: + void randomizeDeathTicks() + { + deathTicks = ((qrand() % (maximumDeathTicks - minimumDeathTicks + 1)) + minimumDeathTicks); + } + +public: + + uint32_t eqId; + uint32_t issi; + QPointF posUTM; + + + bool isLogin; + bool isValidBITE; + TrainingAreaBase::TetraIcd::VulnerabilityState vbg; + + + int patternInList; + int stepInPattern; + + + uint32_t deathTicks; + uint32_t minimumDeathTicks; + uint32_t maximumDeathTicks; + + Player(int eqId_, int issi_, uint32_t minimumDeathTicks_, uint32_t maximumDeathTicks_, const QPointF &posUTM_) + : eqId(eqId_) + , issi(issi_) + , posUTM(posUTM_) + , isLogin(false) + , isValidBITE(false) + , vbg(TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady) + , patternInList(0) + , stepInPattern(1) + , deathTicks(0) + , minimumDeathTicks(minimumDeathTicks_) + , maximumDeathTicks(maximumDeathTicks_) + { + randomizeDeathTicks(); + } + + bool isEndOfTicks() + { + deathTicks--; + if (deathTicks < 1) + { + randomizeDeathTicks(); + return true; + } + return false; + } +}; + +class TTWorker : public QObject +{ + Q_OBJECT + +public: + explicit TTWorker(QTcpSocket *socket, const TTSArgs &ttsArgs); + + bool init(); + +private Q_SLOTS: + void onReadyRead(); + void onSendPlayerPositions(); + + void onSocketError(); + void onSendNachforderungBroadcastTelegramm(); + void onSendDeaktivierungEinzelminen(); + +protected: + void startExecution(); + QVector interpretPattern(QString pattern) const; + void movePlayer(Player *p); + void handleReceivedTelegram(const QByteArray &data); + void handleRegisterInd(); + void handleDataIndReq(const QByteArray &data); + + void sendTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram, uint32_t issi); + template + void sendTelegram(const T &tele, uint32_t issi) + { + N_CoPrtCnv::CoPrtCnvCentralTelegram ct(tele); + sendTelegram(N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(&ct), issi); + } + void sendLogin(uint32_t eqId, uint32_t issi); + void sendBITE(uint32_t eqId, uint32_t issi); + void sendTaktischerStatus(uint32_t eqId, uint32_t issi, TrainingAreaBase::TetraIcd::VulnerabilityState vbg); + void sendSanitationReport(uint32_t eqId, uint32_t issi); + +private: + QTcpSocket *m_socket; + QTimer *m_timer; + QByteArray m_buffer; + unsigned int m_counter; + bool m_toogle; + + TTSArgs m_ttsArgs; + + QVector m_playerList; + QVector m_patternList; + QPointF m_generalPosition; + NGL::INGLLogger &m_logger; +}; diff --git a/TetraIF/PrtCnv/log4cxx_prtcnv.props b/TetraIF/PrtCnv/log4cxx_prtcnv.props new file mode 100644 index 000000000..27f34bc00 --- /dev/null +++ b/TetraIF/PrtCnv/log4cxx_prtcnv.props @@ -0,0 +1,49 @@ +# +# Logger-Config für PrtCnv +# +# $Id$ +# $HeadURL$ +# $Author$ +# +# Aus: grep getNGLLogger * | cut -d \" -f 2 | sort -u +# +log4j.reset=true +#log4j.rootLogger=DEBUG, stdout +log4j.rootLogger=WARN, file + +#log4j.logger.CoPrtCnvCentralTelegram=WARN +#log4j.logger.CoPrtCnvRadioTelegram=WARN +#log4j.logger.CoPrtCnvTelegramConverter=WARN +#log4j.logger.PrtCnvApplication=WARN +#log4j.logger.PrtCnvBroadcastMgr=WARN +#log4j.logger.PrtCnvCentralThread=WARN +#log4j.logger.PrtCnvDbThread=WARN +#log4j.logger.PrtCnvInjectionSocket=WARN +#log4j.logger.PrtCnvInjectionThread=WARN +#log4j.logger.PrtCnvMain=WARN +#log4j.logger.PrtCnvMember=WARN +#log4j.logger.PrtCnvRadioThread=WARN +#log4j.logger.PrtCnvRadioThread.statistic=WARN +#log4j.logger.PrtCnvRadioTrafficThread=WARN +#log4j.logger.PrtCnvStoredCentralTelegram=WARN +#log4j.logger.PrtCnvStoredRadioTelegram=WARN +#log4j.logger.PrtCnvStoredRadioTelegram=WARN +#log4j.logger.PrtCnvTelegramLogThread=WARN +#log4j.logger.PrtCnvThreadStarter=WARN + +# Appender +############ +log4j.appender.file=Lts::RollingFileAppender +log4j.appender.file.MaxFileSize=10MB +log4j.appender.file.MaxBackupIndex=9 +#will be replace by ngllogger +#log4j.appender.file.file=${HOME}/log/PrtCnv.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 %-5p %c |#| %m (%.50F:%L) %n + diff --git a/TetraIF/PrtCnv/logger.cpp b/TetraIF/PrtCnv/logger.cpp new file mode 100644 index 000000000..6bbb33031 --- /dev/null +++ b/TetraIF/PrtCnv/logger.cpp @@ -0,0 +1,30 @@ + + + +#include "logger.h" + +#include + +namespace PrtCnv +{ + +LOGGER_T getLogger(const char *name) +{ + static const char ns[] = "PRT."; + 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(); + } +} + +} diff --git a/TetraIF/PrtCnv/logger.h b/TetraIF/PrtCnv/logger.h new file mode 100644 index 000000000..198d77a70 --- /dev/null +++ b/TetraIF/PrtCnv/logger.h @@ -0,0 +1,18 @@ + + + +#pragma once + +#include + +namespace PrtCnv +{ + +typedef NGL::INGLLogger& LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/Z/src/CMakeLists.txt b/Z/src/CMakeLists.txt new file mode 100755 index 000000000..2ff050a95 --- /dev/null +++ b/Z/src/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +ADD_SUBDIRECTORY(ngldb) +ADD_SUBDIRECTORY(tcpserver) +ADD_SUBDIRECTORY(QtSingleApplication) +ADD_SUBDIRECTORY(WMS_Interface) +ADD_SUBDIRECTORY(nglapplication) +ADD_SUBDIRECTORY(nglcompression) +ADD_SUBDIRECTORY(nglsettings) +ADD_SUBDIRECTORY(ngltranslator) +ADD_SUBDIRECTORY(ngltools) +ADD_SUBDIRECTORY(nglwidgets) +ADD_SUBDIRECTORY(NGLLogger) diff --git a/Z/src/NGLLogger/CMakeLists.txt b/Z/src/NGLLogger/CMakeLists.txt new file mode 100755 index 000000000..ea6074d6f --- /dev/null +++ b/Z/src/NGLLogger/CMakeLists.txt @@ -0,0 +1,50 @@ + +FIND_PACKAGE(Log4Qt REQUIRED) + +# Sourcen +SET(NGLLogger_SRCS + MurmurHash2.cpp + MurmurHash2.h + INGLLogger.h + + NGLLogger_export.h + NGLLoggerBootstrap.cpp + NGLLoggerBootstrap.h + NGLLogger.cpp + NGLLogger.h +) + +# Header +SET(NGLLogger_HDRS +) + +# Make sure NGLLogger.h compiles .. +ADD_DEFINITIONS(-DBUILDING_NGLLOGGER) +NGL_ADD_LIBRARY(ALL NGLLogger SHARED ${NGLLogger_SRCS} ${NGLLogger_HDRS}) +NGL_TARGET_INCLUDE_DIRECTORIES(NGLLogger + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(NGLLogger + PRIVATE + Log4Qt::log4qt + PUBLIC + Qt5::Core +) + +NGL_INSTALL_TARGET(NGLLogger) + +# +# test_ngllogger +# +IF(BUILD_TESTING AND TARGET NGLLogger) + ADD_EXECUTABLE(test_ngllogger test_ngllogger.cpp) + TARGET_LINK_LIBRARIES(test_ngllogger NGLLogger) + TARGET_LINK_LIBRARIES(test_ngllogger + Log4Qt::log4qt + ngltools + ) + ADD_TEST(NAME test_ngllogger COMMAND $) +ENDIF(BUILD_TESTING AND TARGET NGLLogger) + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/log4cxx.props ${CMAKE_BINARY_DIR}/log4cxx.props COPYONLY) diff --git a/Z/src/NGLLogger/INGLLogger.h b/Z/src/NGLLogger/INGLLogger.h new file mode 100755 index 000000000..9bb50cc20 --- /dev/null +++ b/Z/src/NGLLogger/INGLLogger.h @@ -0,0 +1,306 @@ + + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "NGLLogger_export.h" + +namespace NGL +{ +class INGLLogger; + +enum class LogLevel +{ + Undefined = 0, + Trace = 64, + Debug = 96, + Info = 128, + Warning = 150, + Error = 182, + Fatal = 214, +}; + +class LogStreamHelper +{ +public: + inline LogStreamHelper(INGLLogger &logger, LogLevel level, const char *const file, int line, const char *const function) + : m_logger(logger) + , m_level(level) + , m_line(line) + , m_file(file) + , m_func(function) + {} + inline ~LogStreamHelper(); + + template + inline LogStreamHelper &operator<<(const T &val); + +private: + std::ostringstream m_buffer; + NGL::INGLLogger &m_logger; + const LogLevel m_level; + const int m_line; + const char *const m_file; + const char *const m_func; +}; + + + + + + + +class INGLLogger +{ +public: + INGLLogger(const INGLLogger &) = delete; + INGLLogger &operator=(const INGLLogger &) = delete; + INGLLogger() = default; + virtual ~INGLLogger() = default; + + using String = std::string; + + + + + + virtual INGLLogger &getNGLLogger(const char *fullqualifiedname) = 0; + virtual INGLLogger &getNGLLogger(const std::string &fullqualifiedname) = 0; + + + + virtual bool isTraceEnabled() const = 0; + virtual bool isDebugEnabled() const = 0; + virtual bool isInfoEnabled() const = 0; + virtual bool isWarningEnabled() const = 0; + virtual bool isErrorEnabled() const = 0; + virtual bool isFatalEnabled() const = 0; + virtual bool isLevelEnabled(LogLevel level) const = 0; + + + + virtual void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + + virtual void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + virtual void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) = 0; + + + virtual void logStartup(const char *file, int line, const char *function = nullptr) = 0; + + virtual void logShutdown(const char *file, int line, const char *function = nullptr) = 0; + + + virtual std::string getLoggerName() const = 0; + + virtual void setNoSpace(bool bNoSpace) = 0; + virtual bool noSpace() const = 0; +}; + + + + +inline LogStreamHelper::~LogStreamHelper() +{ + m_logger.log(m_level, m_buffer.str(), m_file, m_line, m_func); +} + +template +inline LogStreamHelper &LogStreamHelper::operator<<(const T &val) +{ + m_buffer << val; + if (!m_logger.noSpace()) + m_buffer << " "; + return *this; +} + + +} + +inline std::ostream &operator<<(std::ostream &stream, const QByteArray &str) +{ + stream << std::string(str.data(), str.size()); + return stream; +} + + + + +inline std::ostream &operator<<(std::ostream &stream, + const QPointF &value) +{ + stream << "QPointF(" << QString::number(value.x(), 'f', 6).toStdString() << "#" << QString::number(value.y(), 'f', 6).toStdString() << ")"; + return stream; +} + + + +inline std::ostream &operator<< (std::ostream &stream, + const QPoint &value) +{ + stream << "QPoint(" << value.x() << "#" << value.y() << ")"; + return stream; +} + +inline std::ostream &operator<< (std::ostream &stream, + const QSize &value) +{ + stream << "QSize(w=" << value.width() << ";h=" << value.height() << ")"; + return stream; +} +inline std::ostream &operator<< (std::ostream &stream, + const QSizeF &value) +{ + stream << "QSize(w=" + << QString::number(value.width(), 'f', 6).toStdString() << ";h=" + << QString::number(value.height(), 'f', 6).toStdString() + << ")"; + return stream; +} + + +inline std::ostream &operator<< (std::ostream &stream, + const QRect &value) +{ + stream << "QRect(center=" << value.center() + << " w=" << value.width() + << ";h=" << value.height() + << " bottomLeft=" << value.bottomLeft() + << " topRight=" << value.topRight() + << ")"; + return stream; +} + +inline std::ostream &operator<< (std::ostream &stream, + const QRectF &value) +{ + stream << "QRectF(center=" << value.center() + << " w=" << QString::number(value.width(), 'f', 3).toStdString() + << ";h=" << QString::number(value.height(), 'f', 3).toStdString() + << " bottomLeft=" << value.bottomLeft() + << " topRight=" << value.topRight() + << ")"; + return stream; +} + + + +inline std::ostream &operator<< (std::ostream &stream, + const QList &value) +{ + stream << "QList(" << value.size() << "): "; + for (int i : value) + stream << i << ";"; + return stream; +} + + +inline std::ostream &operator<< (std::ostream &stream, + const QList &value) +{ + stream << "QList(" << value.size() << "): "; + for (const QPointF &item : value) + stream << item << ";"; + return stream; +} + + +inline std::ostream &operator<<(std::ostream &stream, const QString &str) +{ + return stream << str.toUtf8(); +} + +namespace NGL +{ + +namespace NGLLoggerHelper +{ +NGLLOGGER_EXPORT void hexDumpHelper(NGL::INGLLogger &logger, + NGL::LogLevel level, + const void *a_data, + const unsigned int a_size); +inline void hexDumpHelper(NGL::INGLLogger &logger, + NGL::LogLevel level, + const QByteArray &data) +{ + return hexDumpHelper(logger, level, data.data(), data.size()); +} +} + +NGLLOGGER_EXPORT NGL::INGLLogger& getMemoryLogger(); +NGLLOGGER_EXPORT std::string getMemoryData(); + +} + + + + + +#define LOGFUNCTION Q_FUNC_INFO + + +#define NOTICE_LOG(logger) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) + +#ifdef LTS_DEBUG +#define TRACE_LOG(logger) \ + for (bool log_level_enabled = (logger).isTraceEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO) +#else +#define TRACE_LOG(logger) \ + for ( ; false; ) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Trace, __FILE__,__LINE__, Q_FUNC_INFO) +#endif + +#define DEBUG_LOG(logger) \ + for (bool log_level_enabled = (logger).isDebugEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Debug, __FILE__,__LINE__, Q_FUNC_INFO) + +#define INFO_LOG(logger) \ + for (bool log_level_enabled = (logger).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) + +#define WARNING_LOG(logger) \ + for (bool log_level_enabled = (logger).isWarningEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Warning, __FILE__,__LINE__, Q_FUNC_INFO) + +#define ERROR_LOG(logger) \ + for (bool log_level_enabled = (logger).isErrorEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Error, __FILE__,__LINE__, Q_FUNC_INFO) + +#define FATAL_LOG(logger) \ + for (bool log_level_enabled = (logger).isFatalEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(logger, NGL::LogLevel::Fatal, __FILE__,__LINE__, Q_FUNC_INFO) + +#define STARTUP_LOG(logger) { (logger).logStartup(__FILE__, __LINE__, Q_FUNC_INFO); } +#define SHUTDOWN_LOG(logger) { (logger).logShutdown(__FILE__, __LINE__, Q_FUNC_INFO); } + + + + + + + + +#define MEMORY_LOG() \ + for (bool log_level_enabled = (NGL::getMemoryLogger()).isInfoEnabled(); log_level_enabled; log_level_enabled = false) \ + NGL::LogStreamHelper(NGL::getMemoryLogger(), NGL::LogLevel::Info, __FILE__,__LINE__, Q_FUNC_INFO) << NGL::getMemoryData() + + diff --git a/Z/src/NGLLogger/MurmurHash2.cpp b/Z/src/NGLLogger/MurmurHash2.cpp new file mode 100755 index 000000000..8a5ecaeb1 --- /dev/null +++ b/Z/src/NGLLogger/MurmurHash2.cpp @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + +#include "MurmurHash2.h" +#include + +namespace NGL +{ +unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) +{ + + + + const unsigned int m = 0x5bd1e995; + const int r = 24; + + + + unsigned int h = seed ^ len; + + + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + unsigned int k = *(reinterpret_cast(data)); + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + + + switch(len) + { + case 3: h ^= data[2] << 16; + Q_FALLTHROUGH(); + case 2: h ^= data[1] << 8; + Q_FALLTHROUGH(); + case 1: h ^= data[0]; + h *= m; + }; + + + + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} +} diff --git a/Z/src/NGLLogger/MurmurHash2.h b/Z/src/NGLLogger/MurmurHash2.h new file mode 100755 index 000000000..7dc1b579d --- /dev/null +++ b/Z/src/NGLLogger/MurmurHash2.h @@ -0,0 +1,9 @@ + + + +#pragma once + +namespace NGL +{ +unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed = 0 ); +} diff --git a/Z/src/NGLLogger/NGLLogger.cpp b/Z/src/NGLLogger/NGLLogger.cpp new file mode 100755 index 000000000..6dab4f632 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger.cpp @@ -0,0 +1,446 @@ + + + +#include "NGLLogger.h" +#include "MurmurHash2.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace NGL +{ + +void LtsRollingFileAppender::setLtsLogfileName(const QString <sLogfileName) +{ + m_ltsLogfileName = ltsLogfileName; +} + +void LtsRollingFileAppender::activateOptions() +{ + if (!m_ltsLogfileName.isEmpty()) + setFile(m_ltsLogfileName); + Log4Qt::RollingFileAppender::activateOptions(); +} + +QString LtsRollingFileAppender::m_ltsLogfileName; +static Log4Qt::Appender *createLtsRollingFileAppender() +{ + auto ret = new LtsRollingFileAppender; + ret->setAppendFile(true); + return ret; +} + + + + + +class CleanupHelper final +{ +public: + CleanupHelper() = default; + ~CleanupHelper(); + std::mutex &getLoggerMapMutex(); + + std::unordered_map m_loggermap; +protected: + std::mutex m_loggermapmutex; +}; + + + + + +NGL::NGLLogger *NGL::NGLLogger::rootlogger_ptr = nullptr; + +NGL::CleanupHelper NGL::NGLLogger::s_cleanup; + + + + +CleanupHelper::~CleanupHelper() +{ + std::lock_guard lock(m_loggermapmutex); + + for (auto it : m_loggermap) + delete it.second; + m_loggermap.clear(); + + delete NGL::NGLLogger::rootlogger_ptr; + NGL::NGLLogger::rootlogger_ptr = nullptr; +} + +std::mutex &CleanupHelper::getLoggerMapMutex() +{ + return m_loggermapmutex; +} +} + + + + +NGL::NGLLogger::NGLLogger(const std::string &fullqualifiedname) + : name(fullqualifiedname) + , currentLevel(LogLevel::Undefined) + , m_bNoSpace(true) +{ + if (!fullqualifiedname.empty()) + { + logger_ptr = Log4Qt::LogManager::loggerRepository()->logger(QString::fromStdString(name)); + s_cleanup.m_loggermap[MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())] = this; + } + else + { + logger_ptr = Log4Qt::LogManager::loggerRepository()->rootLogger(); + + } + + + configChanged(); +} + + + + + +NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const char *fullqualifiedname) +{ + std::lock_guard lock(s_cleanup.getLoggerMapMutex()); + auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname, strlen(fullqualifiedname))); + if (it != s_cleanup.m_loggermap.end()) + return *(*it).second; + + return *(new NGLLogger(fullqualifiedname)); +} + + + + + +NGL::INGLLogger &NGL::NGLLogger::getNGLLogger(const std::string &fullqualifiedname) +{ + std::lock_guard lock(s_cleanup.getLoggerMapMutex()); + auto it = s_cleanup.m_loggermap.find(MurmurHash2(fullqualifiedname.c_str(), fullqualifiedname.size())); + if (it != s_cleanup.m_loggermap.end()) + return *(*it).second; + + return *(new NGLLogger(fullqualifiedname)); +} + + + + + +void NGL::NGLLogger::log(LogLevel level, const INGLLogger::String &message, const char *file, int line, const char *function) +{ + logger_ptr->logWithLocation(static_cast(level), file, line, function, QString::fromStdString(message)); +} + + + + + +void NGL::NGLLogger::logTrace(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Trace) + log(LogLevel::Trace, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logDebug(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Debug) + log(LogLevel::Debug, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logInfo(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Info) + log(LogLevel::Info, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logWarning(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Warning) + log(LogLevel::Warning, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logError(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + if (currentLevel >= LogLevel::Error) + log(LogLevel::Error, message, file, line, function); +} + + + + + +void NGL::NGLLogger::logFatal(const INGLLogger::String &message, const char *file, int line, const char *function) +{ + log(LogLevel::Fatal, message, file, line, function); +} + + + + +#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 LTS_VERSION_DATE +#define LTS_VERSION_DATE "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_date[] = LTS_VERSION_DATE; +static const char ver_jenkins[] = JENKINS_BUILD_NUMBER; + +void NGL::NGLLogger::logStartup(const char *file, int line, const char *function) +{ + log(LogLevel::Info, QStringLiteral("Application is started (%1.%2-%3 rev%4 from %5)") + .arg(QString::fromLatin1(ver_major), + QString::fromLatin1(ver_minor), + QString::fromLatin1(ver_jenkins), + QString::fromLatin1(ver_patch), + QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function); +} + + + + +void NGL::NGLLogger::logShutdown(const char *file, int line, const char *function) +{ + log(LogLevel::Info, QStringLiteral("Application is shut down (%1.%2-%3 rev%4 from %5)") + .arg(QString::fromLatin1(ver_major), + QString::fromLatin1(ver_minor), + QString::fromLatin1(ver_jenkins), + QString::fromLatin1(ver_patch), + QString::fromLatin1(ver_date)).toUtf8().constData(), file, line, function); +} + + + + + +NGL::NGLLogger &NGL::NGLLogger::getNGLRootLogger() +{ + if (!rootlogger_ptr) throw NotCreatedError(); + return *rootlogger_ptr; +} + + + + +static QString findConfigFile(const QString &configfilename) +{ + if (configfilename.isEmpty()) + return QString(); + + + QFileInfo fi(configfilename); + if (fi.isFile() && fi.isReadable()) + return fi.absoluteFilePath(); + + + QString p = QCoreApplication::applicationDirPath() + QLatin1Char('/') + configfilename; + fi.setFile(p); + if (fi.isFile() && fi.isReadable()) + return fi.absoluteFilePath(); + + return QString(); +} + + + + +NGL::NGLLogger &NGL::NGLLogger::createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName, + bool quiet) +{ + if (rootlogger_ptr) + { + if (!ignorealreadycreated) throw AlreadyCreatedError(); + } + else + { + Log4Qt::Factory::registerAppender("Lts::RollingFileAppender", createLtsRollingFileAppender); + LtsRollingFileAppender::setLtsLogfileName(logOutputName); + + rootlogger_ptr = new NGLLogger(std::string()); + const QString filename = findConfigFile(configfilename); + if (!filename.isEmpty()) + { + Log4Qt::PropertyConfigurator::configureAndWatch(filename); + QObject::connect(Log4Qt::ConfiguratorHelper::instance(), &Log4Qt::ConfiguratorHelper::configurationFileChanged, + []() { configurationFileChanged(); }); + const auto l = Log4Qt::ConfiguratorHelper::instance()->configureError(); + for (const auto &t : l) + std::cerr << t.message().toUtf8().data() << std::endl; + if (!l.isEmpty()) + exit(-1); + } + else + { + if (!quiet) + std::cerr << "Could not find log4cxx configuration file " << configfilename << std::endl + << "Using default logging to stdout" << std::endl; + + + Log4Qt::Properties props; + props.setProperty(QLatin1String("log4j.rootLogger"), + QLatin1String("WARN, stdout")); + props.setProperty(QLatin1String("log4j.appender.stdout"), + QLatin1String("org.apache.log4j.ConsoleAppender")); + props.setProperty(QLatin1String("log4j.appender.stdout.layout"), + QLatin1String("org.apache.log4j.PatternLayout")); + props.setProperty(QLatin1String("log4j.appender.stdout.layout.ConversionPattern"), + QLatin1String("%d %-5p %c |#| %m (%.50F:%L) %n")); + Log4Qt::PropertyConfigurator::configure(props); + } + rootlogger_ptr->configChanged(); + } + return *rootlogger_ptr; +} + +void NGL::NGLLogger::configurationFileChanged() +{ + for (auto ptr : s_cleanup.m_loggermap) + ptr.second->configChanged(); +} + +void NGL::NGLLogger::configChanged() +{ + if (logger_ptr->isTraceEnabled()) + currentLevel = LogLevel::Trace; + else if (logger_ptr->isDebugEnabled()) + currentLevel = LogLevel::Debug; + else if (logger_ptr->isInfoEnabled()) + currentLevel = LogLevel::Info; + else if (logger_ptr->isWarnEnabled()) + currentLevel = LogLevel::Warning; + else if (logger_ptr->isErrorEnabled()) + currentLevel = LogLevel::Error; + else + currentLevel = LogLevel::Fatal; +} + +namespace NGL +{ +namespace NGLLoggerHelper +{ + +void hexDumpHelper(NGL::INGLLogger &logger, NGL::LogLevel level, + const void *a_data, const unsigned int a_size) +{ + if (!logger.isLevelEnabled(level) || !a_data) + return; + + unsigned char *data = (unsigned char *)a_data; + QByteArray baBuf; + for (unsigned int i = 0; i < a_size; i++) + { + if (0 == (i % 8)) + baBuf = QByteArray::number(i, 16).rightJustified(8, '0').toUpper(); + baBuf += " " + QByteArray::number(data[i], 16).rightJustified(2, '0').toUpper(); + if (7 == (i % 8)) + logger.log(level, baBuf.constData(), __FILE__, __LINE__); + } + if (a_size % 8) + logger.log(level, baBuf.constData(), __FILE__, __LINE__); +} + +} + + +NGL::INGLLogger& getMemoryLogger() +{ + try + { + return NGLLogger::getNGLRootLogger().getNGLLogger("memorystate"); + + } + catch (const std::exception &ex) + { + fprintf(stderr, "Error retrieving logger: %s", ex.what()); + abort(); + } +} + +int parseLine(char* line){ + + int i = strlen(line); + const char* p = line; + while (*p <'0' || *p > '9') p++; + line[i-3] = '\0'; + i = atoi(p); + return i; +} + +int getMemoryValue() +{ + + FILE* file = fopen("/proc/self/status", "r"); + int result = -1; + char line[128]; + + while (fgets(line, 128, file) != NULL){ + + if (strncmp(line, "VmRSS:", 6) == 0){ + result = parseLine(line); + break; + } + } + fclose(file); + return result; +} + +std::string getMemoryData() +{ + return QStringLiteral("VmRSS: %1 kB #").arg(QString::number(getMemoryValue())).toStdString(); +} + + +} + + + + diff --git a/Z/src/NGLLogger/NGLLogger.h b/Z/src/NGLLogger/NGLLogger.h new file mode 100755 index 000000000..3d23a46e4 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger.h @@ -0,0 +1,94 @@ + + + +#pragma once + +#ifndef BUILDING_NGLLOGGER +#error Do not include me outside NGLLogger library - only use INGLLogger.h! +#endif + +#include "INGLLogger.h" + +#include + +#include +#include + +namespace NGL +{ + +class CleanupHelper; + +class LtsRollingFileAppender final : public Log4Qt::RollingFileAppender +{ + Q_OBJECT +public: + using Log4Qt::RollingFileAppender::RollingFileAppender; + static void setLtsLogfileName(const QString <sLogfileName); + void activateOptions() override; +private: + static QString m_ltsLogfileName; +}; + +class NGLLogger final : public INGLLogger +{ + explicit NGLLogger(const std::string &fullqualifiedname); +public: + + class NotCreatedError {}; + class AlreadyCreatedError {}; + + INGLLogger &getNGLLogger(const char *fullqualifiedname) override; + INGLLogger &getNGLLogger(const std::string &fullqualifiedname) override; + + inline bool isTraceEnabled() const override { return currentLevel <= LogLevel::Trace; } + inline bool isDebugEnabled() const override { return currentLevel <= LogLevel::Debug; } + inline bool isInfoEnabled() const override { return currentLevel <= LogLevel::Info; } + inline bool isWarningEnabled() const override { return currentLevel <= LogLevel::Warning; } + inline bool isErrorEnabled() const override { return currentLevel <= LogLevel::Error; } + inline bool isFatalEnabled() const override { return currentLevel <= LogLevel::Fatal; } + inline bool isLevelEnabled(LogLevel level) const override { return currentLevel <= level; } + + void log(LogLevel level, const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logTrace(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logDebug(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logInfo(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logWarning(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logError(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + void logFatal(const INGLLogger::String &message, const char *file = nullptr, int line = -1, const char *function = nullptr) override; + + void logStartup(const char *file, int line, const char *function = nullptr) override; + void logShutdown(const char *file, int line, const char *function = nullptr) override; + + inline void setNoSpace(bool bNoSpace) override { m_bNoSpace = bNoSpace; } + inline bool noSpace() const override { return m_bNoSpace; } + + inline std::string getLoggerName() const override { return name; } + + static NGLLogger &getNGLRootLogger(); + static NGLLogger &createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString(), + bool quiet = false); + + Log4Qt::Logger *log4qtLogger() { return logger_ptr; } +protected: + static void configurationFileChanged(); + void configChanged(); + +private: + + Log4Qt::Logger *logger_ptr; + const std::string name; + LogLevel currentLevel; + bool m_bNoSpace; + + static NGLLogger *rootlogger_ptr; + + friend class CleanupHelper; + static CleanupHelper s_cleanup; + + friend class XMLWatchdog; +}; + +} diff --git a/Z/src/NGLLogger/NGLLoggerBootstrap.cpp b/Z/src/NGLLogger/NGLLoggerBootstrap.cpp new file mode 100755 index 000000000..84d8b382f --- /dev/null +++ b/Z/src/NGLLogger/NGLLoggerBootstrap.cpp @@ -0,0 +1,30 @@ + + + +#include "NGLLoggerBootstrap.h" +#include "NGLLogger.h" + + + + + +NGL::INGLLogger & NGL::NGLLoggerBootstrap::getNGLRootLogger() +{ + return NGL::NGLLogger::getNGLRootLogger(); +} + + + + + +NGL::INGLLogger & NGL::NGLLoggerBootstrap::createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName, + bool quiet) +{ + return NGL::NGLLogger::createNGLRootLogger(configfilename, ignorealreadycreated, logOutputName, quiet); +} + + + + diff --git a/Z/src/NGLLogger/NGLLoggerBootstrap.h b/Z/src/NGLLogger/NGLLoggerBootstrap.h new file mode 100755 index 000000000..2b767b522 --- /dev/null +++ b/Z/src/NGLLogger/NGLLoggerBootstrap.h @@ -0,0 +1,59 @@ + + + +#ifndef NGLLOGGERBOOTSTRAP_H +#define NGLLOGGERBOOTSTRAP_H + +#include "INGLLogger.h" +#include "NGLLogger_export.h" + +namespace NGL +{ + +namespace NGLLoggerBootstrap +{ +class AlreadyCreatedError final : public std::exception +{ + const char* what() const noexcept override + { + return "NGLLogger rootlogger already created!"; + } +}; + +class NotCreatedError final : public std::exception +{ + const char* what() const noexcept override + { + return "NGLLogger rootlogger not yet created!"; + } +}; + + + + +NGLLOGGER_EXPORT INGLLogger &getNGLRootLogger(); + + + + + + + + +NGLLOGGER_EXPORT INGLLogger &createNGLRootLogger(const QString &configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString(), + bool quiet = false); +inline INGLLogger &createNGLRootLogger(const char *configfilename, + bool ignorealreadycreated, + const QString &logOutputName = QString()) +{ + return createNGLRootLogger(QString::fromUtf8(configfilename), ignorealreadycreated, logOutputName); +} + +} + +} + + +#endif diff --git a/Z/src/NGLLogger/NGLLogger_export.h b/Z/src/NGLLogger/NGLLogger_export.h new file mode 100755 index 000000000..a998ace10 --- /dev/null +++ b/Z/src/NGLLogger/NGLLogger_export.h @@ -0,0 +1,22 @@ + + +#ifndef NGLLOGGER_EXPORT_H +#define NGLLOGGER_EXPORT_H + +#ifndef NGLLOGGER_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLLOGGER_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLLOGGER_LIB +# define NGLLOGGER_EXPORT __declspec(dllexport) +# else +# define NGLLOGGER_EXPORT __declspec(dllimport) +# endif +# else +# define NGLLOGGER_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif + +#endif diff --git a/Z/src/NGLLogger/log4cxx.props b/Z/src/NGLLogger/log4cxx.props new file mode 100755 index 000000000..210d66b5c --- /dev/null +++ b/Z/src/NGLLogger/log4cxx.props @@ -0,0 +1,42 @@ +log4j.reset=true +log4j.rootLogger=ERROR, stdout + +log4j.logger.Gui=TRACE, console +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%p %d %t %c{1} - %F:%L %m%n + + +log4j.logger.ngs=FATAL, stdout +log4j.logger.ngs.Application_1=INFO, file +log4j.logger.ngs.Application_2=ERROR +log4j.logger.ngs.Application_3=ERROR + +log4j.logger.libsymbol.SymbolTable=WARN, stdout +log4j.logger.libsymbol.SymbolReader=WARN, stdout +log4j.logger.libngldb=INFO, stdout + +log4j.logger.NGL.main=INFO, stdout, file +log4j.logger.NGL.MainWindow=INFO, stdout, file +log4j.logger.NGL.zwmsqt=INFO, stdout, file + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n + +log4j.appender.file=org.apache.log4j.RollingFileAppender +log4j.appender.file.MaxFileSize=1MB +log4j.appender.file.MaxBackupIndex=9 +log4j.appender.file.file=log.out +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=#ngs# %r %p %d %t %c %c{1} - %F:%L %m%n + +log4j.appender.syslog=org.apache.log4j.SyslogAppender +log4j.appender.syslog.Threshold=WARN +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 diff --git a/Z/src/NGLLogger/test_ngllogger.cpp b/Z/src/NGLLogger/test_ngllogger.cpp new file mode 100755 index 000000000..96549d6ea --- /dev/null +++ b/Z/src/NGLLogger/test_ngllogger.cpp @@ -0,0 +1,34 @@ +#include "INGLLogger.h" +#include "NGLLoggerBootstrap.h" +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx.props", false); + + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger(). getNGLLogger( "Gui" ); + + STARTUP_LOG(l); + SHUTDOWN_LOG(l); + NOTICE_LOG(l) << "Gui - NOTICE"; + TRACE_LOG(l) << "Gui - TRACE"; + DEBUG_LOG(l) << "Gui - DEBUG"; + INFO_LOG(l) << "Gui - INFO"; + WARNING_LOG(l) << "Gui - WARNING"; + ERROR_LOG(l) << "Gui - ERROR"; + FATAL_LOG(l) << "Gui - FATAL"; + + NGL::INGLLogger &l2 = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "Gui.AES" ); + NOTICE_LOG(l2) << "Gui.AES - NOTICE"; + TRACE_LOG(l2) << "Gui.AES - TRACE"; + DEBUG_LOG(l2) << "Gui.AES - DEBUG"; + INFO_LOG(l2) << "Gui.AES - INFO"; + WARNING_LOG(l2) << "Gui.AES - WARNING"; + ERROR_LOG(l2) << "Gui.AES - ERROR"; + FATAL_LOG(l2) << "Gui.AES - FATAL"; + SHUTDOWN_LOG(l2) + + return 0; +} diff --git a/Z/src/QtSingleApplication/CMakeLists.txt b/Z/src/QtSingleApplication/CMakeLists.txt new file mode 100755 index 000000000..0159d87b7 --- /dev/null +++ b/Z/src/QtSingleApplication/CMakeLists.txt @@ -0,0 +1,51 @@ +# QtSingleApplication solution from +# http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Utilities/qtsingleapplication +# LGPL + +SET(qtsapp_common_SRCS + qtlocalpeer.cpp + qtlocalpeer.h +) +QT5_WRAP_CPP(qtsapp_common_SRCS qtlockedfile.h) +NGL_ADD_LIBRARY(WS AAR SV qtsa_common STATIC ${qtsapp_common_SRCS}) +NGL_TARGET_LINK_LIBRARIES(qtsa_common + PUBLIC + Qt5::Network + Qt5::Core +) + +SET(qtsapp_SRCS + qtsingleapplication.cpp + qtsingleapplication.h + +) +NGL_ADD_LIBRARY(WS qtsingleapplication SHARED ${qtsapp_SRCS}) +NGL_INSTALL_TARGET(qtsingleapplication) +NGL_TARGET_INCLUDE_DIRECTORIES(qtsingleapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_TARGET_LINK_LIBRARIES(qtsingleapplication + PRIVATE + qtsa_common + PUBLIC + Qt5::Core + Qt5::Widgets +) + +SET(qtscoreapp_SRCS + qtsinglecoreapplication.h + qtsinglecoreapplication.cpp +) +NGL_ADD_LIBRARY(AAR SV qtsinglecoreapplication SHARED ${qtscoreapp_SRCS}) +NGL_INSTALL_TARGET(qtsinglecoreapplication) +NGL_TARGET_INCLUDE_DIRECTORIES(qtsinglecoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_TARGET_LINK_LIBRARIES(qtsinglecoreapplication + PRIVATE + qtsa_common + PUBLIC + Qt5::Core +) diff --git a/Z/src/QtSingleApplication/QtLockedFile b/Z/src/QtSingleApplication/QtLockedFile new file mode 100755 index 000000000..642afda07 --- /dev/null +++ b/Z/src/QtSingleApplication/QtLockedFile @@ -0,0 +1 @@ +#include "qtlockedfile.h" diff --git a/Z/src/QtSingleApplication/QtSingleApplication b/Z/src/QtSingleApplication/QtSingleApplication new file mode 100755 index 000000000..baa6ea94a --- /dev/null +++ b/Z/src/QtSingleApplication/QtSingleApplication @@ -0,0 +1 @@ +#include "qtsingleapplication.h" diff --git a/Z/src/QtSingleApplication/QtSingleCoreApplication b/Z/src/QtSingleApplication/QtSingleCoreApplication new file mode 100755 index 000000000..d247e7528 --- /dev/null +++ b/Z/src/QtSingleApplication/QtSingleCoreApplication @@ -0,0 +1 @@ +#include "qtsinglecoreapplication.h" diff --git a/Z/src/QtSingleApplication/qtlocalpeer.cpp b/Z/src/QtSingleApplication/qtlocalpeer.cpp new file mode 100755 index 000000000..641d5abee --- /dev/null +++ b/Z/src/QtSingleApplication/qtlocalpeer.cpp @@ -0,0 +1,167 @@ + + + + +#include "qtlocalpeer.h" +#include +#include +#include + +#if defined(Q_OS_WIN) +#include +#include +typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); +static PProcessIdToSessionId pProcessIdToSessionId = 0; +#endif +#if defined(Q_OS_UNIX) +#include +#include +#include +#endif + +namespace QtLP_Private { +#include "qtlockedfile.cpp" +#if defined(Q_OS_WIN) +#include "qtlockedfile_win.cpp" +#else +#include "qtlockedfile_unix.cpp" +#endif +} + +const char* QtLocalPeer::ack = "ack"; + +QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + : QObject(parent), id(appId) +{ + QString prefix = id; + if (id.isEmpty()) { + id = QCoreApplication::applicationFilePath(); +#if defined(Q_OS_WIN) + id = id.toLower(); +#endif + prefix = id.section(QLatin1Char('/'), -1); + } + prefix.remove(QRegExp(QLatin1String("[^a-zA-Z]"))); + prefix.truncate(6); + + QByteArray idc = id.toUtf8(); + quint16 idNum = qChecksum(idc.constData(), idc.size()); + socketName = QLatin1String("qtsingleapp-") + prefix + + QLatin1Char('-') + QString::number(idNum, 16); + +#if defined(Q_OS_WIN) + if (!pProcessIdToSessionId) { + QLibrary lib(QLatin1String("kernel32")); + pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); + } + if (pProcessIdToSessionId) { + DWORD sessionId = 0; + pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += QLatin1Char('-') + QString::number(sessionId, 16); + } +#else + socketName += QLatin1Char('-') + QString::number(::getuid(), 16); +#endif + + server = new QLocalServer(this); + QString lockName = QDir(QDir::tempPath()).absolutePath() + + QLatin1Char('/') + socketName + + QLatin1String("-lockfile"); + lockFile.setFileName(lockName); + lockFile.open(QIODevice::ReadWrite); +} + + + +bool QtLocalPeer::isClient() +{ + if (lockFile.isLocked()) + return false; + + if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) + return true; + + bool res = server->listen(socketName); +#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) + + if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { + QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); + res = server->listen(socketName); + } +#endif + if (!res) + qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); + QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); + return false; +} + + +bool QtLocalPeer::sendMessage(const QString &message, int timeout) +{ + if (!isClient()) + return false; + + QLocalSocket socket; + bool connOk = false; + for(int i = 0; i < 2; i++) { + + socket.connectToServer(socketName); + connOk = socket.waitForConnected(timeout/2); + if (connOk || i) + break; + int ms = 250; +#if defined(Q_OS_WIN) + Sleep(DWORD(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, nullptr); +#endif + } + if (!connOk) + return false; + + QByteArray uMsg(message.toUtf8()); + QDataStream ds(&socket); + ds.writeBytes(uMsg.constData(), uMsg.size()); + bool res = socket.waitForBytesWritten(timeout); + if (res) { + res &= socket.waitForReadyRead(timeout); + if (res) + res &= (socket.read(qstrlen(ack)) == ack); + } + return res; +} + + +void QtLocalPeer::receiveConnection() +{ + QLocalSocket* socket = server->nextPendingConnection(); + if (!socket) + return; + + while (socket->bytesAvailable() < (int)sizeof(quint32)) + socket->waitForReadyRead(); + QDataStream ds(socket); + QByteArray uMsg; + quint32 remaining; + ds >> remaining; + uMsg.resize(remaining); + int got = 0; + char* uMsgBuf = uMsg.data(); + do { + got = ds.readRawData(uMsgBuf, remaining); + remaining -= got; + uMsgBuf += got; + } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); + if (got < 0) { + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); + delete socket; + return; + } + QString message(QString::fromUtf8(uMsg)); + socket->write(ack, qstrlen(ack)); + socket->waitForBytesWritten(1000); + socket->waitForDisconnected(1000); + delete socket; + emit messageReceived(message); +} diff --git a/Z/src/QtSingleApplication/qtlocalpeer.h b/Z/src/QtSingleApplication/qtlocalpeer.h new file mode 100755 index 000000000..3b745167a --- /dev/null +++ b/Z/src/QtSingleApplication/qtlocalpeer.h @@ -0,0 +1,40 @@ + + + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qtlockedfile.h" + +class QtLocalPeer : public QObject +{ + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString()); + bool isClient(); + bool sendMessage(const QString &message, int timeout); + QString applicationId() const + { return id; } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif diff --git a/Z/src/QtSingleApplication/qtlockedfile.cpp b/Z/src/QtSingleApplication/qtlockedfile.cpp new file mode 100755 index 000000000..2306c2833 --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile.cpp @@ -0,0 +1,68 @@ + + + +#include "qtlockedfile.h" + + + + + + + + + +QtLockedFile::QtLockedFile() + : QFile() +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + + + +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + + + +bool QtLockedFile::open(OpenMode mode) +{ + if (mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + + + +bool QtLockedFile::isLocked() const +{ + return m_lock_mode != NoLock; +} + + + +QtLockedFile::LockMode QtLockedFile::lockMode() const +{ + return m_lock_mode; +} + + + + + + + + + diff --git a/Z/src/QtSingleApplication/qtlockedfile.h b/Z/src/QtSingleApplication/qtlockedfile.h new file mode 100755 index 000000000..0b33d7a2a --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile.h @@ -0,0 +1,61 @@ + + + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ + Q_OBJECT +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + explicit QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/Z/src/QtSingleApplication/qtlockedfile_unix.cpp b/Z/src/QtSingleApplication/qtlockedfile_unix.cpp new file mode 100755 index 000000000..67fcd0727 --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile_unix.cpp @@ -0,0 +1,78 @@ + + + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/Z/src/QtSingleApplication/qtlockedfile_win.cpp b/Z/src/QtSingleApplication/qtlockedfile_win.cpp new file mode 100755 index 000000000..d4f97687e --- /dev/null +++ b/Z/src/QtSingleApplication/qtlockedfile_win.cpp @@ -0,0 +1,174 @@ + + + +#include "qtlockedfile.h" +#include +#include + +#define MUTEX_PREFIX "QtLockedFile mutex " + +#define MAX_READERS MAXIMUM_WAIT_OBJECTS + +#if QT_VERSION >= 0x050000 +#define QT_WA(unicode, ansi) unicode +#endif + +Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) +{ + if (mutexname.isEmpty()) { + QFileInfo fi(*this); + mutexname = QString::fromLatin1(MUTEX_PREFIX) + + fi.absoluteFilePath().toLower(); + } + QString mname(mutexname); + if (idx >= 0) + mname += QString::number(idx); + + Qt::HANDLE mutex; + if (doCreate) { + QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); + return 0; + } + } + else { + QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); + return 0; + } + } + return mutex; +} + +bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock) +{ + Q_ASSERT(mutex); + DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0); + switch (res) { + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + return true; + break; + case WAIT_TIMEOUT: + break; + default: + qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed"); + } + return false; +} + + + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + if (!wmutex && !(wmutex = getMutexHandle(-1, true))) + return false; + + if (!waitMutex(wmutex, block)) + return false; + + if (mode == ReadLock) { + int idx = 0; + for (; idx < MAX_READERS; idx++) { + rmutex = getMutexHandle(idx, false); + if (!rmutex || waitMutex(rmutex, false)) + break; + CloseHandle(rmutex); + } + bool ok = true; + if (idx >= MAX_READERS) { + qWarning("QtLockedFile::lock(): too many readers"); + rmutex = 0; + ok = false; + } + else if (!rmutex) { + rmutex = getMutexHandle(idx, true); + if (!rmutex || !waitMutex(rmutex, false)) + ok = false; + } + if (!ok && rmutex) { + CloseHandle(rmutex); + rmutex = 0; + } + ReleaseMutex(wmutex); + if (!ok) + return false; + } + else { + Q_ASSERT(rmutexes.isEmpty()); + for (int i = 0; i < MAX_READERS; i++) { + Qt::HANDLE mutex = getMutexHandle(i, false); + if (mutex) + rmutexes.append(mutex); + } + if (rmutexes.size()) { + DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), + TRUE, block ? INFINITE : 0); + if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) { + if (res != WAIT_TIMEOUT) + qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed"); + m_lock_mode = WriteLock; + unlock(); + return false; + } + } + } + + m_lock_mode = mode; + return true; +} + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + if (m_lock_mode == ReadLock) { + ReleaseMutex(rmutex); + CloseHandle(rmutex); + rmutex = 0; + } + else { + for (Qt::HANDLE mutex : qAsConst(rmutexes)) { + ReleaseMutex(mutex); + CloseHandle(mutex); + } + rmutexes.clear(); + ReleaseMutex(wmutex); + } + + m_lock_mode = QtLockedFile::NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); + if (wmutex) + CloseHandle(wmutex); +} diff --git a/Z/src/QtSingleApplication/qtsingleapplication.cpp b/Z/src/QtSingleApplication/qtsingleapplication.cpp new file mode 100755 index 000000000..b3a70c2ca --- /dev/null +++ b/Z/src/QtSingleApplication/qtsingleapplication.cpp @@ -0,0 +1,104 @@ + + + + +#include "qtsingleapplication.h" +#include "qtlocalpeer.h" +#include + + + + + + +void QtSingleApplication::sysInit(const QString &appId) +{ + actWin = nullptr; + peer = new QtLocalPeer(this, appId); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived); +} + + + + + +QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) + : QApplication(argc, argv, GUIenabled) +{ + sysInit(); +} + + + + + +QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) + : QApplication(argc, argv) +{ + sysInit(appId); +} + + + + +bool QtSingleApplication::isRunning() +{ + return peer->isClient(); +} + + + + +bool QtSingleApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + + + +QString QtSingleApplication::id() const +{ + return peer->applicationId(); +} + + + + + +void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) +{ + actWin = aw; + if (activateOnMessage) + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); + else + disconnect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); +} + + + + +QWidget* QtSingleApplication::activationWindow() const +{ + return actWin; +} + + + + +void QtSingleApplication::activateWindow() +{ + if (actWin) { + actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); + actWin->raise(); + actWin->activateWindow(); + } +} + + + + + + + + diff --git a/Z/src/QtSingleApplication/qtsingleapplication.h b/Z/src/QtSingleApplication/qtsingleapplication.h new file mode 100755 index 000000000..82f3507f7 --- /dev/null +++ b/Z/src/QtSingleApplication/qtsingleapplication.h @@ -0,0 +1,56 @@ + + + +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H + +#include + +class QtLocalPeer; + +#ifndef QTSINGLEAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define QTSINGLEAPPLICATION_EXPORT +# else +# if defined(MAKE_QTSINGLEAPPLICATION_LIB) +# define QTSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define QTSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +class QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication +{ + Q_OBJECT + +public: + QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); + QtSingleApplication(const QString &appId, int &argc, char **argv); + + bool isRunning(); + QString id() const; + + void setActivationWindow(QWidget* aw, bool activateOnMessage = true); + QWidget* activationWindow() const; + + + void initialize(bool dummy = true) + { isRunning(); Q_UNUSED(dummy) } + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + void activateWindow(); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + void sysInit(const QString &appId = QString()); + QtLocalPeer *peer; + QWidget *actWin; +}; + +#endif diff --git a/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp b/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp new file mode 100755 index 000000000..7c9cc883d --- /dev/null +++ b/Z/src/QtSingleApplication/qtsinglecoreapplication.cpp @@ -0,0 +1,60 @@ + + + + +#include "qtsinglecoreapplication.h" +#include "qtlocalpeer.h" + + + + + + + +QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + peer = new QtLocalPeer(this); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived); +} + + + + +QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + peer = new QtLocalPeer(this, appId); + connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleCoreApplication::messageReceived); +} + + + + + +bool QtSingleCoreApplication::isRunning() +{ + return peer->isClient(); +} + + + + + +bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + + + + +QString QtSingleCoreApplication::id() const +{ + return peer->applicationId(); +} + + + + diff --git a/Z/src/QtSingleApplication/qtsinglecoreapplication.h b/Z/src/QtSingleApplication/qtsinglecoreapplication.h new file mode 100755 index 000000000..8c23f3ab8 --- /dev/null +++ b/Z/src/QtSingleApplication/qtsinglecoreapplication.h @@ -0,0 +1,46 @@ + + + +#ifndef QTSINGLECOREAPPLICATION_H +#define QTSINGLECOREAPPLICATION_H + +#include + +class QtLocalPeer; + +#ifndef QTSINGLECOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define QTSINGLEAPPLICATION_EXPORT +# else +# if defined(MAKE_QTSINGLECOREAPPLICATION_LIB) +# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define QTSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +class QTSINGLECOREAPPLICATION_EXPORT QtSingleCoreApplication : public QCoreApplication +{ + Q_OBJECT + +public: + QtSingleCoreApplication(int &argc, char **argv); + QtSingleCoreApplication(const QString &appId, int &argc, char **argv); + + bool isRunning(); + QString id() const; + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + QtLocalPeer* peer; +}; + +#endif diff --git a/Z/src/WMS_Interface/CMakeLists.txt b/Z/src/WMS_Interface/CMakeLists.txt new file mode 100755 index 000000000..3700fc0d8 --- /dev/null +++ b/Z/src/WMS_Interface/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + + +SET(wms_ds_SRCS + IECC2WMS.h + IWMS2ECC.h + wms_ecc_equipmenttypes.cpp + wms_ecc_equipmenttypes.h + wms_ecc_equipRequirements.cpp + wms_ecc_equipRequirements.h + wms_ecc_exercises.cpp + wms_ecc_exercises.h + wms_ecc_ibase.h + wms_ecc_playerInfo.cpp + wms_ecc_playerInfo.h + wms_ecc_registration.cpp + wms_ecc_registration.h + wms_ecc_unregister.cpp + wms_ecc_unregister.h + json_keys.h + ) + +NGL_ADD_LIBRARY2(AAR SV wms_json_ds SHARED ${wms_ds_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(wms_json_ds + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ) +NGL_TARGET_LINK_LIBRARIES(wms_json_ds + PUBLIC + Qt5::Core + ) diff --git a/Z/src/WMS_Interface/IECC2WMS.h b/Z/src/WMS_Interface/IECC2WMS.h new file mode 100755 index 000000000..4dd163a06 --- /dev/null +++ b/Z/src/WMS_Interface/IECC2WMS.h @@ -0,0 +1,20 @@ + + + +#pragma once + +namespace WmsJson +{ +class IECC2WMS +{ + +public: + IECC2WMS() = default; + virtual ~IECC2WMS() = default; + + + virtual void playerChanged(int playerId, int exerciseId) = 0; + virtual void exerciseDataChanged(int exerciseId, int betrZustand) = 0; + +}; +} diff --git a/Z/src/WMS_Interface/IWMS2ECC.h b/Z/src/WMS_Interface/IWMS2ECC.h new file mode 100755 index 000000000..c91fa42f3 --- /dev/null +++ b/Z/src/WMS_Interface/IWMS2ECC.h @@ -0,0 +1,137 @@ + + +#pragma once + +#include +#include +#include +#include + +class IWMS2ECC +{ + +public: + IWMS2ECC() = default; + virtual ~IWMS2ECC() = default; + + enum RegisterReturnValue + { + RegistrationOk = 0, + PlayerNotFound = 1, + PlayerDeleted = 2, + AssignmentIncorrect = 3, + EquipNoAlreadyAssigned = 4, + RegistrationFailed = 5 + }; + + enum UnregisterReturnValue + { + UnregisterOk = 0, + EquipNoNotFound = 1, + UnregisterFailed = 2 + }; + + enum PlayerState + { + NOT_FOUND = 0, + FOUND = 1, + DELETED = 2 + }; + + enum PlayerAssignState + { + UNDEFINED = -2, + NOT_ASSIGNED = -1, + ASSIGNED = 0, + HANDOUT_EXCON = 1, + HANDOUT_WMS = 2, + HANDOUT_EXCON_OVERRULED_WMS = 3 + }; + static inline PlayerAssignState int2PlayerAssignState(int s) + { + switch (s) + { + case UNDEFINED: + case NOT_ASSIGNED: + case ASSIGNED: + case HANDOUT_EXCON: + case HANDOUT_WMS: + case HANDOUT_EXCON_OVERRULED_WMS: + return static_cast(s); + } + Q_ASSERT(false); + return UNDEFINED; + } + + struct PlayerInfo + { + PlayerState playerState = NOT_FOUND; + int playerId = -1; + int parentPlayerId = -1; + int equipNo = -1; + PlayerAssignState assignState = UNDEFINED; + int exerciseId = -1; + int forceId = -1; + int typeId = -1; + int equipTypeId = -1; + int typeClassId = -1; + int symbolColor = -1; + bool isDeleted = false; + QByteArray symbolPNG; + QString hierarchy; + QString designator; + QString tactIdent; + QString info; + QString alias; + QString forceName; + }; + + struct Exercise + { + int id = -1; + int actExercise = 0; + time_t start = 0; + time_t end = 0; + QString name; + QString stateAsString; + }; + using exerciseMap = QMap; + + struct EquipmentType + { + QString name; + int id = 0; + int specialType = 0; + int minEquipNo = 0; + int maxEquipNo = 0; + int taVulnerabilityModelId = 0; + int taPlayerTypeId = 0; + bool deletedInWMS = false; + }; + using equipTypeMap = QMap; + + + virtual RegisterReturnValue registerPlayer(int playerId, int equipNo, const PlayerAssignState &zuordnung, const QString &alias, + const QString &info, int exerciseId) = 0; + + virtual UnregisterReturnValue unregister(int equipNo, int exerciseId) = 0; + virtual PlayerInfo getPlayerInfo(int playerId, int exerciseId) = 0; + + virtual exerciseMap getExercises() const = 0; + virtual Exercise getActualExercise() const = 0; + + + virtual QMap getEquipRequirements(int exerciseId) const = 0; + + virtual QMap getAllPlayers(int exerciseId) const = 0; + virtual QMap getAllVehicles(int exerciseId) const = 0; + + virtual int getPlayerId(int equipNo, int exerciseId) const = 0; + virtual int getEquipNo(int playerId, int exerciseId) const = 0; + + virtual int getTypeClassId(int equipTypeId) const = 0; +}; + +Q_DECLARE_METATYPE(IWMS2ECC::Exercise) +Q_DECLARE_METATYPE(IWMS2ECC::EquipmentType) +Q_DECLARE_METATYPE(IWMS2ECC::RegisterReturnValue) diff --git a/Z/src/WMS_Interface/json_keys.h b/Z/src/WMS_Interface/json_keys.h new file mode 100755 index 000000000..90d147efb --- /dev/null +++ b/Z/src/WMS_Interface/json_keys.h @@ -0,0 +1,52 @@ + + +#pragma once + +#include + +namespace WebSocketInterface +{ + + +namespace JsonKeys +{ + +inline QString EXERCISE_ID() { return QStringLiteral("exerciseId"); } +inline QString DATA_MODIFICATION() { return QStringLiteral("dataModification"); } +inline QString PARTICIPANT_ID() { return QStringLiteral("participantId"); } +inline QString REGISTRATION_RETURN_VALUE() { return QStringLiteral("registrationReturnValue"); } + + +inline QString EQUIPMENT_TYPES_REQUEST() { return QStringLiteral("equipmentTypesRequest"); } + + +inline QString EQUIPMENT_TYPES_REPLY() { return QStringLiteral("equipmentTypesReply"); } + + +inline QString EXERCISES_REQUEST() { return QStringLiteral("exercisesRequest"); } + + +inline QString EXERCISES_REPLY() { return QStringLiteral("exercisesReply"); } + + +inline QString EXERCISE_UPDATE() { return QStringLiteral("exercisesUpdate"); } + + +inline QString PARTICIPANTS_REQUEST() { return QStringLiteral("participantsRequest"); } + + +inline QString PARTICIPANTS_REPLY() { return QStringLiteral("participantsReply"); } + + +inline QString PARTICIPANTS_UPDATE() { return QStringLiteral("participantsUpdate"); } + + +inline QString PARTICIPANT_REGISTER_IN_EXCON_REQUEST() { return QStringLiteral("participantRegisterInEXCONRequest");} + + +inline QString PARTICIPANT_REGISTER_IN_EXCON_REPLY() { return QStringLiteral("participantRegisterInEXCONReply");} + + + +} +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp b/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp new file mode 100755 index 000000000..1eb29d300 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipRequirements.cpp @@ -0,0 +1,71 @@ + + + +#include "wms_ecc_equipRequirements.h" +#include +#include + +QJsonObject EquipRequirements::toJson() const +{ + QJsonArray arr; + for (QMap::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it) + { + QJsonObject obj; + obj[QLatin1String("key")] = it.key(); + obj[QLatin1String("value")] = it.value(); + arr.append(obj); + } + + QJsonObject retMap; + retMap[QLatin1String("equipMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +EquipRequirements EquipRequirements::fromJson(const QJsonObject &map) +{ + EquipRequirements eq; + + const QJsonArray arr = map[QLatin1String("equipMap")].toArray(); + for (const auto &ele : arr) + { + const QJsonObject obj = ele.toObject(); + int equipmentTypeId = obj[QLatin1String("key")].toInt(); + int amount = obj[QLatin1String("value")].toInt(); + eq.m_equipRequire.insert(equipmentTypeId, amount); + } + + eq.m_ok = map[QLatin1String("ok")].toBool(); + + return eq; +} + +QVariantMap EquipRequirements::toVariantMap() const +{ + QVariantMap viMap; + for (QMap::ConstIterator it = m_equipRequire.begin(); it != m_equipRequire.end(); ++it) + viMap.insert(QString::number(it.key()), QVariant(it.value())); + + QVariantMap retMap; + retMap[QLatin1String("equipMap")] = QVariant(viMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +EquipRequirements EquipRequirements::fromVariantMap(const QVariantMap &map) +{ + EquipRequirements eq; + + const QVariantMap viMap = map[QLatin1String("equipMap")].toMap(); + for (QVariantMap::ConstIterator it = viMap.begin(); it != viMap.end(); ++it) + { + const int key = it.key().toInt(); + eq.m_equipRequire.insert(key, it.value().toInt()); + } + + eq.m_ok = map[QLatin1String("ok")].toBool(); + + return eq; +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipRequirements.h b/Z/src/WMS_Interface/wms_ecc_equipRequirements.h new file mode 100755 index 000000000..9a9f25e4f --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipRequirements.h @@ -0,0 +1,30 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + +class WMS_JSON_DS_EXPORT EquipRequirements : public IBase +{ +public: + QJsonObject toJson() const; + static EquipRequirements fromJson(const QJsonObject &map); + + QVariantMap toVariantMap() const; + static EquipRequirements fromVariantMap(const QVariantMap &map); + + + QMap getEquipRequirements() const { return m_equipRequire; } + bool getOk() const { return m_ok; } + + void setEquipRequirements(const QMap &equip) { m_equipRequire = equip; } + void setOk(bool ok) { m_ok = ok; } + +private: + QMap m_equipRequire; + bool m_ok = false; +}; diff --git a/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp new file mode 100755 index 000000000..f66025f9d --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.cpp @@ -0,0 +1,132 @@ + + + +#include "wms_ecc_equipmenttypes.h" +#include + +QJsonObject EquipmentTypes::toJson(const IWMS2ECC::EquipmentType &et) +{ + QJsonObject obj; + + obj[QLatin1String("id")] = et.id; + obj[QLatin1String("name")] = et.name; + obj[QLatin1String("minEquipNo")] = et.minEquipNo; + obj[QLatin1String("maxEquipNo")] = et.maxEquipNo; + obj[QLatin1String("specialType")] = et.specialType; + obj[QLatin1String("taVulnerabilityModelId")] = et.taVulnerabilityModelId; + obj[QLatin1String("taPlayerTypeId")] = et.taPlayerTypeId; + obj[QLatin1String("deletedInWMS")] = et.deletedInWMS; + + return obj; +} + +IWMS2ECC::EquipmentType EquipmentTypes::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::EquipmentType et; + + et.id = obj[QLatin1String("id")].toInt(); + et.name = obj[QLatin1String("name")].toString(); + et.minEquipNo = obj[QLatin1String("minEquipNo")].toInt(); + et.maxEquipNo = obj[QLatin1String("maxEquipNo")].toInt(); + et.specialType = obj[QLatin1String("specialType")].toInt(); + et.taVulnerabilityModelId = obj[QLatin1String("taVulnerabilityModelId")].toInt(); + et.taPlayerTypeId = obj[QLatin1String("taPlayerTypeId")].toInt(); + et.deletedInWMS = obj[QLatin1String("deletedInWMS")].toBool(); + + return et; +} + +QJsonObject EquipmentTypes::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::EquipmentType &et : m_equipmentTypes) + arr.append(toJson(et)); + + QJsonObject retMap; + retMap[QLatin1String("etMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +EquipmentTypes EquipmentTypes::fromJsonAll(const QJsonObject &map) +{ + EquipmentTypes ets; + + const QJsonArray arr = map[QLatin1String("etMap")].toArray(); + for (const auto &ele : arr) + { + const IWMS2ECC::EquipmentType val = fromJson(ele.toObject()); + ets.m_equipmentTypes.insert(val.id, val); + } + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} + + +QVariantMap EquipmentTypes::toVariantMap() const +{ + QVariantMap vMap; + + vMap[QLatin1String("id")] = QVariant(m_equipmentType.id); + vMap[QLatin1String("name")] = m_equipmentType.name; + vMap[QLatin1String("minEquipNo")] = QVariant((int)m_equipmentType.minEquipNo); + vMap[QLatin1String("maxEquipNo")] = QVariant((int)m_equipmentType.maxEquipNo); + vMap[QLatin1String("specialType")] = QVariant(m_equipmentType.specialType); + vMap[QLatin1String("deletedInWMS")] = QVariant(m_equipmentType.deletedInWMS); + + vMap[QLatin1String("ok")] = QVariant(m_ok); + + return vMap; +} + +EquipmentTypes EquipmentTypes::fromVariantMap(const QVariantMap &map) +{ + EquipmentTypes ets; + + ets.m_equipmentType.id = map[QLatin1String("id")].toInt(); + ets.m_equipmentType.name = map[QLatin1String("name")].toString(); + ets.m_equipmentType.minEquipNo = map[QLatin1String("minEquipNo")].toInt(); + ets.m_equipmentType.maxEquipNo = map[QLatin1String("maxEquipNo")].toInt(); + ets.m_equipmentType.specialType = map[QLatin1String("specialType")].toInt(); + ets.m_equipmentType.deletedInWMS = map[QLatin1String("deletedInWMS")].toBool(); + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} + +QVariantMap EquipmentTypes::toVariantMapAll() const +{ + QVariantMap vMap; + for (IWMS2ECC::equipTypeMap::ConstIterator it = m_equipmentTypes.begin(); it != m_equipmentTypes.end(); ++it) + { + m_equipmentType = it.value(); + vMap.insert(QString::number(it.key()), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("etMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +EquipmentTypes EquipmentTypes::fromVariantMapAll(const QVariantMap &map) +{ + EquipmentTypes ets; + + const QVariantMap vMap = map[QLatin1String("etMap")].toMap(); + for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it) + { + int key = it.key().toInt(); + IWMS2ECC::EquipmentType et = EquipmentTypes::fromVariantMap(it.value().toMap()).m_equipmentType; + ets.m_equipmentTypes.insert(key, et); + } + + ets.m_ok = map[QLatin1String("ok")].toBool(); + + return ets; +} diff --git a/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h new file mode 100755 index 000000000..67cde3778 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_equipmenttypes.h @@ -0,0 +1,37 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include +#include + +class WMS_JSON_DS_EXPORT EquipmentTypes : public IBase +{ +public: + QJsonObject toJsonAll() const; + static EquipmentTypes fromJsonAll(const QJsonObject &map); + static QJsonObject toJson(const IWMS2ECC::EquipmentType &et); + static IWMS2ECC::EquipmentType fromJson(const QJsonObject &obj); + + QVariantMap toVariantMapAll() const; + static EquipmentTypes fromVariantMapAll(const QVariantMap &map); + QVariantMap toVariantMap() const; + static EquipmentTypes fromVariantMap(const QVariantMap &map); + + IWMS2ECC::EquipmentType getEquipmentType() const { return m_equipmentType; } + IWMS2ECC::equipTypeMap getEquipmentTypes() const { return m_equipmentTypes; } + bool getOk() const { return m_ok; } + + void setEquipmentType(const IWMS2ECC::EquipmentType &et) { m_equipmentType = et; } + void setEquipmentTypes(const IWMS2ECC::equipTypeMap &map) { m_equipmentTypes = map; } + void setOk(bool ok) { m_ok = ok; } + +private: + IWMS2ECC::equipTypeMap m_equipmentTypes; + mutable IWMS2ECC::EquipmentType m_equipmentType; + bool m_ok = false; +}; diff --git a/Z/src/WMS_Interface/wms_ecc_exercises.cpp b/Z/src/WMS_Interface/wms_ecc_exercises.cpp new file mode 100755 index 000000000..31c89d9c8 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_exercises.cpp @@ -0,0 +1,135 @@ + + + +#include "wms_ecc_exercises.h" +#include +#include + +namespace EXCON +{ + +QJsonObject Exercises::toJson(const IWMS2ECC::Exercise &ex) const +{ + QJsonObject obj; + + obj[QLatin1String("id")] = ex.id; + obj[QLatin1String("actExercise")] = ex.actExercise; + obj[QLatin1String("start")] = static_cast(ex.start); + obj[QLatin1String("end")] = static_cast(ex.end); + obj[QLatin1String("name")] = ex.name; + obj[QLatin1String("state")] = ex.stateAsString; + + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +IWMS2ECC::Exercise Exercises::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::Exercise ex; + + ex.id = obj[QLatin1String("id")].toInt(); + ex.actExercise = obj[QLatin1String("actExercise")].toInt(); + ex.start = static_cast(obj[QLatin1String("start")].toInt()); + ex.end = static_cast(obj[QLatin1String("end")].toInt()); + ex.name = obj[QLatin1String("name")].toString(); + ex.stateAsString = obj[QLatin1String("state")].toString(); + + return ex; +} + +QJsonObject Exercises::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::Exercise &ex : m_exercises) + arr.append(toJson(ex)); + + QJsonObject obj; + obj[QLatin1String("exMap")] = arr; + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +Exercises Exercises::fromJsonAll(const QJsonObject &map) +{ + Exercises ex; + + const QJsonArray arr = map[QLatin1String("exMap")].toArray(); + for (const QJsonValue &val : arr) + { + const IWMS2ECC::Exercise exinfo = fromJson(val.toObject()); + ex.m_exercises.insert(exinfo.id, exinfo); + } + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + + +QVariantMap Exercises::toVariantMap() const +{ + QVariantMap vMap; + + vMap[QLatin1String("id")] = QVariant(m_exercise.id); + vMap[QLatin1String("name")] = m_exercise.name; + vMap[QLatin1String("start")] = QVariant(static_cast(m_exercise.start)); + vMap[QLatin1String("end")] = QVariant(static_cast(m_exercise.end)); + vMap[QLatin1String("state")] = m_exercise.stateAsString; + + vMap[QLatin1String("ok")] = QVariant(m_ok); + + return vMap; +} + +Exercises Exercises::fromVariantMap(const QVariantMap &map) +{ + Exercises ex; + + ex.m_exercise.id = map[QLatin1String("id")].toInt(); + ex.m_exercise.name = map[QLatin1String("name")].toString(); + ex.m_exercise.start = map[QLatin1String("start")].toLongLong(); + ex.m_exercise.end = map[QLatin1String("end")].toLongLong(); + ex.m_exercise.stateAsString = map[QLatin1String("state")].toString(); + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + +QVariantMap Exercises::toVariantMapAll() const +{ + QVariantMap vMap; + for (IWMS2ECC::exerciseMap::ConstIterator it = m_exercises.begin(); it != m_exercises.end(); ++it) + { + m_exercise = it.value(); + vMap.insert(QString::number(it.key()), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("exeMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Exercises Exercises::fromVariantMapAll(const QVariantMap &map) +{ + Exercises ex; + + const QVariantMap vMap = map[QLatin1String("exeMap")].toMap(); + for (QVariantMap::ConstIterator it = vMap.begin(); it != vMap.end(); ++it) + { + + int key = it.key().toInt(); + IWMS2ECC::Exercise e = Exercises::fromVariantMap(it.value().toMap()).m_exercise; + ex.m_exercises.insert(key, e); + } + + ex.m_ok = map[QLatin1String("ok")].toBool(); + + return ex; +} + +} diff --git a/Z/src/WMS_Interface/wms_ecc_exercises.h b/Z/src/WMS_Interface/wms_ecc_exercises.h new file mode 100755 index 000000000..ce982a868 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_exercises.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + +namespace EXCON +{ + +class WMS_JSON_DS_EXPORT Exercises : public IBase +{ +public: + QJsonObject toJsonAll() const; + static Exercises fromJsonAll(const QJsonObject &map); + QJsonObject toJson(const IWMS2ECC::Exercise &ex) const; + static IWMS2ECC::Exercise fromJson(const QJsonObject &obj); + + QVariantMap toVariantMapAll() const; + static Exercises fromVariantMapAll(const QVariantMap &map); + QVariantMap toVariantMap() const; + static Exercises fromVariantMap(const QVariantMap &map); + + IWMS2ECC::Exercise getExercise() const { return m_exercise; } + IWMS2ECC::exerciseMap getExercises() const { return m_exercises; } + bool getOk() const { return m_ok; } + + void setExercise(const IWMS2ECC::Exercise &exe) { m_exercise = exe; } + void setExercises(const IWMS2ECC::exerciseMap &exe) { m_exercises = exe; } + void setOk(bool ok) { m_ok = ok; } + +private: + IWMS2ECC::exerciseMap m_exercises; + mutable IWMS2ECC::Exercise m_exercise; + bool m_ok = false; +}; + +} diff --git a/Z/src/WMS_Interface/wms_ecc_ibase.h b/Z/src/WMS_Interface/wms_ecc_ibase.h new file mode 100755 index 000000000..e6d44597a --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_ibase.h @@ -0,0 +1,15 @@ + + + +#pragma once + +#include + +class WMS_JSON_DS_EXPORT IBase +{ +public: + IBase() = default; + virtual ~IBase() = default; + +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp b/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp new file mode 100755 index 000000000..545cbf422 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_playerInfo.cpp @@ -0,0 +1,176 @@ + + + +#include "wms_ecc_playerInfo.h" +#include +#include +#include + +QJsonObject PlayerInfo::toJson(const IWMS2ECC::PlayerInfo &pi) +{ + QJsonObject obj; + obj[QLatin1String("playerState")] = pi.playerState; + obj[QLatin1String("playerId")] = pi.playerId; + obj[QLatin1String("parentPlayerId")] = pi.parentPlayerId; + obj[QLatin1String("equipNo")] = pi.equipNo; + obj[QLatin1String("assignState")] = pi.assignState; + obj[QLatin1String("exerciseId")] = pi.exerciseId; + obj[QLatin1String("forceId")] = pi.forceId; + obj[QLatin1String("typeId")] = pi.typeId; + obj[QLatin1String("isDeleted")] = pi.isDeleted; + obj[QLatin1String("equipTypeId")] = pi.equipTypeId; + obj[QLatin1String("typeClassId")] = pi.typeClassId; + obj[QLatin1String("symbolColor")] = pi.symbolColor; + obj[QLatin1String("symbolPNG")] = QString::fromLatin1(pi.symbolPNG.toBase64()); + obj[QLatin1String("hierarchy")] = pi.hierarchy; + obj[QLatin1String("designator")] = pi.designator; + obj[QLatin1String("tactIdent")] = pi.tactIdent; + obj[QLatin1String("info")] = pi.info; + obj[QLatin1String("alias")] = pi.alias; + obj[QLatin1String("forceName")] = pi.forceName; + + return obj; +} + +IWMS2ECC::PlayerInfo PlayerInfo::fromJson(const QJsonObject &obj) +{ + IWMS2ECC::PlayerInfo pi; + + pi.playerState = static_cast(obj[QLatin1String("playerState")].toInt()); + pi.playerId = obj[QLatin1String("playerId")].toInt(); + pi.parentPlayerId = obj[QLatin1String("parentPlayerId")].toInt(); + pi.equipNo = obj[QLatin1String("equipNo")].toInt(); + pi.assignState = static_cast(obj[QLatin1String("assignState")].toInt()); + pi.exerciseId = obj[QLatin1String("exerciseId")].toInt(); + pi.forceId = obj[QLatin1String("forceId")].toInt(); + pi.typeId = obj[QLatin1String("typeId")].toInt(); + pi.isDeleted = obj[QLatin1String("isDeleted")].toBool(); + pi.equipTypeId = obj[QLatin1String("equipTypeId")].toInt(); + pi.typeClassId = obj[QLatin1String("typeClassId")].toInt(); + pi.symbolColor = obj[QLatin1String("symbolColor")].toInt(); + pi.symbolPNG = QByteArray::fromBase64(obj[QLatin1String("symbolPNG")].toString().toLatin1()); + pi.hierarchy = obj[QLatin1String("hierarchy")].toString(); + pi.designator = obj[QLatin1String("designator")].toString(); + pi.tactIdent = obj[QLatin1String("tactIdent")].toString(); + pi.info = obj[QLatin1String("info")].toString(); + pi.alias = obj[QLatin1String("alias")].toString(); + pi.forceName = obj[QLatin1String("forceName")].toString(); + + return pi; +} + +QJsonObject PlayerInfo::toJsonAll() const +{ + QJsonArray arr; + for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo) + arr.append(toJson(pi)); + + QJsonObject retMap; + retMap[QLatin1String("piMap")] = arr; + retMap[QLatin1String("ok")] = m_ok; + + return retMap; +} + +PlayerInfo PlayerInfo::fromJsonAll(const QJsonObject &map) +{ + PlayerInfo pi; + + const QJsonArray arr = map[QLatin1String("piMap")].toArray(); + for (const QJsonValue &val : arr) + { + const IWMS2ECC::PlayerInfo player = fromJson(val.toObject()); + + pi.m_allPlayerInfo.insert(player.playerId, player); + } + + pi.m_ok = map[QLatin1String("ok")].toBool(); + + return pi; +} + +QVariantMap PlayerInfo::toVariantMap() const +{ + QVariantMap retMap; + retMap[QLatin1String("playerId")] = QVariant(m_playerInfo.playerId); + retMap[QLatin1String("parentPlayerId")] = QVariant(m_playerInfo.parentPlayerId); + retMap[QLatin1String("equipNo")] = QVariant(m_playerInfo.equipNo); + retMap[QLatin1String("equipTypeId")] = QVariant(m_playerInfo.equipTypeId); + retMap[QLatin1String("typeClassId")] = QVariant(m_playerInfo.typeClassId); + retMap[QLatin1String("forceId")] = QVariant(m_playerInfo.forceId); + retMap[QLatin1String("designator")] = m_playerInfo.designator; + retMap[QLatin1String("tactIdent")] = m_playerInfo.tactIdent; + retMap[QLatin1String("hierarchy")] = m_playerInfo.hierarchy; + retMap[QLatin1String("forceName")] = m_playerInfo.forceName; + retMap[QLatin1String("info")] = m_playerInfo.info; + retMap[QLatin1String("alias")] = m_playerInfo.alias; + retMap[QLatin1String("symbolPNG")] = QVariant(m_playerInfo.symbolPNG); + retMap[QLatin1String("symbolColor")] = QVariant(m_playerInfo.symbolColor); + + retMap[QLatin1String("assignState")] = QVariant(m_playerInfo.assignState); + retMap[QLatin1String("playerState")] = QVariant(m_playerInfo.playerState); + + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +PlayerInfo PlayerInfo::fromVariantMap(const QVariantMap &map) +{ + PlayerInfo pi; + + pi.m_playerInfo.playerId = map[QLatin1String("playerId")].toInt(); + pi.m_playerInfo.parentPlayerId = map[QLatin1String("parentPlayerId")].toInt(); + pi.m_playerInfo.equipNo = map[QLatin1String("equipNo")].toInt(); + pi.m_playerInfo.forceId = map[QLatin1String("forceId")].toInt(); + pi.m_playerInfo.equipTypeId = map[QLatin1String("equipTypeId")].toInt(); + pi.m_playerInfo.typeClassId = map[QLatin1String("typeClassId")].toInt(); + pi.m_playerInfo.designator = map[QLatin1String("designator")].toString(); + pi.m_playerInfo.tactIdent = map[QLatin1String("tactIdent")].toString(); + pi.m_playerInfo.hierarchy = map[QLatin1String("hierarchy")].toString(); + pi.m_playerInfo.forceName = map[QLatin1String("forceName")].toString(); + pi.m_playerInfo.info = map[QLatin1String("info")].toString(); + pi.m_playerInfo.alias = map[QLatin1String("alias")].toString(); + pi.m_playerInfo.symbolPNG = map[QLatin1String("symbolPNG")].toByteArray(); + pi.m_playerInfo.symbolColor = map[QLatin1String("symbolColor")].toInt(); + pi.m_playerInfo.assignState = (IWMS2ECC::PlayerAssignState) map[QLatin1String("assignState")].toInt(); + pi.m_playerInfo.playerState = (IWMS2ECC::PlayerState) map[QLatin1String("playerState")].toInt(); + + pi.m_ok = map[QLatin1String("ok")].toBool(); + + return pi; +} + +QVariantMap PlayerInfo::toVariantMapAll() const +{ + QVariantMap vMap; + for (const IWMS2ECC::PlayerInfo &pi : m_allPlayerInfo) + { + m_playerInfo = pi; + vMap.insert(QString::number(pi.playerId), QVariant(toVariantMap())); + } + + QVariantMap retMap; + retMap[QLatin1String("plMap")] = QVariant(vMap); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +PlayerInfo PlayerInfo::fromVariantMapAll(const QVariantMap &map) +{ + PlayerInfo players; + + const QVariantMap vMap = map[QLatin1String("plMap")].toMap(); + for (const QVariant &data : vMap) + { + PlayerInfo player = PlayerInfo::fromVariantMap(data.toMap()); + IWMS2ECC::PlayerInfo pi = player.getPlayerInfo(); + players.m_allPlayerInfo.insert(pi.playerId, pi); + } + + players.m_ok = vMap[QLatin1String("ok")].toBool(); + return players; +} + + diff --git a/Z/src/WMS_Interface/wms_ecc_playerInfo.h b/Z/src/WMS_Interface/wms_ecc_playerInfo.h new file mode 100755 index 000000000..898a96cb7 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_playerInfo.h @@ -0,0 +1,40 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include + + +class WMS_JSON_DS_EXPORT PlayerInfo : public IBase +{ +public: + static QJsonObject toJson(const IWMS2ECC::PlayerInfo &pi); + static IWMS2ECC::PlayerInfo fromJson(const QJsonObject &obj); + + QJsonObject toJsonAll() const; + static PlayerInfo fromJsonAll(const QJsonObject &map); + + QVariantMap toVariantMap() const; + static PlayerInfo fromVariantMap(const QVariantMap &map); + + QVariantMap toVariantMapAll() const; + static PlayerInfo fromVariantMapAll(const QVariantMap &map); + + IWMS2ECC::PlayerInfo getPlayerInfo() const { return m_playerInfo; } + QMap getAllPlayerInfo() const { return m_allPlayerInfo; } + bool getOk() const { return m_ok; } + + void setPlayerInfo(const IWMS2ECC::PlayerInfo &info) { m_playerInfo = info; } + void setAllPlayerInfo(const QMap &pi) { m_allPlayerInfo = pi; } + void setOk(bool ok) { m_ok = ok; } + +private: + QMap m_allPlayerInfo; + mutable IWMS2ECC::PlayerInfo m_playerInfo; + bool m_ok = false; +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_registration.cpp b/Z/src/WMS_Interface/wms_ecc_registration.cpp new file mode 100755 index 000000000..3aee57a61 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_registration.cpp @@ -0,0 +1,89 @@ + + + +#include "wms_ecc_registration.h" +#include + +QJsonObject Registration::toJson() const +{ + QJsonObject obj; + + obj[QLatin1String("playerId")] = m_playerId; + obj[QLatin1String("assignment")] = m_assignment; + obj[QLatin1String("exerciseId")] = m_exerciseId; + obj[QLatin1String("ok")] = m_ok; + + if (m_bEquipNoIsSet) + obj[QLatin1String("equipNo")] = m_equipNo; + if (m_bAliasIsSet) + obj[QLatin1String("alias")] = m_alias; + if (m_bInfoIsSet) + obj[QLatin1String("info")] = m_info; + + return obj; +} + +Registration Registration::fromJson(const QJsonObject &obj) +{ + Registration rg; + + rg.m_playerId = obj[QLatin1String("playerId")].toInt(); + rg.m_assignment = IWMS2ECC::int2PlayerAssignState(obj[QLatin1String("assignment")].toInt()); + rg.m_exerciseId = obj[QLatin1String("exerciseId")].toInt(); + + rg.m_bEquipNoIsSet = obj.contains(QLatin1String("equipNo")); + if (rg.m_bEquipNoIsSet) + rg.m_equipNo = obj[QLatin1String("equipNo")].toInt(); + rg.m_bAliasIsSet = obj.contains(QLatin1String("alias")); + if (rg.m_bAliasIsSet) + rg.m_alias = obj[QLatin1String("alias")].toString(); + rg.m_bInfoIsSet = obj.contains(QLatin1String("info")); + if (rg.m_bInfoIsSet) + rg.m_info = obj[QLatin1String("info")].toString(); + rg.m_ok = obj[QLatin1String("ok")].toBool(); + + return rg; +} + + +QVariantMap Registration::toVariantMap() const +{ + QVariantMap retMap; + + retMap[QLatin1String("playerId")] = QVariant(m_playerId); + retMap[QLatin1String("assignment")] = QVariant(m_assignment); + retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId); + + if (m_bEquipNoIsSet) + retMap[QLatin1String("equipNo")] = QVariant(m_equipNo); + if (m_bAliasIsSet) + retMap[QLatin1String("alias")] = m_alias; + if (m_bInfoIsSet) + retMap[QLatin1String("info")] = m_info; + + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Registration Registration::fromVariantMap(const QVariantMap &map) +{ + Registration rg; + + rg.m_playerId = map[QLatin1String("playerId")].toInt(); + rg.m_assignment = IWMS2ECC::int2PlayerAssignState(map[QLatin1String("assignment")].toInt()); + rg.m_exerciseId = map[QLatin1String("exerciseId")].toInt(); + rg.m_ok = map[QLatin1String("ok")].toBool(); + + rg.m_bEquipNoIsSet = map.contains(QLatin1String("equipNo")); + if (rg.m_bEquipNoIsSet) + rg.m_equipNo = map[QLatin1String("equipNo")].toInt(); + rg.m_bAliasIsSet = map.contains(QLatin1String("alias")); + if (rg.m_bAliasIsSet) + rg.m_alias = map[QLatin1String("alias")].toString(); + rg.m_bInfoIsSet = map.contains(QLatin1String("info")); + if (rg.m_bInfoIsSet) + rg.m_info = map[QLatin1String("info")].toString(); + + return rg; +} diff --git a/Z/src/WMS_Interface/wms_ecc_registration.h b/Z/src/WMS_Interface/wms_ecc_registration.h new file mode 100755 index 000000000..8c0fc6348 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_registration.h @@ -0,0 +1,55 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" +#include "IWMS2ECC.h" + +#include +#include + + +class WMS_JSON_DS_EXPORT Registration : public IBase +{ +public: + QJsonObject toJson() const; + static Registration fromJson(const QJsonObject &obj); + + QVariantMap toVariantMap() const; + static Registration fromVariantMap(const QVariantMap &map); + + int getPlayerId() const { return m_playerId; } + int getEquipNo() const { return m_equipNo; } + int getExerciseId() const { return m_exerciseId; } + QString getAlias() const { return m_alias; } + QString getInfo() const { return m_info; } + bool isEquipNoSet() const { return m_bEquipNoIsSet; } + bool isAliasSet() const { return m_bAliasIsSet; } + bool isInfoSet() const { return m_bInfoIsSet; } + + IWMS2ECC::PlayerAssignState getAssignment() const { return m_assignment; } + + bool getOk() const { return m_ok; } + + void setPlayerId(int playerId) { m_playerId = playerId; } + void setEquipNo(int equipNo) { m_equipNo = equipNo; m_bEquipNoIsSet = true; } + void setAssignment(IWMS2ECC::PlayerAssignState assignment) { m_assignment = assignment; } + void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; } + void setAlias(const QString &alias) { m_alias = alias; m_bAliasIsSet = true; } + void setInfo(const QString &info) { m_info = info; m_bInfoIsSet = true; } + void setOk(bool ok) { m_ok = ok; } + +private: + QString m_alias; + QString m_info; + IWMS2ECC::PlayerAssignState m_assignment = IWMS2ECC::UNDEFINED; + int m_playerId = 0; + int m_equipNo = 0; + int m_exerciseId = -1; + bool m_bEquipNoIsSet = false; + bool m_bAliasIsSet = false; + bool m_bInfoIsSet = false; + bool m_ok = false; +}; + diff --git a/Z/src/WMS_Interface/wms_ecc_unregister.cpp b/Z/src/WMS_Interface/wms_ecc_unregister.cpp new file mode 100755 index 000000000..5f1974f24 --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_unregister.cpp @@ -0,0 +1,50 @@ + + + +#include "wms_ecc_unregister.h" +#include + +QJsonObject Unregister::toJson() const +{ + QJsonObject obj; + + obj[QLatin1String("equipNo")] = m_equipNo; + obj[QLatin1String("exerciseId")] = m_exerciseId; + obj[QLatin1String("ok")] = m_ok; + + return obj; +} + +Unregister Unregister::fromJson(const QJsonObject &obj) +{ + Unregister ur; + + ur.m_equipNo = obj[QLatin1String("equipNo")].toInt(); + ur.m_exerciseId = obj[QLatin1String("exerciseId")].toInt(); + ur.m_ok = obj[QLatin1String("ok")].toBool(); + + return ur; +} + +QVariantMap Unregister::toVariantMap() const +{ + QVariantMap retMap; + + retMap[QLatin1String("equipNo")] = QVariant(m_equipNo); + retMap[QLatin1String("exerciseId")] = QVariant(m_exerciseId); + retMap[QLatin1String("ok")] = QVariant(m_ok); + + return retMap; +} + +Unregister Unregister::fromVariantMap(const QVariantMap &map) +{ + Unregister ur; + + ur.m_equipNo = map[QLatin1String("equipNo")].toInt(); + ur.m_exerciseId = map[QLatin1String("exerciseId")].toInt(); + ur.m_ok = map[QLatin1String("ok")].toBool(); + + return ur; +} + diff --git a/Z/src/WMS_Interface/wms_ecc_unregister.h b/Z/src/WMS_Interface/wms_ecc_unregister.h new file mode 100755 index 000000000..d3731020c --- /dev/null +++ b/Z/src/WMS_Interface/wms_ecc_unregister.h @@ -0,0 +1,32 @@ + + + +#pragma once + +#include "wms_ecc_ibase.h" + +#include +#include + +class WMS_JSON_DS_EXPORT Unregister : public IBase +{ +public: + QJsonObject toJson() const; + static Unregister fromJson(const QJsonObject &obj); + + QVariantMap toVariantMap() const; + static Unregister fromVariantMap(const QVariantMap &map); + + int getEquipNo() const { return m_equipNo; } + int getExerciseId() const { return m_exerciseId; } + bool getOk() const { return m_ok; } + + void setEquipNo(int equipNo) { m_equipNo = equipNo; } + void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; } + void setOk(bool ok) { m_ok = ok; } + +private: + int m_equipNo = 0; + int m_exerciseId = -1; + bool m_ok = false; +}; diff --git a/Z/src/nglapplication/CMakeLists.txt b/Z/src/nglapplication/CMakeLists.txt new file mode 100755 index 000000000..05e5541b2 --- /dev/null +++ b/Z/src/nglapplication/CMakeLists.txt @@ -0,0 +1,134 @@ +# +# $Id$ +# $HeadURL$ +# $Author$ +# + +# +# nglapplication +# +SET(nglapplication_SRCS + nglapplication.cpp + nglapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) +NGL_ADD_LIBRARY(WS AAR SV HLA nglapplication SHARED ${nglapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Core + Qt5::Widgets +) +NGL_INSTALL_TARGET(nglapplication) + +# +# nglsingleapplication +# +SET(nglsingleapplication_SRCS + nglsingleapplication.cpp + nglsingleapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) +NGL_ADD_LIBRARY(WS nglsingleapplication SHARED ${nglsingleapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglsingleapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglsingleapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + qtsingleapplication +) +NGL_INSTALL_TARGET(nglsingleapplication) + +# +# nglcoreapplication +# +SET(nglcoreapplication_SRCS + nglcoreapplication.cpp + nglcoreapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(ALL nglcoreapplication SHARED ${nglcoreapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglcoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglcoreapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Core +) +NGL_INSTALL_TARGET(nglcoreapplication) + +# +# nglsinglecoreapplication +# +SET(nglsinglecoreapplication_SRCS + nglsinglecoreapplication.cpp + nglsinglecoreapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(AAR SV nglsinglecoreapplication SHARED ${nglsinglecoreapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglsinglecoreapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglsinglecoreapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + qtsinglecoreapplication +) +NGL_INSTALL_TARGET(nglsinglecoreapplication) + +# +# nglguiapplication +# +SET(nglguiapplication_SRCS + nglguiapplication.cpp + nglguiapplication.h + nglloggerhandler.cpp + nglloggerhandler.h + ngl_qt_msg_handler.inc + ngl_signal_handler.inc +) + +NGL_ADD_LIBRARY(ALL nglguiapplication SHARED ${nglguiapplication_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglguiapplication + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_TARGET_LINK_LIBRARIES(nglguiapplication + PRIVATE + NGLLogger + nglsettings + PUBLIC + Qt5::Gui +) +NGL_INSTALL_TARGET(nglguiapplication) diff --git a/Z/src/nglapplication/ngl_qt_msg_handler.inc b/Z/src/nglapplication/ngl_qt_msg_handler.inc new file mode 100755 index 000000000..c9da57f53 --- /dev/null +++ b/Z/src/nglapplication/ngl_qt_msg_handler.inc @@ -0,0 +1,64 @@ +/** + * @RDE_HEADER@ + * callback to catch qt log messages + * $Id$ + * $HeadURL$ + * $Author$ + */ + +#include +#include + +static void qtMsgHandler(QtMsgType type, const QMessageLogContext &, const QString &msg) +{ + // pulse audio connect errors are important but can be very annoying - so only print it ONE time only and also as an error + static bool pulseAudioMessageSent = false; + static QString pulseAudioMessage = QStringLiteral("PulseAudioService: pa_context_connect() failed"); + if (msg.startsWith(pulseAudioMessage)) + { + if (pulseAudioMessageSent) + { + return; + } + + type = QtCriticalMsg; + pulseAudioMessageSent = true; + } + + + try + { + NGL::INGLLogger &l = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "NGL.Qt" ); + switch (type) { + case QtDebugMsg: + DEBUG_LOG(l) << msg ; + break; + case QtInfoMsg: + INFO_LOG(l) << msg ; + break; + case QtWarningMsg: + WARNING_LOG(l) << msg ; + break; + case QtCriticalMsg: + ERROR_LOG(l) << msg ; + break; + case QtFatalMsg: + FATAL_LOG(l) << msg ; + break; + } + } catch (...) { + switch (type) + { + case QtDebugMsg: + case QtInfoMsg: + fputs(qPrintable(msg), stdout); + break; + case QtWarningMsg: + case QtCriticalMsg: + case QtFatalMsg: + fputs(qPrintable(msg), stderr); + break; + } + } +} + diff --git a/Z/src/nglapplication/ngl_signal_handler.inc b/Z/src/nglapplication/ngl_signal_handler.inc new file mode 100755 index 000000000..cf1d5f976 --- /dev/null +++ b/Z/src/nglapplication/ngl_signal_handler.inc @@ -0,0 +1,41 @@ +/** + * @RDE_HEADER@ + * small stub to catch SIGTERM for proper shutdown + * $Id$ + * $HeadURL$ + * $Author$ + */ + +#include +#include + +#ifdef Q_OS_WIN +#include +#include + + +class MyEventFilter final : public QAbstractNativeEventFilter +{ + public: + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override + { + Q_UNUSED(eventType); + Q_UNUSED(result); + const MSG *msg = reinterpret_cast(message); + if (msg->message == WM_CLOSE && msg->hwnd == nullptr) + QCoreApplication::quit(); + return false; + } +}; +#endif + +#ifndef SIGTERM +# define SIGTERM 15 +#endif +static void signalHandler(int signal_number) +{ + if(signal_number != SIGTERM) + return; + QCoreApplication::quit(); +} + diff --git a/Z/src/nglapplication/nglapplication.cpp b/Z/src/nglapplication/nglapplication.cpp new file mode 100755 index 000000000..ff96bd7c2 --- /dev/null +++ b/Z/src/nglapplication/nglapplication.cpp @@ -0,0 +1,31 @@ + + + +#include "nglapplication.h" +#include "ngl_signal_handler.inc" + + +NGLApplication::NGLApplication(int &argc, char **argv) + : QApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} + + +bool NGLApplication::notify(QObject *o, QEvent *e) +{ + bool bRet = false; + try + { + bRet = QApplication::notify(o, e); + } + catch (const std::exception &e) + { + fprintf(stderr, "exception %s\n", e.what()); + } + return bRet; +} diff --git a/Z/src/nglapplication/nglapplication.h b/Z/src/nglapplication/nglapplication.h new file mode 100755 index 000000000..a1fe052f6 --- /dev/null +++ b/Z/src/nglapplication/nglapplication.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLAPPLICATION_LIB +# define NGLAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLAPPLICATION_EXPORT NGLApplication : public QApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLApplication(int &argc, char **argv); + +protected: + bool notify(QObject *o, QEvent *e) override; +}; + +#define nglApp static_cast(NGLApplication::instance()) diff --git a/Z/src/nglapplication/nglcoreapplication.cpp b/Z/src/nglapplication/nglcoreapplication.cpp new file mode 100755 index 000000000..40f536612 --- /dev/null +++ b/Z/src/nglapplication/nglcoreapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglcoreapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLCoreApplication::NGLCoreApplication(int &argc, char **argv) + : QCoreApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglcoreapplication.h b/Z/src/nglapplication/nglcoreapplication.h new file mode 100755 index 000000000..ab6eebe95 --- /dev/null +++ b/Z/src/nglapplication/nglcoreapplication.h @@ -0,0 +1,31 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLCOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLCOREAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLCOREAPPLICATION_LIB +# define NGLCOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLCOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLCOREAPPLICATION_EXPORT NGLCoreApplication : public QCoreApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLCoreApplication(int &argc, char **argv); +}; diff --git a/Z/src/nglapplication/nglguiapplication.cpp b/Z/src/nglapplication/nglguiapplication.cpp new file mode 100755 index 000000000..a4f066ffe --- /dev/null +++ b/Z/src/nglapplication/nglguiapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglguiapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLGuiApplication::NGLGuiApplication(int &argc, char **argv) + : QGuiApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglguiapplication.h b/Z/src/nglapplication/nglguiapplication.h new file mode 100755 index 000000000..9f9eaaaf0 --- /dev/null +++ b/Z/src/nglapplication/nglguiapplication.h @@ -0,0 +1,33 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLGUIAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLGUIAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLGUIAPPLICATION_LIB +# define NGLGUIAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLGUIAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLGUIAPPLICATION_EXPORT NGLGuiApplication : public QGuiApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLGuiApplication(int &argc, char **argv); +}; + +#define nglGuiApp static_cast(NGLGuiApplication::instance()) diff --git a/Z/src/nglapplication/nglloggerhandler.cpp b/Z/src/nglapplication/nglloggerhandler.cpp new file mode 100755 index 000000000..6c3e9e7d1 --- /dev/null +++ b/Z/src/nglapplication/nglloggerhandler.cpp @@ -0,0 +1,91 @@ + + + +#include "nglloggerhandler.h" +#include "ngl_qt_msg_handler.inc" + +#include +#include +#include + +namespace NGL +{ + +static QByteArray username() +{ +#ifdef Q_OS_WIN + return qgetenv("USERNAME"); +#else + return qgetenv("USER"); +#endif +} + +static void setEnvVars() +{ + + const QString logPath = NGL::Settings::logPath(); + qputenv("LOG4QT_LOGDIR", logPath.toLocal8Bit()); + qputenv("LOG4QT_USER", username()); +} + + +void LoggerHandler::createLogger(const QByteArray &baseName, const char *configFileName, bool quiet) +{ + setEnvVars(); + m_baseLoggerName = baseName; + + const QString bnStr(QString::fromLatin1(baseName.toLower())); + const QString logPath = NGL::Settings::logPath(); + m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr; + m_loggerFilenamePrefix = QLatin1String(".log"); + + const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix; + NGL::NGLLoggerBootstrap::createNGLRootLogger(QString::fromLatin1(configFileName), false, logOutputName, quiet); + + + qInstallMessageHandler(&qtMsgHandler); +} + + +void LoggerHandler::createLogger(const QByteArray &baseName, int exerciseId, int additionalId, bool quiet) +{ + setEnvVars(); + + const QString bnStr(QString::fromLatin1(baseName.toLower())); + const QString configFileName = QLatin1String("log4cxx_") + bnStr + QLatin1String(".props"); + const QString logPath = NGL::Settings::logPath(); + m_loggerFilenamePostfix = logPath + QLatin1Char('/') + QString::fromLocal8Bit(username()) + QLatin1Char('_') + bnStr; + if (exerciseId > 0) + m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(exerciseId); + if (additionalId > 0) + m_loggerFilenamePostfix += QLatin1Char('_') + QString::number(additionalId); + + m_loggerFilenamePrefix = QLatin1String(".log"); + m_baseLoggerName = baseName + QByteArray(".main"); + + const QString logOutputName = m_loggerFilenamePostfix + m_loggerFilenamePrefix; + NGL::NGLLoggerBootstrap::createNGLRootLogger(configFileName, false, logOutputName, quiet); + + + qInstallMessageHandler(&qtMsgHandler); +} + + +NGL::INGLLogger &LoggerHandler::baseLogger() const +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(m_baseLoggerName.data()); +} + + +NGL::INGLLogger &LoggerHandler::logger(const char *loggerName) const +{ + return NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName); +} + + +LoggerHandler *LoggerHandler::getLoggerHandler() +{ + return dynamic_cast(QCoreApplication::instance()); +} + +} diff --git a/Z/src/nglapplication/nglloggerhandler.h b/Z/src/nglapplication/nglloggerhandler.h new file mode 100755 index 000000000..826dd754d --- /dev/null +++ b/Z/src/nglapplication/nglloggerhandler.h @@ -0,0 +1,67 @@ + + +#pragma once + +#include +#include + +#ifndef LOGGERHANDLER_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define LOGGERHANDLER_EXPORT +# else +# if defined(MAKE_NGLCOREAPPLICATION_LIB) || defined(MAKE_NGLGUIAPPLICATION_LIB) || defined(MAKE_NGLAPPLICATION_LIB) || defined(MAKE_NGLSINGLECOREAPPLICATION_LIB) || defined(MAKE_NGLSINGLEAPPLICATION_LIB) +# define LOGGERHANDLER_EXPORT Q_DECL_EXPORT +# else +# define LOGGERHANDLER_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; + +class LOGGERHANDLER_EXPORT LoggerHandler +{ +public: + LoggerHandler() = default; + ~LoggerHandler() = default; + + + + void createLogger(const QByteArray &baseName, + const char *configFileName, + bool quiet = false); + + + + void createLogger(const QByteArray &baseName, + int exerciseId = 0, + int additionalId = 0, + bool quiet = false); + + + + NGL::INGLLogger &baseLogger() const; + + + + NGL::INGLLogger &logger(const char *loggerName) const; + + + + QString loggerNamePostfix() const { return m_loggerFilenamePostfix; } + + + + QString loggerNamePrefix() const { return m_loggerFilenamePrefix; } + + + + static LoggerHandler *getLoggerHandler(); +private: + QByteArray m_baseLoggerName; + QString m_loggerFilenamePostfix; + QString m_loggerFilenamePrefix; +}; +} diff --git a/Z/src/nglapplication/nglsingleapplication.cpp b/Z/src/nglapplication/nglsingleapplication.cpp new file mode 100755 index 000000000..48dbdd4ff --- /dev/null +++ b/Z/src/nglapplication/nglsingleapplication.cpp @@ -0,0 +1,32 @@ + + + +#include "nglsingleapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLSingleApplication::NGLSingleApplication(int &argc, char **argv) + : QtSingleApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} + + +bool NGLSingleApplication::notify(QObject *o, QEvent *e) +{ + bool bRet = false; + try + { + bRet = QtSingleApplication::notify(o, e); + } + catch (const std::exception &e) + { + fprintf(stderr, "exception %s\n", e.what()); + } + return bRet; +} diff --git a/Z/src/nglapplication/nglsingleapplication.h b/Z/src/nglapplication/nglsingleapplication.h new file mode 100755 index 000000000..d34e47125 --- /dev/null +++ b/Z/src/nglapplication/nglsingleapplication.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLSINGLEAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSINGLEAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLSINGLEAPPLICATION_LIB +# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLSINGLEAPPLICATION_EXPORT NGLSingleApplication : public QtSingleApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLSingleApplication(int &argc, char **argv); + +protected: + bool notify(QObject *o, QEvent *e) override; +}; + +#define nglApp static_cast(NGLSingleApplication::instance()) diff --git a/Z/src/nglapplication/nglsinglecoreapplication.cpp b/Z/src/nglapplication/nglsinglecoreapplication.cpp new file mode 100755 index 000000000..be75bbb28 --- /dev/null +++ b/Z/src/nglapplication/nglsinglecoreapplication.cpp @@ -0,0 +1,17 @@ + + + +#include "nglsinglecoreapplication.h" + +#include "ngl_signal_handler.inc" + + +NGLSingleCoreApplication::NGLSingleCoreApplication(int &argc, char **argv) + : QtSingleCoreApplication(argc, argv) +{ + + signal(SIGTERM, &signalHandler); +#ifdef Q_OS_WIN + installNativeEventFilter(new MyEventFilter); +#endif +} diff --git a/Z/src/nglapplication/nglsinglecoreapplication.h b/Z/src/nglapplication/nglsinglecoreapplication.h new file mode 100755 index 000000000..c64eba419 --- /dev/null +++ b/Z/src/nglapplication/nglsinglecoreapplication.h @@ -0,0 +1,31 @@ + + +#pragma once + +#include +#include "nglloggerhandler.h" + +#ifndef NGLSINGLECOREAPPLICATION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSINGLECOREAPPLICATION_EXPORT +# else +# ifdef MAKE_NGLSINGLECOREAPPLICATION_LIB +# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_EXPORT +# else +# define NGLSINGLECOREAPPLICATION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif + +namespace NGL +{ +class INGLLogger; +} + +class NGLSINGLECOREAPPLICATION_EXPORT NGLSingleCoreApplication : public QtSingleCoreApplication, public NGL::LoggerHandler +{ + Q_OBJECT + +public: + NGLSingleCoreApplication(int &argc, char **argv); +}; diff --git a/Z/src/nglcompression/CMakeLists.txt b/Z/src/nglcompression/CMakeLists.txt new file mode 100755 index 000000000..0b867347d --- /dev/null +++ b/Z/src/nglcompression/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# CMake Script +# $Id$ +# $HeadURL$ +# $Author$ +# + +FIND_PACKAGE(BZip2 REQUIRED) +SET(nglcomp_SRCS + nglcomp_bzip2iodevice.cpp + nglcomp_bzip2iodevice.h + nglcomp_compress.cpp + nglcomp_compress.h + nglcomp_export.h + nglcomp_tarfilter.cpp + nglcomp_tarfilter.h +) +NGL_ADD_LIBRARY(WS nglcompression SHARED ${nglcomp_SRCS}) +NGL_TARGET_LINK_LIBRARIES(nglcompression + PUBLIC + Qt5::Core + PRIVATE + Qt5::Concurrent + NGLLogger + ${BZIP2_LIBRARIES} +# BZip2::BZip2 # not available with cmake 3.5 +) +NGL_TARGET_INCLUDE_DIRECTORIES(nglcompression + PRIVATE + ${BZIP2_INCLUDE_DIR} +) +NGL_INSTALL_TARGET(nglcompression) + +IF(BUILD_WS AND BUILD_TESTING) + REMOVE_DEFINITIONS(-DQT_GUI_LIB) + ADD_EXECUTABLE(nglcomp_test nglcomp_test.cpp nglcomp_test.h) + + TARGET_LINK_LIBRARIES(nglcomp_test + NGLLogger + nglcoreapplication + ngltools + nglcompression + Qt5::Test + ) + + ADD_TEST(NAME nglcomp_test COMMAND $) +ENDIF() diff --git a/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp b/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp new file mode 100755 index 000000000..e8bbf0258 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_bzip2iodevice.cpp @@ -0,0 +1,360 @@ + + + + + +#include "nglcomp_bzip2iodevice.h" + +#include +#include + +#include + + + + +class BZip2IODevice::Private +{ +public: + Private(BZip2IODevice *parent_, QIODevice *dev, int bs) + : parent(parent_) + , device(dev) + , iCurPos(0) + , iMaxBufSize(1024 * 1024) + , blocksize(bs) + , initialized(false) + , decomressStreamEnd(false) + { + buffer.resize(iMaxBufSize); + } + + bool initializeCompress(); + qint64 doCompress(const char *in, qint64 iMaxLen); + bool finishCompress(); + bool initializeDecompress(); + qint64 doDecompress(char *out, qint64 iMaxLen); + bool finishDecompress(); + static QString bzipError2String(int errCode); + + QAtomicInt aborted { 0 }; + BZip2IODevice *parent; + QIODevice *device; + unsigned int iCurPos; + unsigned int iMaxBufSize; + unsigned int blocksize; + bool initialized; + bool decomressStreamEnd; + QByteArray buffer; + bz_stream stream; +}; + +bool BZip2IODevice::Private::initializeCompress() +{ + if (initialized) + return true; + memset(&stream, 0, sizeof(stream)); + int blockSize = (blocksize > 0 && blocksize < 10) ? blocksize : 10; + int ret = BZ2_bzCompressInit(&stream, blockSize, 0, 0); + if (ret != BZ_OK) + { + parent->setErrorString(QStringLiteral("Error initializing bzip2 %1").arg(bzipError2String(ret))); + initialized = false; + } + else + initialized = true; + + return initialized; +} + +qint64 BZip2IODevice::Private::doCompress(const char *in, qint64 iMaxLen) +{ + if (!initialized) + { + if (parent->errorString().isEmpty()) + parent->setErrorString(QLatin1String("Internal Error - bzip not initialized")); + finishCompress(); + return -1; + } + if (iMaxLen > 2 * 1024 * 1024 * 1024LL) + { + finishCompress(); + parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!")); + return -1; + } + + stream.next_in = const_cast(in); + stream.avail_in = iMaxLen; + + do + { + if (aborted) return 0; + + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); + + const int ret = BZ2_bzCompress(&stream, BZ_RUN); + if (ret != BZ_RUN_OK) + { + finishCompress(); + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + return -1; + } + int iBytesToWrite = buffer.size() - stream.avail_out; + if (iBytesToWrite) + { + if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite) + { + finishCompress(); + parent->setErrorString(QLatin1String("Error writing to QIODevice")); + return -1; + } + } + } + while (stream.avail_in != 0); + + return stream.next_in - in; +} + +bool BZip2IODevice::Private::finishCompress() +{ + if (!initialized || aborted) + return true; + + int ret = -1; + + do + { + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); + ret = BZ2_bzCompress(&stream, BZ_FINISH); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { + finishCompress(); + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + return false; + } + int iBytesToWrite = buffer.size() - stream.avail_out; + if (device->write(buffer.constData(), iBytesToWrite) != iBytesToWrite) + { + finishCompress(); + parent->setErrorString(QLatin1String("Error writing to QIODevice")); + return false; + } + } + while (ret != BZ_STREAM_END); + BZ2_bzCompressEnd(&stream); + + initialized = false; + return true; +} + +bool BZip2IODevice::Private::initializeDecompress() +{ + if (initialized) + return true; + memset(&stream, 0, sizeof(stream)); + int ret = BZ2_bzDecompressInit(&stream, 0, 0); + if (ret != BZ_OK) + { + parent->setErrorString(QStringLiteral("Error initializing bzip2: %1").arg(bzipError2String(ret))); + initialized = false; + } + else + initialized = true; + decomressStreamEnd = false; + return initialized; +} + +qint64 BZip2IODevice::Private::doDecompress(char *out, qint64 iMaxLen) +{ + int ret = -1; + if (!initialized) + { + if (parent->errorString().isEmpty()) + parent->setErrorString(QLatin1String("Internal Error - bzip not initialized")); + finishDecompress(); + return -1; + } + if (decomressStreamEnd) + return 0; + + if (iMaxLen > 2 * 1024 * 1024 * 1024LL) + { + finishCompress(); + parent->setErrorString(QLatin1String("Currently can't handle more than 2GB!")); + return -1; + } + + stream.next_out = out; + stream.avail_out = iMaxLen; + + do + { + if (ret != BZ_STREAM_END && stream.avail_in == 0) + { + qint64 iReadCnt = device->read(buffer.data(), buffer.size()); + if (iReadCnt <= 0) + return -1; + stream.next_in = buffer.data(); + stream.avail_in = iReadCnt; + } + + ret = BZ2_bzDecompress(&stream); + if (ret != BZ_OK && ret != BZ_STREAM_END) + { + parent->setErrorString(QStringLiteral("Error executing BZ2_bzCompress: %1").arg(bzipError2String(ret))); + finishDecompress(); + return -1; + } + } + while (stream.avail_out != 0 && ret != BZ_STREAM_END); + decomressStreamEnd = (ret == BZ_STREAM_END); + return stream.next_out - out; +} + +bool BZip2IODevice::Private::finishDecompress() +{ + if (!initialized) + return true; + BZ2_bzDecompressEnd(&stream); + + initialized = false; + return true; +} + +QString BZip2IODevice::Private::bzipError2String(int errCode) +{ + switch (errCode) + { + case BZ_SEQUENCE_ERROR: + return QLatin1String("Sequence error"); + case BZ_PARAM_ERROR: + return QLatin1String("Parameter not correct"); + case BZ_MEM_ERROR: + return QLatin1String("Memory allocation error"); + case BZ_DATA_ERROR: + return QLatin1String("Invalid input data"); + case BZ_DATA_ERROR_MAGIC: + return QLatin1String("Not a bzip2 file"); + case BZ_IO_ERROR: + return QLatin1String("I/O error"); + case BZ_UNEXPECTED_EOF: + return QLatin1String("Unexpected end of file"); + case BZ_OUTBUFF_FULL: + return QLatin1String("Output buffer full"); + case BZ_CONFIG_ERROR: + return QLatin1String("Wrong config parameter"); + }; + return QString::number(errCode); +} + + + + +BZip2IODevice::BZip2IODevice(QIODevice *dev, int blocksize) + : d(new Private(this, dev, blocksize)) +{} + +BZip2IODevice::~BZip2IODevice() +{ + close(); + delete d; +} + +void BZip2IODevice::setBufferSize(unsigned int size) +{ + d->iMaxBufSize = size > 1024 ? size : 1024; + d->buffer.resize(d->iMaxBufSize); +} + +void BZip2IODevice::setBlockSize(unsigned int size) +{ + if (isOpen()) + return; + d->blocksize = size; +} + +bool BZip2IODevice::isSequential() const +{ + return true; +} + +bool BZip2IODevice::open(OpenMode mode) +{ + if ((mode & QIODevice::ReadWrite) == 0) + { + setErrorString(QStringLiteral("Unsupported OpenMode %1").arg(mode)); + return false; + } + if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) + { + setErrorString(QLatin1String("Can't read and write simultaniously")); + return false; + } + if ((mode & QIODevice::ReadOnly) == QIODevice::ReadOnly) + { + if (!d->device) + { + setErrorString(QLatin1String("No QIODevice for reading available")); + return false; + } + if ((d->device->openMode() & QIODevice::ReadOnly) == 0) + { + setErrorString(QLatin1String("QIODevice not opened for reading")); + return false; + } + if (!d->initializeDecompress()) + return false; + } + else + { + if (!d->device) + { + setErrorString(QLatin1String("No QIODevice for writing available")); + return false; + } + if ((d->device->openMode() & QIODevice::WriteOnly) == 0) + { + setErrorString(QLatin1String("QIODevice not opened for writing")); + return false; + } + if (!d->initializeCompress()) + return false; + } + setErrorString(QString()); + setOpenMode(mode); + return QIODevice::open(mode); +} + +void BZip2IODevice::abort() +{ + d->aborted = 1; +} + +void BZip2IODevice::close() +{ + if (!isOpen()) + return; + if ((openMode() & QIODevice::ReadOnly) == QIODevice::ReadOnly) + d->finishDecompress(); + else + d->finishCompress(); + QIODevice::close(); +} + +bool BZip2IODevice::atEnd() const +{ + if (!d->device) + return true; + return d->device->atEnd() && d->decomressStreamEnd && QIODevice::atEnd(); +} + +qint64 BZip2IODevice::readData(char *data, qint64 maxSize) +{ + return d->doDecompress(data, maxSize); +} + +qint64 BZip2IODevice::writeData(const char *data, qint64 maxSize) +{ + return d->doCompress(data, maxSize); +} diff --git a/Z/src/nglcompression/nglcomp_bzip2iodevice.h b/Z/src/nglcompression/nglcomp_bzip2iodevice.h new file mode 100755 index 000000000..79310fbdc --- /dev/null +++ b/Z/src/nglcompression/nglcomp_bzip2iodevice.h @@ -0,0 +1,42 @@ + + + + + +#ifndef BZIP2IODEVICE_H +#define BZIP2IODEVICE_H + +#include +#include + + + +class BZip2IODevice : public QIODevice +{ +public: + + + + BZip2IODevice(QIODevice *dev, int blocksize = 5); + virtual ~BZip2IODevice(); + + void abort(); + void setBufferSize(unsigned int size); + void setBlockSize(unsigned int size); + + + virtual bool isSequential() const; + virtual bool open(OpenMode mode); + virtual void close(); + virtual bool atEnd() const; +protected: + virtual qint64 readData(char *data, qint64 maxSize); + virtual qint64 writeData(const char *data, qint64 maxSize); +private: + + class Private; + friend class Private; + Private *const d; +}; + +#endif diff --git a/Z/src/nglcompression/nglcomp_compress.cpp b/Z/src/nglcompression/nglcomp_compress.cpp new file mode 100755 index 000000000..aeed7079c --- /dev/null +++ b/Z/src/nglcompression/nglcomp_compress.cpp @@ -0,0 +1,566 @@ + + +#include "nglcomp_compress.h" +#include "nglcomp_bzip2iodevice.h" +#include "nglcomp_tarfilter.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + + + + + + + + +#include + + + + + + + + + + + + +namespace NGL +{ + +Compress::Compress(QObject *parent) + : QObject(parent) + , m_u2_memFiles() + , m_aborted(0) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("nglcompress")) +{ + DEBUG_LOG(m_logger) << "c_tor"; + + + + + + + + + + QTimer *t = new QTimer(this); + t->setInterval(1000); + connect(t, &QTimer::timeout, this, [](){qWarning() << "still alive ...";}); + t->start(); +} + +Compress::~Compress() +{ + qWarning() << "## COMPRESS DTOR!!!!"; + + + DEBUG_LOG(m_logger) << "~"; + + abort(); + m_future.waitForFinished(); + DEBUG_LOG(m_logger) << "~ finished"; +} + +void Compress::abort() +{ + DEBUG_LOG(m_logger) << "ABORT"; + + m_aborted = 1; + m_lastError = tr("Aborted"); + + if (m_currentTarFilter != nullptr) + { + DEBUG_LOG(m_logger) << "aborting tar"; + m_currentTarFilter->abort(); + } + + if (m_currentBzipDevice != nullptr) + { + DEBUG_LOG(m_logger) << "aborting bzip"; + m_currentBzipDevice->abort(); + } +} + +void Compress::compress(QIODevice *out, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &destRootDir) +{ + DEBUG_LOG(m_logger) << "compress #2"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_compress, out, filesRootDir, files, memFiles, destRootDir)); +} + +void Compress::compress(QIODevice *out, const QString &sourceDir, const QString &destRootDir) +{ + DEBUG_LOG(m_logger) << "compress #1 source dir: " << sourceDir << ", destRootDir: " << destRootDir; + reset(); + + QVector inFiles = directoryFileList(sourceDir, true); + + + int len = sourceDir.length(); + if (!sourceDir.endsWith(QLatin1Char('/'))) + len += 1; + for (auto &fi : inFiles) + { + fi.inputFileName = fi.inputFileName.mid(len); + fi.bAbsInputPath = false; + DEBUG_LOG(m_logger) << "fi: ifm = " << fi.inputFileName << ", abs = " << fi.bAbsInputPath; + } + + DEBUG_LOG(m_logger) << "FI list size: " << inFiles.count(); + + compress(out, sourceDir, inFiles, {}, destRootDir); +} + +bool Compress::_compress(QIODevice *output, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &_destRootDir) +{ + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #1"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!output || !output->isWritable()) + { + m_lastError = tr("Device is not writeable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError;; + + return false; + } + + const QString destRootDir = _destRootDir.endsWith(QLatin1Char('/')) ? + _destRootDir : _destRootDir + QLatin1Char('/'); + + const qint64 maxCount = files.count() + memFiles.count(); + qint64 count = 0; + + DEBUG_LOG(m_logger) << "destRootDir = " << destRootDir << ", maxCount = " << maxCount << ", count = " << count; + + BZip2IODevice bzip2(output, 9); + m_currentBzipDevice = &bzip2; + + if (!bzip2.open(QIODevice::WriteOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + + + qint64 bytesTotal = 0; + for (const FileInformations &file : qAsConst(files)) + { + if (m_aborted) return false; + + const QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName; + const QFileInfo fi(in); + + bytesTotal += fi.size(); + } + + + qint64 currentFileSize = 0; + QString currentFileName; + auto readCallback = [this, &maxCount, &count, ¤tFileSize, ¤tFileName, &bytesTotal](const qint64 iSize) + { + DEBUG_LOG(m_logger) << "readCallback: maxCount = " << maxCount << ", count = " << count + << ", currentFileSize = " << currentFileSize << ", currentFileName = " << currentFileName << ", iSize = " << iSize; + emit compressInfoEx(maxCount, count, currentFileSize, (currentFileSize - iSize), currentFileName, bytesTotal); + }; + + + TarFilter tf(&bzip2, nullptr, readCallback); + m_currentTarFilter = &tf; + const QVector paths = destRootDir.splitRef(QLatin1Char('/'), QString::SkipEmptyParts); + QString curPath; + + + DEBUG_LOG(m_logger) << "prepairing tar filter"; + for (const QStringRef &path : paths) + { + DEBUG_LOG(m_logger) << "path = " << path.toString(); + if (m_aborted) return false; + + if (curPath.isEmpty()) + curPath = path + QLatin1Char('/'); + else + curPath += path + QLatin1Char('/'); + + DEBUG_LOG(m_logger) << "curPath = " << curPath << ", filesRootDir.isEmpty() = " << filesRootDir.isEmpty(); + + if (filesRootDir.isEmpty()) + { + if (!tf.addData(curPath, QByteArray(), true)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + else + { + if (!tf.addFile(filesRootDir, curPath)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + } + + m_c_sizeInfo.realSize = 0; + for (const FileInformations &file : qAsConst(files)) + { + DEBUG_LOG(m_logger) << "file = " << file.inputFileName; + emit compressInfo(maxCount, ++count, file.inputFileName); + + if (m_aborted) return false; + + QString in = file.bAbsInputPath ? file.inputFileName : filesRootDir + QLatin1Char('/') + file.inputFileName; + QString out = destRootDir + (file.outputFileName.isEmpty() ? file.inputFileName : file.outputFileName); + + DEBUG_LOG(m_logger) << "in = " << in << ", out = " << out; + + QFileInfo fi(in); + + currentFileName = fi.fileName(); + currentFileSize = fi.size(); + m_c_sizeInfo.realSize += currentFileSize; + + DEBUG_LOG(m_logger) << "currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize; + + if (!tf.addFile(in, out)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + for (const FileInformations &file : qAsConst(memFiles)) + { + DEBUG_LOG(m_logger) << "(mem) file = " << file.inputFileName; + emit compressInfo(maxCount, ++count, file.inputFileName); + + if (m_aborted) return false; + + currentFileName = file.inputFileName; + currentFileSize = file.fileData.size(); + m_c_sizeInfo.compressedSize += currentFileSize; + + DEBUG_LOG(m_logger) << "(mem) currentFileName = " << currentFileName << ", currentFileSize = " << currentFileSize << "m_c_sizeInfo.realSize" << m_c_sizeInfo.realSize; + + if (!tf.addData(file.inputFileName, file.fileData)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + + DEBUG_LOG(m_logger) << "writing eos"; + tf.writeEOS(); + + DEBUG_LOG(m_logger) << "closing bzip"; + bzip2.close(); + + m_c_sizeInfo.compressedSize = output->size(); + DEBUG_LOG(m_logger) << "m_c_sizeInfo.compressedSize = " << m_c_sizeInfo.compressedSize; + + m_success = true; + + DEBUG_LOG(m_logger) << "DONE!"; + + return true; +} + +void Compress::uncompress(QIODevice *in, const QString &outDir) +{ + DEBUG_LOG(m_logger) << "uncompress #1"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressDirectory, in, outDir)); +} + +bool Compress::_uncompressDirectory(QIODevice *input, const QString &outDir) +{ + DEBUG_LOG(m_logger) << "_uncompressDirectory"; + + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!input || !input->isReadable()) + { + m_lastError = tr("Device is not readable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + BZip2IODevice bzip2(input, 9); + m_currentBzipDevice = &bzip2; + if (!bzip2.open(QIODevice::ReadOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + TarFilter tf(&bzip2); + m_currentTarFilter = &tf; + TarFilter::FileInformations tfi; + QDir dir(outDir); + + DEBUG_LOG(m_logger) << "dir = " << dir.path(); + + while (tf.getData(tfi)) + { + DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName; + emit uncompressInfo(input->size(), input->pos(), tfi.fileName); + if (m_aborted) return false; + + QString path = outDir + QLatin1Char('/') + tfi.fileName; + DEBUG_LOG(m_logger) << "path = " << path; + if (tfi.fileType == TarFilter::directory) + { + DEBUG_LOG(m_logger) << "tfi.fileType == TarFilter::directory"; + if (!dir.exists(path) && !dir.mkpath(path)) + { + m_lastError = tr("Error creating directory %1").arg(outDir); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + else + { + + QString pathName = QFileInfo(path).absolutePath(); + if (!dir.exists(pathName) && !dir.mkpath(pathName)) + { + m_lastError = tr("Error creating directory %1").arg(pathName); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + QFile f(path); + if (!f.open(QIODevice::WriteOnly)) + { + m_lastError = tr("Error opening %1 for writing (%2)").arg(path, f.errorString()); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + if (!tf.getData(&f)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + } + + DEBUG_LOG(m_logger) << "uncompress done!"; + m_success = true; + return true; +} + +void Compress::uncompress(QIODevice *in) +{ + DEBUG_LOG(m_logger) << "uncompress #2!"; + reset(); + setupFutureWatcher(QtConcurrent::run(this, &Compress::_uncompressBuffer, in)); +} + +bool Compress::_uncompressBuffer(QIODevice *input) +{ + DEBUG_LOG(m_logger) << "uncompressBuffer"; + + std::shared_ptr invalidatePointersOnScopeLeave(nullptr, [this](int *) + { + DEBUG_LOG(m_logger) << "invalidatePointersOnScopeLeave #2"; + m_currentTarFilter = nullptr; + m_currentBzipDevice = nullptr; + }); + (void)invalidatePointersOnScopeLeave; + + + if (!input->isReadable()) + { + m_lastError = tr("Device is not readable"); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + BZip2IODevice bzip2(input, 9); + m_currentBzipDevice = &bzip2; + if (!bzip2.open(QIODevice::ReadOnly)) + { + m_lastError = bzip2.errorString(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + + TarFilter tf(&bzip2); + m_currentTarFilter = &tf; + TarFilter::FileInformations tfi; + while (tf.getData(tfi)) + { + DEBUG_LOG(m_logger) << "tfi.fileName = " << tfi.fileName; + emit uncompressInfo(input->size(), input->pos(), tfi.fileName); + if (m_aborted) return false; + + FileInformations fi; + fi.outputFileName = tfi.fileName; + + DEBUG_LOG(m_logger) << "fi.outputFileName = " << fi.outputFileName; + + if (tfi.fileType == TarFilter::directory) + { + fi.outputFileName += QLatin1Char('/'); + DEBUG_LOG(m_logger) << "> fi.outputFileName = " << fi.outputFileName; + } + else + { + DEBUG_LOG(m_logger) << "stuff"; + + QBuffer buf(&fi.fileData); + if (!buf.open(QIODevice::WriteOnly)) + { + m_lastError = tr("Error opening buffer for writing (%1)").arg(buf.errorString()); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + if (!tf.getData(&buf)) + { + m_lastError = tf.lastError(); + ERROR_LOG(m_logger) << "compress failed: " << m_lastError; + + return false; + } + } + + fi.bAbsInputPath = fi.outputFileName.startsWith(QLatin1Char('/')); + DEBUG_LOG(m_logger) << "added fi.bAbsInputPath = " << fi.bAbsInputPath; + m_u2_memFiles += fi; + } + + return true; +} + +bool Compress::success() const +{ + + ERROR_LOG(m_logger) << "success? " << (m_future.isFinished() && !m_future.isCanceled() && m_success); + ERROR_LOG(m_logger) << "success details: " + << "success m_future.isFinished() = " << (m_future.isFinished()) + << " !m_future.isCanceled() = " << !m_future.isCanceled() + << " m_success = " << m_success; + return (m_future.isFinished() && !m_future.isCanceled() && m_success); +} + +bool Compress::waitForFinished() +{ + DEBUG_LOG(m_logger) << "waitForFinished..."; + m_future.waitForFinished(); + DEBUG_LOG(m_logger) << "waitForFinished... done!"; + return success(); +} + +QVector Compress::directoryFileList(const QString &dir, bool recursive) +{ + DEBUG_LOG(m_logger) << "directoryFileList"; + + QVector sl_absolute; + QDir d(dir); + + if (d.exists()) + { + DEBUG_LOG(m_logger) << "exists"; + const auto entries = d.entryList(QDir::Files); + sl_absolute.reserve(sl_absolute.size() + entries.size()); + for (const QString &entry : entries) + sl_absolute << FileInformations(QFileInfo(d, entry).absoluteFilePath(), true); + } + + if (recursive) + { + DEBUG_LOG(m_logger) << "recursive"; + const auto entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + sl_absolute.reserve(sl_absolute.size() + entries.size()); + for (const QString &s : entries) + sl_absolute << directoryFileList(dir + QLatin1Char('/') + s, true); + } + + DEBUG_LOG(m_logger) << "done"; + return sl_absolute; +} + +void Compress::reset() +{ + DEBUG_LOG(m_logger) << "reset"; + m_u2_memFiles.clear(); + + m_lastError.clear(); + + m_c_sizeInfo.realSize = 0; + m_c_sizeInfo.compressedSize = 0; + + m_success = false; +} + +void Compress::setupFutureWatcher(const QFuture &future) +{ + DEBUG_LOG(m_logger) << "setupFutureWatcher"; + m_future = future; + QFutureWatcher *fw = new QFutureWatcher(this); + QObject::connect(fw, &QObject::destroyed, this, [this]() { DEBUG_LOG(m_logger) << "Future Watcher destroyed"; }); + QObject::connect(fw, &QFutureWatcher::finished, this, &Compress::finished); + QObject::connect(fw, &QFutureWatcher::finished, fw, &QObject::deleteLater); + QObject::connect(fw, &QFutureWatcher::finished, fw, [this]() { DEBUG_LOG(m_logger) << "Future Watcher about to be deleted"; }); + fw->setFuture(m_future); +} + +} diff --git a/Z/src/nglcompression/nglcomp_compress.h b/Z/src/nglcompression/nglcomp_compress.h new file mode 100755 index 000000000..07c6ee0d0 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_compress.h @@ -0,0 +1,140 @@ + + +#pragma once + +#include "nglcomp_export.h" + +#include + +#include +#include +#include +#include +#include + +class QIODevice; +class TarFilter; +class BZip2IODevice; + + +namespace NGL +{ +class NGLCOMPRESSION_EXPORT Compress : public QObject +{ + Q_OBJECT +public: + struct FileInformations + { + QString inputFileName; + QString outputFileName; + QByteArray fileData; + bool bAbsInputPath = true; + FileInformations() = default; + + FileInformations(const QString &name, bool isAbsolute) + : inputFileName(name) + , bAbsInputPath(isAbsolute) + {} + }; + + + struct FileSizeInfo + { + qint64 realSize = 0; + qint64 compressedSize = 0; + }; + + + + explicit Compress(QObject *parent = nullptr); + + ~Compress(); + + + + QVector getMemFiles() const { return m_u2_memFiles; } + + + FileSizeInfo getFileSizeInfo() const { return m_c_sizeInfo; } + + + bool success() const; + + + + void compress(QIODevice *out, + const QString &sourceRootDir, + const QVector &files, + const QVector &memFiles, + const QString &destRootDir); + + + + void compress(QIODevice *out, + const QString &sourceDir, + const QString &destRootDir); + + + void uncompress(QIODevice *in, + const QString &outDir); + + + void uncompress(QIODevice *in); + + + QString lastError() const { return m_lastError; } + + + + bool waitForFinished(); + +public Q_SLOTS: + void abort(); + +Q_SIGNALS: + + + void uncompressInfo(qint64 totalSize, qint64 curPos, const QString &curName); + + + void compressInfo(qint64 totalFiles, qint64 curFile, const QString &curName); + void compressInfoEx(qint64 totalFiles, qint64 curFile, qint64 totalSize, qint64 curPos, const QString &curName, const qint64 bytesTotal); + + + + void error(const QString &errorString); + + + + void finished(); +private: + + bool _compress(QIODevice *output, + const QString &filesRootDir, + const QVector &files, + const QVector &memFiles, + const QString &_destRootDir); + bool _uncompressDirectory(QIODevice *input, const QString &outDir); + bool _uncompressBuffer(QIODevice *input); + + void reset(); + void setupFutureWatcher(const QFuture &future); + + QVector directoryFileList(const QString &dir, bool recursive = false); + + FileSizeInfo m_c_sizeInfo; + QVector m_u2_memFiles; + + QString m_lastError; + QAtomicInt m_aborted; + + TarFilter *m_currentTarFilter { nullptr }; + BZip2IODevice *m_currentBzipDevice { nullptr }; + + QFuture m_future; + bool m_success { false }; + NGL::INGLLogger &m_logger; +}; +} +Q_DECLARE_TYPEINFO(NGL::Compress::FileInformations, Q_MOVABLE_TYPE); + diff --git a/Z/src/nglcompression/nglcomp_export.h b/Z/src/nglcompression/nglcomp_export.h new file mode 100755 index 000000000..a1fcc74d8 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLCOMPRESSION_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLCOMPRESSION_EXPORT +# else +# if defined(MAKE_NGLCOMPRESSION_LIB) +# define NGLCOMPRESSION_EXPORT Q_DECL_EXPORT +# else +# define NGLCOMPRESSION_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/nglcompression/nglcomp_tarfilter.cpp b/Z/src/nglcompression/nglcomp_tarfilter.cpp new file mode 100755 index 000000000..37c290324 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_tarfilter.cpp @@ -0,0 +1,525 @@ + + + + + +#include +#include +#include +#include +#include +#include + +#include + +#include "nglcomp_tarfilter.h" + +#ifndef Q_OS_WIN +#include +#include +#include +#endif + + + + + + + + +class TarFilter::Private +{ +public: + Private(QIODevice *dev, QTextCodec *c) + : device(dev) + , codec(c ? c : QTextCodec::codecForLocale()) + , iBufSize(1024 * 1024) + , nextChunkSize(-1) + {} + + struct tar_posix_header + { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char unused[12]; + }; + bool fi2tph(const FileInformations &infos); + bool addHeader(const FileInformations &infos); + + bool tph2fi(FileInformations &infos); + bool getHeader(FileInformations &infos); + bool checkDevice(QIODevice *in, QIODevice *out); + bool copyData(QIODevice *in, QIODevice *out, qint64 iSize); + + QIODevice *device; + QTextCodec *codec; + QString lastError; + unsigned int iBufSize; + qint64 nextChunkSize; + QAtomicInt aborted { 0 }; + std::function readCallback; +}; + +bool TarFilter::Private::fi2tph(const FileInformations &infos) +{ + QByteArray fn = codec->fromUnicode(infos.fileName); +#ifdef Q_OS_WIN + if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/')) + fn = fn.mid(3); +#endif + if (fn.startsWith('/')) + fn = fn.mid(1); + + long unsigned int fileSize = infos.fileType == directory ? 0 : infos.fileSize; + long unsigned int mtime = infos.mtime != -1 ? infos.mtime : time(nullptr); + tar_posix_header hdr; + memset(&hdr, 0, sizeof(hdr)); + QByteArray fn_part1 = fn.left(sizeof(hdr.name)); + memcpy(hdr.name, fn_part1.constData(), fn_part1.size()); + sprintf(hdr.mode, "%07x", 0x0fff & infos.mode); + sprintf(hdr.uid, "%07o", infos.uid); + sprintf(hdr.gid, "%07o", infos.gid); + sprintf(hdr.size, "%011lo", fileSize); + sprintf(hdr.mtime, "%011lo", mtime); + memset(hdr.chksum, ' ', sizeof(hdr.chksum)); + hdr.typeflag = infos.fileType; + + memcpy(hdr.magic, "ustar ",sizeof(hdr.magic) + sizeof(hdr.version)); +#ifdef Q_OS_WIN + + +#else + qstrncpy(hdr.uname, codec->fromUnicode(infos.uname).constData(), sizeof(hdr.uname)); + qstrncpy(hdr.gname, codec->fromUnicode(infos.gname).constData(), sizeof(hdr.gname)); +#endif + + + + + unsigned int checksum = 0; + const unsigned char *ptr = reinterpret_cast(&hdr); + for (unsigned i = 0; i < sizeof(hdr); i++) + checksum += ptr[i]; + constexpr int octalMax = 01000000; + while (checksum > octalMax) + checksum -= octalMax; + sprintf(hdr.chksum, "%06o", checksum); + + if (!device->write((const char *)&hdr, sizeof(hdr))) + { + lastError = QLatin1String("Error writing to QIODevice"); + return false; + } + return true; +} + +bool TarFilter::Private::addHeader(const FileInformations &infos) +{ + + + QByteArray fn = codec->fromUnicode(infos.fileName); +#ifdef Q_OS_WIN + if (fn.size() > 3 && fn[1] == ':' && (fn[2] == '\\' || fn[2] == '/')) + fn = fn.mid(3); +#endif + if (fn.startsWith('/')) + fn = fn.mid(1); + if (fn.size() > 512) + { + lastError = QLatin1String("Can't handle filenames with more then 512 bytes"); + return false; + } + if (fn.size() > 100) + { + FileInformations longlink; + longlink.fileName = QLatin1String("././@LongLink"); + longlink.fileType = gnu_longname; + longlink.fileSize = strlen(fn.constData()) + 1; + longlink.mtime = 0; + longlink.uid = 0; + longlink.gid = 0; +#ifndef Q_OS_WIN + struct passwd *p = getpwuid(longlink.uid); + if (p) + longlink.uname = codec->toUnicode(p->pw_name); + struct group *g = getgrgid(longlink.gid); + if (g) + longlink.gname = codec->toUnicode(g->gr_name); +#endif + fi2tph(longlink); + QByteArray ba(512, '\0'); + qstrncpy(ba.data(), fn.constData(), ba.size()); + if (!device->write(ba.constData(), ba.size())) + { + lastError = QLatin1String("Error writing to QIODevice"); + return false; + } + } + if (!fi2tph(infos)) + return false; + + return true; +} + +bool TarFilter::Private::tph2fi(FileInformations &infos) +{ + Private::tar_posix_header hdr; + do + { + int iBytesRead = device->read((char *)&hdr, sizeof(hdr)); + if (iBytesRead != sizeof(hdr)) + { + if (iBytesRead == 0 && device->atEnd()) + { + lastError = QString(); + return false; + } + lastError = QStringLiteral("Error reading from QIODevice! needed: %1, got: %2").arg(sizeof(hdr)).arg(iBytesRead); + return false; + } + } + while (memcmp(hdr.magic, "\0\0\0\0\0\0", sizeof(hdr.magic)) == 0); + if (memcmp(hdr.magic, "ustar ", sizeof(hdr.magic))) + { + lastError = QLatin1String("The archive is not supported"); + return false; + } + int checksum = QByteArray(hdr.chksum, sizeof(hdr.chksum)).toUInt(nullptr, 8); + memset(hdr.chksum, ' ', sizeof(hdr.chksum)); + int realChecksum = 0; + const unsigned char *ptr = reinterpret_cast(&hdr); + for (unsigned i = 0; i < sizeof(hdr); i++) + realChecksum += ptr[i]; + if (checksum != realChecksum) + { + lastError = QStringLiteral("Checksum does not match! needed: %1, got: %2").arg(checksum).arg(realChecksum); + return false; + } + + QByteArray ba(hdr.name, sizeof(hdr.name)); + ba.resize(qstrlen(ba.constData())); + infos.fileName = codec->toUnicode(ba); + infos.fileSize = QByteArray(hdr.size, sizeof(hdr.size)).toUInt(nullptr, 8); + infos.mode = static_cast(QByteArray(hdr.mode, sizeof(hdr.mode)).toUInt(nullptr, 16)); + infos.uid = QByteArray(hdr.uid, sizeof(hdr.uid)).toUInt(nullptr, 8); + infos.gid = QByteArray(hdr.gid, sizeof(hdr.gid)).toUInt(nullptr, 8); + infos.mtime = QByteArray(hdr.mtime, sizeof(hdr.mtime)).toUInt(nullptr, 8); + infos.fileType = (FileType)hdr.typeflag; + infos.uname = codec->toUnicode(hdr.uname, sizeof(hdr.uname)); + infos.gname = codec->toUnicode(hdr.gname, sizeof(hdr.gname)); + + return true; +} + +bool TarFilter::Private::getHeader(FileInformations &infos) +{ + if (!tph2fi(infos)) + return false; + switch (infos.fileType) + { + case regular: + case regular2: + case directory: + case gnu_longname: + break; + default: + lastError = QStringLiteral("Unsupported fileType %1").arg(infos.fileType); + return false; + } + if (infos.fileType == gnu_longname) + { + const QByteArray fn = device->read(512); + if (fn.size() != 512) + { + lastError = QLatin1String("Unexpected end of inputstream"); + return false; + } + if (!tph2fi(infos)) + return false; + const int len = qstrlen(fn.constData()); + infos.fileName = codec->toUnicode(fn.constData(), len); + } + + return true; +} + +bool TarFilter::Private::checkDevice(QIODevice *in, QIODevice *out) +{ + if (!in) + { + lastError = QLatin1String("No QIODevice for reading available"); + return false; + } + if ((in->openMode() & QIODevice::ReadOnly) == 0) + { + lastError = QLatin1String("QIODevice not opened for reading"); + return false; + } + + if (!out) + { + lastError = QLatin1String("No QIODevice for writing available"); + return false; + } + if ((out->openMode() & QIODevice::WriteOnly) == 0) + { + lastError = QLatin1String("QIODevice not opened for writing"); + return false; + } + return true; +} + +bool TarFilter::Private::copyData(QIODevice *in, QIODevice *out, qint64 iSize) +{ + if (iSize <= 0) + return true; + + while (iSize > 0) + { + if (aborted) return false; + + const qint64 iBytesToRead = iSize > iBufSize ? iBufSize : iSize; + const QByteArray ba = in->read(iBytesToRead); + + if (aborted) return false; + + if (ba.size() == 0) + { + lastError = QStringLiteral("Could not read %1 bytes from QIODevice").arg(iBytesToRead); + return false; + } + + if (out->write(ba) != ba.size()) + { + lastError = QStringLiteral("Could not write %1 bytes to QIODevice").arg(ba.size()); + return false; + } + iSize -= ba.size(); + + if (readCallback) + readCallback(iSize); + } + return true; +} + + + + +TarFilter::TarFilter(QIODevice *dev, QTextCodec *codec, const std::function &readCallback) + : d(new Private(dev, codec)) +{ + d->readCallback = readCallback; +} + +TarFilter::~TarFilter() +{ + delete d; +} + +void TarFilter::abort() +{ + d->aborted = 1; +} + +void TarFilter::setLocaleCodec(QTextCodec *codec) +{ + d->codec = codec ? codec : QTextCodec::codecForLocale(); +} + +void TarFilter::setBufferSize(unsigned int size) +{ + d->iBufSize = size > 1024 ? size : 1024; +} + +bool TarFilter::error() const +{ + return !d->lastError.isEmpty(); +} + +QString TarFilter::lastError() const +{ + return d->lastError; +} + +bool TarFilter::addFile(const QString &filename, const QString &filenameInArchive) +{ + QFileInfo fi(filename); + if (!fi.exists()) + { + d->lastError = QStringLiteral("File %1 does not exist").arg(filename); + return false; + } + if (!(fi.isDir() || fi.isFile())) + { + d->lastError = QStringLiteral("%1 isn't a directory or a regular file").arg(filename); + return false; + } + + FileInformations fInfos; + fInfos.fileName = (filenameInArchive.isEmpty() ? filename : filenameInArchive); + fInfos.fileSize = fi.isDir() ? 0 : fi.size(); + fInfos.mode = fi.permissions() & 0x0fff; +#ifdef Q_OS_WIN + fInfos.uid = 1000; + fInfos.gid = 100; +#else + fInfos.uid = fi.ownerId(); + fInfos.gid = fi.groupId(); + fInfos.uname = fi.owner(); + fInfos.gname = fi.group(); +#endif + fInfos.mtime = fi.lastModified().toSecsSinceEpoch(); + fInfos.fileType = fi.isDir() ? directory : regular; + + if (fi.isDir()) + { + QBuffer buf; + buf.open(QIODevice::ReadOnly); + return addData(fInfos, &buf); + } + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) + { + d->lastError = QStringLiteral("Error opening %1 for reading").arg(filename); + return false; + } + + if (d->aborted) return false; + + return addData(fInfos, &f); +} + +bool TarFilter::addData(const QString &filename, const QByteArray &data, bool bIsDir) +{ + if (d->aborted) return false; + + FileInformations fi; + fi.fileName = filename; + fi.fileSize = bIsDir ? 0 : data.size(); + fi.mode = static_cast(bIsDir ? 0x0755 : 0x0644); + fi.fileType = bIsDir ? directory : regular; +#ifndef Q_OS_WIN + fi.uid = getuid(); + fi.gid = getgid(); + char name[256]; + struct passwd *p_ptr = nullptr; + struct passwd p; + getpwuid_r(fi.uid, &p, name, sizeof(name) - 1, &p_ptr); + if (p_ptr) + fi.uname = d->codec->toUnicode(p_ptr->pw_name); + struct group *g_ptr; + struct group g; + getgrgid_r(fi.gid, &g, name, sizeof(name) - 1, &g_ptr); + if (g_ptr) + fi.gname = d->codec->toUnicode(g_ptr->gr_name); +#endif + + QBuffer buf(const_cast(&data)); + if (!buf.open(QIODevice::ReadOnly)) + { + d->lastError = QLatin1String("Internal Error - can't open QBuffer for reading!"); + return false; + } + return addData(fi, &buf); +} + +bool TarFilter::addData(const FileInformations &fi, QIODevice *in) +{ + if (d->aborted) return false; + + if (!d->checkDevice(in, d->device)) + return false; + + if (!d->addHeader(fi)) + return false; + + if (fi.fileSize) + { + if (!d->copyData(in, d->device, fi.fileSize)) + return false; + + int align = fi.fileSize % 512; + if (align) + { + align = 512 - align; + QByteArray ba2(align, '\0'); + d->device->write(ba2.constData(), align); + } + } + return true; +} + +bool TarFilter::writeEOS() +{ + + const int size = sizeof(TarFilter::Private::tar_posix_header) * 2; + QByteArray ba(size, '\0'); + return (d->device->write(ba) == size); +} + +bool TarFilter::getData(FileInformations &fi) +{ + if (d->aborted) return false; + + d->nextChunkSize = -1; + if (!d->getHeader(fi)) + return false; + d->nextChunkSize = fi.fileSize; + return true; +} + +bool TarFilter::getData(QIODevice *out) +{ + if (d->aborted) return false; + + if (!d->checkDevice(d->device, out)) + return false; + + if (d->nextChunkSize < 0) + { + d->lastError = QLatin1String("No informations about next chunk size. Did you call getData(FileInformations &fi) before?"); + return false; + } + + if (!d->copyData(d->device, out, d->nextChunkSize)) + return false; + + int align = d->nextChunkSize % 512; + if (align) + d->device->read(512 - align); + + d->nextChunkSize = -1; + return true; +} + +bool TarFilter::getData(FileInformations &fi, QByteArray &data) +{ + if (!getData(fi)) + return false; + + QBuffer buf(&data); + buf.open(QIODevice::WriteOnly); + return getData(&buf); +} + +bool TarFilter::getData(FileInformations &fi, QIODevice *out) +{ + if (!getData(fi)) + return false; + + return getData(out); +} diff --git a/Z/src/nglcompression/nglcomp_tarfilter.h b/Z/src/nglcompression/nglcomp_tarfilter.h new file mode 100755 index 000000000..f4144dd26 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_tarfilter.h @@ -0,0 +1,82 @@ + + + + + +#ifndef TARFILTER_H +#define TARFILTER_H + +#include +#include +#include + +class QIODevice; +class QTextCodec; +class QByteArray; + + + +class TarFilter +{ +public: + Q_DISABLE_COPY(TarFilter) + + enum FileType + { + regular = '0', + regular2 = '\0', + link = '1', + reserved = '2', + charType = '3', + block = '4', + directory = '5', + fifo = '6', + reserved2 = '7', + gnu_longLink = 'K', + gnu_longname = 'L', + }; + struct FileInformations + { + QString fileName; + qint64 fileSize = 0; + int uid = 1000; + int gid = 100; + QString uname; + QString gname; + time_t mtime = -1; + FileType fileType = regular; + QFile::Permissions mode = QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther; + }; + + + + TarFilter(QIODevice *dev, QTextCodec *codec = nullptr, const std::function &readCallback = nullptr); + ~TarFilter(); + + void abort(); + void setLocaleCodec(QTextCodec *codec); + void setBufferSize(unsigned int size); + bool error() const; + QString lastError() const; + + + bool addData(const FileInformations &fi, QIODevice *in); + + bool addFile(const QString &filename, const QString &filenameInArchive = QString()); + bool addData(const QString &filename, const QByteArray &data = QByteArray(), bool bIsDir = false); + + bool writeEOS(); + + + bool getData(FileInformations &fi, QIODevice *out); + + bool getData(FileInformations &fi); + bool getData(QIODevice *out); + bool getData(FileInformations &fi, QByteArray &data); + +private: + class Private; + Private *const d; +}; + +#endif diff --git a/Z/src/nglcompression/nglcomp_test.cpp b/Z/src/nglcompression/nglcomp_test.cpp new file mode 100755 index 000000000..89e49736a --- /dev/null +++ b/Z/src/nglcompression/nglcomp_test.cpp @@ -0,0 +1,175 @@ + + +#include "nglcomp_test.h" + +#include "nglcomp_compress.h" + +#include + +#include +#include + +#include + + + +void nglcomp_test::initTestCase() +{ + m_tempDirIn.setAutoRemove(true); + m_tempDirOut.setAutoRemove(true); + QVERIFY(m_tempDirIn.isValid()); + QVERIFY(m_tempDirOut.isValid()); + QVERIFY(m_tf.open()); + m_tf.setAutoRemove(true); + + m_fileContent[QLatin1String("1.txt")] = "111111111111111111111111"; + m_fileContent[QLatin1String("sub1/s1.txt")] = "222222222222222222222222"; + m_fileContent[QLatin1String("sub1/sub11/s11.txt")] = "333333333333333333333333"; + m_fileContent[QLatin1String("sub1/sub12/s12.txt")] = "444444444444444444444444"; + m_fileContent[QLatin1String("sub2/2.txt")] = "555555555555555555555555"; +} + + +void nglcomp_test::testCompressFile() +{ + QDir dir; + const auto directories = { + QLatin1String("sub1"), + QLatin1String("sub1/sub11"), + QLatin1String("sub1/sub12"), + QLatin1String("sub2") + }; + for (const QLatin1String &directory : directories) + QVERIFY(dir.mkdir(subPathIn(directory))); + + for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it) + writeTestFile(it.key(), it.value()); + + NGL::Compress c; + c.compress(&m_tf, subPathIn(QString()), QLatin1String("out")); + QVERIFY(c.waitForFinished()); +} + + +void nglcomp_test::testCompressMemory() +{ + QBuffer f(&m_ba); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVector fi1; + QVector fi2; + NGL::Compress::FileInformations fi; + + fi.inputFileName = QLatin1String("chris.txt"); + fi.fileData = QByteArray("dumdidum\n"); + fi2 += fi; + + fi.inputFileName = QLatin1String("blub/chris.txt"); + fi.fileData = QByteArray("dumdidum im Verzeichnis blub\n"); + fi2 += fi; + + fi.inputFileName = QLatin1String("blub/blub/chris2.txt"); + fi.fileData = QByteArray("dumdidum im Verzeichnis blub/blub\n"); + fi2 += fi; + + NGL::Compress c; + c.compress(&f, QString(), fi1, fi2, QLatin1String("blub")); + QVERIFY(c.waitForFinished()); + f.close(); +} + +void nglcomp_test::testUncompressMemory() +{ + QBuffer f(&m_ba); + QVERIFY(f.open(QIODevice::ReadOnly)); + NGL::Compress c; + c.uncompress(&f, subPathIn(QString())); + QVERIFY(c.waitForFinished()); + f.close(); + + QVERIFY(f.open(QIODevice::ReadOnly)); + c.uncompress(&f); + QVERIFY(c.waitForFinished()); + QVector fi1 = c.getMemFiles(); + QVERIFY(fi1.count() == 4); + f.close(); +} + +void nglcomp_test::testUncompressFile() +{ + NGL::Compress c; + m_tf.seek(0); + c.uncompress(&m_tf, subPathOut(QString())); + QVERIFY(c.waitForFinished()); + + for (auto it = m_fileContent.cbegin(); it != m_fileContent.cend(); ++it) + checkContent(it.key(), it.value()); +} + +void nglcomp_test::cleanupTestCase() +{ + m_tf.close(); + m_tempDirIn.remove(); + m_tempDirOut.remove(); +} + + + +void nglcomp_test::writeTestFile(const QString &fn, const QByteArray &content) const +{ + QFile f(subPathIn(fn)); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVERIFY(f.write(content) == content.size()); + f.close(); +} + +void nglcomp_test::checkContent(const QString &fn, const QByteArray &content) const +{ + QFile f(subPathOut(QLatin1String("out/") + fn)); + QVERIFY(f.open(QIODevice::ReadOnly)); + QCOMPARE(f.readAll(), content); +} + +QString nglcomp_test::subPathIn(const QString &p) const +{ + return m_tempDirIn.path() + QLatin1Char('/') + p; +} + +QString nglcomp_test::subPathOut(const QString &p) const +{ + return m_tempDirOut.path() + QLatin1Char('/') + p; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + +int main(int argc, char *argv[]) +{ + NGLCoreApplication app(argc, argv); + + app.createLogger("nglcomp_test", "log4cxx_nglcomp_test.props"); + nglcomp_test tc; + return QTest::qExec(&tc, argc, argv); +} diff --git a/Z/src/nglcompression/nglcomp_test.h b/Z/src/nglcompression/nglcomp_test.h new file mode 100755 index 000000000..9272e0926 --- /dev/null +++ b/Z/src/nglcompression/nglcomp_test.h @@ -0,0 +1,36 @@ + + +#pragma once + +#include +#include +#include +#include +#include + +class nglcomp_test : public QObject +{ + Q_OBJECT + +public: + nglcomp_test() = default; + +private Q_SLOTS: + void initTestCase(); + void testCompressFile(); + void testCompressMemory(); + void testUncompressFile(); + void testUncompressMemory(); + void cleanupTestCase(); +private: + void writeTestFile(const QString &fn, const QByteArray &content) const; + void checkContent(const QString &fn, const QByteArray &content) const; + QString subPathIn(const QString &p) const; + QString subPathOut(const QString &p) const; +private: + QHash m_fileContent; + QByteArray m_ba; + QTemporaryFile m_tf; + QTemporaryDir m_tempDirIn; + QTemporaryDir m_tempDirOut; +}; diff --git a/Z/src/ngldb/CMakeLists.txt b/Z/src/ngldb/CMakeLists.txt new file mode 100755 index 000000000..a6ae5d6c7 --- /dev/null +++ b/Z/src/ngldb/CMakeLists.txt @@ -0,0 +1,45 @@ +# NGLDB +FIND_PACKAGE(PostgreSQL REQUIRED) + +OPTION(ENABLE_DB_TRACING "Enable trace output for NGLDB library" OFF) +IF(ENABLE_DB_TRACING) + add_compile_definitions(NGLDB_ENABLE_TRACE) +ENDIF(ENABLE_DB_TRACING) + +# +# NGL Database Library +# +SET(ngldb_SRCS + dbcommon.h + dbconnection.cpp + dbconnection.h + db_service_handler.h + dbtransaction.cpp + dbtransaction.h + ngldb_export.h + ngldb_logger.cpp + ngldb_logger.h + nsqlquery.cpp + nsqlquery.h + sql_query_janitor.cpp + sql_query_janitor.h +) + +NGL_ADD_LIBRARY(AAR SV HLA WS ngldb SHARED ${ngldb_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngldb + PRIVATE + NGLLogger + nglsettings + ${PostgreSQL_LIBRARIES} + PUBLIC + Qt5::Core + Qt5::Sql +) +NGL_TARGET_INCLUDE_DIRECTORIES(ngldb + PRIVATE + ${PostgreSQL_INCLUDE_DIR} + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) + +NGL_INSTALL_TARGET(ngldb) diff --git a/Z/src/ngldb/db_service_handler.h b/Z/src/ngldb/db_service_handler.h new file mode 100755 index 000000000..c4d64b774 --- /dev/null +++ b/Z/src/ngldb/db_service_handler.h @@ -0,0 +1,58 @@ + + +#pragma once + +#include +#include + +class QSqlDatabase; +namespace NGLDB +{ +template +class DbServiceHandler +{ +public: + DbServiceHandler() = default; + ~DbServiceHandler() = default; + + + bool init(int exerciseId, NGL::Settings *settings) + { + if (m_dbInterface) + return true; + + m_dbInterface = DB::create(exerciseId); + + if (!m_dbInterface->init(m_dbInterface->dbUser(), + settings->databasePassword(m_dbInterface->dbUser()), + settings->databaseDriver(), + settings->databaseHostname(), + settings->databaseName())) + { + m_dbInterface = nullptr; + return false; + } + return true; + } + + bool init(int exerciseId, const QSqlDatabase &db) + { + if (m_dbInterface) + return true; + + m_dbInterface = DB::create(exerciseId); + + if (!m_dbInterface->init(db)) + { + m_dbInterface = nullptr; + return false; + } + return true; + } + + std::shared_ptr db() const { return m_dbInterface; } + +private: + std::shared_ptr m_dbInterface; +}; +} diff --git a/Z/src/ngldb/dbcommon.h b/Z/src/ngldb/dbcommon.h new file mode 100755 index 000000000..b4804145d --- /dev/null +++ b/Z/src/ngldb/dbcommon.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include "ngldb_export.h" +#include + + + +namespace DBCommon +{ + +enum class eDatabaseSchema +{ + Exercise +}; + + + +inline QString getExerciseSchemaName(int exerciseId) +{ + return QLatin1String("ex_") + QString::number(exerciseId); +} + + + +inline QString getTableName(const QString &tableName, const QString &schemaName) +{ + if (schemaName.isEmpty()) + return tableName; + return schemaName + QLatin1Char('.') + tableName; +} + + + +inline QString getExerciseTableName(const QString &tableName, int exerciseId) +{ + return getTableName(tableName, getExerciseSchemaName(exerciseId)); +} +} diff --git a/Z/src/ngldb/dbconnection.cpp b/Z/src/ngldb/dbconnection.cpp new file mode 100755 index 000000000..843628e54 --- /dev/null +++ b/Z/src/ngldb/dbconnection.cpp @@ -0,0 +1,68 @@ + + +#include "dbconnection.h" + +#include +#include +#include + +#include "nsqlquery.h" + +namespace DBConnection +{ + +QSqlDatabase open(NGL::INGLLogger &logger, + const QString &dbUser, + const QString &dbPasswd, + const QString &dbDriver, + const QString &dbHost, + const QString &dbName, + const QString &schemaName, + const QString &connectionName) +{ + + + + DEBUG_LOG(logger) << "host: " << dbHost << " database: " << dbName; + QString realConnectionName(connectionName); + if (connectionName.isEmpty()) + { + realConnectionName = dbHost + QLatin1Char('_') + dbName; + if (!schemaName.isEmpty()) + realConnectionName += QLatin1Char('_') + schemaName; + } + + auto dbConnection = QSqlDatabase::addDatabase(dbDriver, realConnectionName); + dbConnection.setHostName(dbHost); + dbConnection.setDatabaseName(dbName); + dbConnection.setUserName(dbUser); + dbConnection.setPassword(dbPasswd); + + if (!dbConnection.open()) + { + const QString err = dbConnection.lastError().nativeErrorCode(); + FATAL_LOG(logger) << "Error opening database " << dbHost + << ":" << dbName << " as user " << dbUser; + FATAL_LOG(logger) << dbConnection.lastError().driverText() << " " + << dbConnection.lastError().databaseText() << " " << err; + return dbConnection; + } + + DEBUG_LOG(logger) << "Database Initialisation successful -> DB: " << dbName << ", con: " << realConnectionName; + + if (!schemaName.isEmpty()) + { + const QString stmt = QLatin1String("SET SEARCH_PATH TO ") + schemaName + QLatin1String(", PUBLIC"); + + NSqlQuery q(dbConnection); + if (!q.exec(stmt)) + { + ERROR_LOG(logger) << "Set SEARCH_PATH to " << schemaName << " failed!"; + dbConnection.close(); + } + } + + return dbConnection; +} + +} diff --git a/Z/src/ngldb/dbconnection.h b/Z/src/ngldb/dbconnection.h new file mode 100755 index 000000000..612caf361 --- /dev/null +++ b/Z/src/ngldb/dbconnection.h @@ -0,0 +1,24 @@ + + +#pragma once + +#include + +#include "ngldb_export.h" + +namespace NGL +{ +class INGLLogger; +} + +namespace DBConnection +{ +NGLDB_EXPORT QSqlDatabase open(NGL::INGLLogger &logger, + const QString &dbUser, + const QString &dbPasswd, + const QString &dbDriver, + const QString &dbHost, + const QString &dbName, + const QString &schemaName = QString(), + const QString &connectionName = QString()); +} diff --git a/Z/src/ngldb/dbtransaction.cpp b/Z/src/ngldb/dbtransaction.cpp new file mode 100755 index 000000000..a7cfe825d --- /dev/null +++ b/Z/src/ngldb/dbtransaction.cpp @@ -0,0 +1,82 @@ + + + +#include "dbtransaction.h" +#include "ngldb_logger.h" +#include + +thread_local int s_refCounter = 0; + +DBTransaction::DBTransaction(const QSqlDatabase &db) + : m_db(db) + , m_bCommitted(true) + , mLogger(NGLDB::getLogger("DBTransaction")) +{ + ++s_refCounter; + if (s_refCounter == 1) + begin(); +} + +DBTransaction::~DBTransaction() +{ + if (s_refCounter == 1) + { + if (!m_bCommitted) + rollback(); + } + --s_refCounter; +} + +bool DBTransaction::begin() +{ + if (!m_bCommitted) + return setState(false); + if (!m_db.transaction()) + { + ERROR_LOG(mLogger) << "Error starting a transaction: " << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = false; + return setState(true); +} + +bool DBTransaction::commit() +{ + if (s_refCounter == 1) + { + if (!m_db.commit()) + { + ERROR_LOG(mLogger) << "Error committing a transaction: " << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = true; + return setState(true); + } + return true; +} + +bool DBTransaction::rollback() +{ + if (s_refCounter == 1) + { + if (!m_db.rollback()) + { + ERROR_LOG(mLogger) << "Error rolling back a transaction" << m_db.lastError().driverText(); + return setState(false); + } + m_bCommitted = true; + return setState(true); + } + return true; +} + +bool DBTransaction::state() const +{ + return m_lastState; +} + +bool DBTransaction::setState(bool bState) +{ + m_lastState = bState; + return m_lastState; +} diff --git a/Z/src/ngldb/dbtransaction.h b/Z/src/ngldb/dbtransaction.h new file mode 100755 index 000000000..2803a06a5 --- /dev/null +++ b/Z/src/ngldb/dbtransaction.h @@ -0,0 +1,48 @@ + + +#pragma once + +#include + +#include "ngldb_export.h" + +namespace NGL +{ +class INGLLogger; +} + + +class NGLDB_EXPORT DBTransaction +{ +public: + + + explicit DBTransaction(const QSqlDatabase &db); + + + + ~DBTransaction(); + + + + bool begin(); + + + bool commit(); + + + bool rollback(); + + + bool state() const; + +private: + bool setState(bool bState); + + QSqlDatabase m_db; + bool m_bCommitted; + bool m_lastState; + NGL::INGLLogger &mLogger; +}; + + diff --git a/Z/src/ngldb/ngldb_export.h b/Z/src/ngldb/ngldb_export.h new file mode 100755 index 000000000..eecef03c2 --- /dev/null +++ b/Z/src/ngldb/ngldb_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLDB_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLDB_EXPORT +# else +# if defined(MAKE_NGLDB_LIB) +# define NGLDB_EXPORT Q_DECL_EXPORT +# else +# define NGLDB_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/ngldb/ngldb_logger.cpp b/Z/src/ngldb/ngldb_logger.cpp new file mode 100755 index 000000000..d7f1342ea --- /dev/null +++ b/Z/src/ngldb/ngldb_logger.cpp @@ -0,0 +1,24 @@ + + + +#include "ngldb_logger.h" +#include + +NGLDB::LOGGER_T NGLDB::getLogger(const char *name) +{ + static const char ns[] = "NGLDB."; + 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(); + } +} diff --git a/Z/src/ngldb/ngldb_logger.h b/Z/src/ngldb/ngldb_logger.h new file mode 100755 index 000000000..7326f9a16 --- /dev/null +++ b/Z/src/ngldb/ngldb_logger.h @@ -0,0 +1,31 @@ + + + +#pragma once + +#include + +#ifdef Q_CC_GNU +#define DB_TRACE_FUNCTION __PRETTY_FUNCTION__ +#else +#define DB_TRACE_FUNCTION __FUNCTION__ +#endif + +#ifdef NGLDB_ENABLE_TRACE +#define DB_TRACE { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION } +#define DB_TRACE2(x) { TRACE_LOG(mLogger) << DB_TRACE_FUNCTION << x } +#else +#define DB_TRACE +#define DB_TRACE2(x) +#endif + +namespace NGLDB +{ +typedef NGL::INGLLogger &LOGGER_T; + +LOGGER_T getLogger(const char *name); +inline LOGGER_T getLogger(const QString &loggerName) +{ + return getLogger(loggerName.toUtf8().constData()); +} +} diff --git a/Z/src/ngldb/nsqlquery.cpp b/Z/src/ngldb/nsqlquery.cpp new file mode 100755 index 000000000..261401068 --- /dev/null +++ b/Z/src/ngldb/nsqlquery.cpp @@ -0,0 +1,457 @@ + + +#include "nsqlquery.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngldb_logger.h" +#include + +static QString getSqlErrorString(const QSqlError &error) +{ + return error.driverText() + QLatin1Char(' ') + + error.databaseText() + QLatin1Char(' ') + + error.nativeErrorCode(); +} + +NSqlQuery::NSqlQuery(const QSqlDatabase &db) + : QSqlQuery(db) + , m_db(db) + , mLogger(NGLDB::getLogger("NSqlQuery")) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger) + : QSqlQuery(db) + , m_db(db) + , mLogger(logger) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db) + : QSqlQuery(query, db) + , m_db(db) + , mLogger(NGLDB::getLogger("NSqlQuery")) +{ + DB_TRACE + setForwardOnly(true); +} + +NSqlQuery::NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger) + : QSqlQuery(query, db) + , m_db(db) + , mLogger(logger) +{ + DB_TRACE + setForwardOnly(true); +} + +void NSqlQuery::addBindValue(const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + DEBUG_LOG(mLogger) << "type: " << val.type() << " paramType: " << paramType; + QSqlQuery::addBindValue(val, paramType); +} + +int NSqlQuery::at() const +{ + DB_TRACE + return QSqlQuery::at(); +} + +void NSqlQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + TRACE_LOG(mLogger) << "placeholder: " << placeholder << " type: " << val.type() << " paramType: " << paramType; + QSqlQuery::bindValue(placeholder, val, paramType); +} + +void NSqlQuery::bindValue(int pos, const QVariant &val, QSql::ParamType paramType) +{ + DB_TRACE; + TRACE_LOG(mLogger) << "pos: " << pos << " type: " << val.type() << " paramType: " << paramType; + QSqlQuery::bindValue(pos, val, paramType); +} + +QVariant NSqlQuery::boundValue(const QString &placeholder) const +{ + DB_TRACE + TRACE_LOG(mLogger) << "placeholder: " << placeholder; + return QSqlQuery::boundValue(placeholder); +} + +QVariant NSqlQuery::boundValue(int pos) const +{ + DB_TRACE + TRACE_LOG(mLogger) << "pos: " << pos; + return QSqlQuery::boundValue(pos); +} + +QMap NSqlQuery::boundValues() const +{ + DB_TRACE + return QSqlQuery::boundValues(); +} + +void NSqlQuery::clear() +{ + DB_TRACE + return QSqlQuery::clear(); +} + +const QSqlDriver *NSqlQuery::driver() const +{ + DB_TRACE + return QSqlQuery::driver(); +} + +bool NSqlQuery::exec(const QString &query, bool bEmitMessageOnError) +{ + DB_TRACE; + DEBUG_LOG(mLogger) << "query: " << query; + if (QSqlQuery::exec(query)) + return true; + if (bEmitMessageOnError) + printLastSqlError(); + return false; +} + +bool NSqlQuery::exec(bool bEmitMessageOnError) +{ + DB_TRACE + DEBUG_LOG(mLogger) << "query: " << lastQuery(); + + if (mLogger.isDebugEnabled()) + { + const QMap &boundValuesMap = boundValues(); + for (auto it=boundValuesMap.begin(); it != boundValuesMap.end(); ++it) + { + if ( it.value().canConvert()) + DEBUG_LOG(mLogger) << "key='" << it.key() << "' value='" << it.value().toString() << "'"; + else + DEBUG_LOG(mLogger) << "key='" << it.key() << "' value cant Convert to string'"; + } + } + if (QSqlQuery::exec()) + return true; + if (bEmitMessageOnError) + printLastSqlError(); + return false; +} + +bool NSqlQuery::execAndFetch() +{ + DB_TRACE + if (!exec()) + return false; + return (next()); +} + +bool NSqlQuery::execAndFetch(const QString &query) +{ + DB_TRACE + if (!exec(query)) + return false; + return (next()); +} + +bool NSqlQuery::execBatch(BatchExecutionMode mode) +{ + DB_TRACE2("mode: " << mode) + DEBUG_LOG(mLogger) << "mode: " << mode; + if (QSqlQuery::execBatch(mode)) + return true; + printLastSqlError(); + return false; +} + +QString NSqlQuery::executedQuery() const +{ + DB_TRACE + return QSqlQuery::executedQuery(); +} + +void NSqlQuery::finish() +{ + DB_TRACE + QSqlQuery::finish(); +} + +bool NSqlQuery::first() +{ + DB_TRACE + if (QSqlQuery::first()) + return true; + printLastSqlError(); + return false; +} + +bool NSqlQuery::isActive() const +{ + DB_TRACE + return QSqlQuery::isActive(); +} + +bool NSqlQuery::isForwardOnly() const +{ + DB_TRACE + return QSqlQuery::isForwardOnly(); +} + +bool NSqlQuery::isNull(int field) const +{ + DB_TRACE2("field: " << field) + return QSqlQuery::isNull(field); +} + +bool NSqlQuery::isSelect() const +{ + DB_TRACE + return QSqlQuery::isSelect(); +} + +bool NSqlQuery::isValid() const +{ + DB_TRACE + return QSqlQuery::isValid(); +} + +bool NSqlQuery::last() +{ + DB_TRACE + if (QSqlQuery::last()) + return true; + printLastSqlError(); + return false; +} + +QSqlError NSqlQuery::lastError() const +{ + DB_TRACE + return QSqlQuery::lastError(); +} + +QString NSqlQuery::sqlstate() +{ + const QVariant resultHandle = this->result()->handle(); + + + + + if (resultHandle.isValid() && (qstrcmp(resultHandle.typeName(), "PGresult*") == 0)) + { + + const PGresult *pgresHandle = *static_cast(resultHandle.data()); + + if (pgresHandle != nullptr) + { + + return QString::fromLocal8Bit(PQresultErrorField(pgresHandle, PG_DIAG_SQLSTATE)); + } + } + + + return QStringLiteral("58000"); +} + +QVariant NSqlQuery::lastInsertId() +{ + DB_TRACE + + QVariant ret; + + if (this->driver()->hasFeature(QSqlDriver::LastInsertId)) + ret = QSqlQuery::lastInsertId(); + + if (!ret.isValid()) + { + NSqlQuery q(m_db); + if (q.execAndFetch(QLatin1String("SELECT LASTVAL()"))) + ret = q.value(0); + } + return ret; +} + +QString NSqlQuery::lastQuery() const +{ + DB_TRACE + return QSqlQuery::lastQuery(); +} + +bool NSqlQuery::next() +{ + DB_TRACE + return QSqlQuery::next(); +} + +bool NSqlQuery::nextResult() +{ + DB_TRACE + if (QSqlQuery::nextResult()) + return true; + printLastSqlError(); + return false; +} + +int NSqlQuery::numRowsAffected() const +{ + DB_TRACE + return QSqlQuery::numRowsAffected(); +} + +QSql::NumericalPrecisionPolicy NSqlQuery::numericalPrecisionPolicy() const +{ + DB_TRACE + return QSqlQuery::numericalPrecisionPolicy(); +} + +bool NSqlQuery::prepare(const QString &query) +{ + DB_TRACE2("query: " << query) + if (QSqlQuery::prepare(query)) + return true; + printLastSqlError(); + return false; +} + +bool NSqlQuery::previous() +{ + DB_TRACE + if (QSqlQuery::previous()) + return true; + printLastSqlError(); + return false; +} + +QSqlRecord NSqlQuery::record() const +{ + DB_TRACE + return QSqlQuery::record(); +} + +const QSqlResult *NSqlQuery::result() const +{ + DB_TRACE + return QSqlQuery::result(); +} + +bool NSqlQuery::seek(int index, bool relative) +{ + DB_TRACE2("index: " << index << " relative: " << relative); + if (QSqlQuery::seek(index, relative)) + return true; + printLastSqlError(); + return false; +} + +void NSqlQuery::setForwardOnly(bool forward) +{ + DB_TRACE2("forward: " << forward); + QSqlQuery::setForwardOnly(forward); +} + +void NSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy) +{ + DB_TRACE2("precisionPolicy: " << precisionPolicy); + QSqlQuery::setNumericalPrecisionPolicy(precisionPolicy); +} + +int NSqlQuery::size() const +{ + DB_TRACE + return QSqlQuery::size(); +} + +QVariant NSqlQuery::value(int index) const +{ + DB_TRACE2("index: " << index) + return QSqlQuery::value(index); +} + +NSqlQuery &NSqlQuery::operator= (const NSqlQuery &other) +{ + DB_TRACE + QSqlQuery::operator= (other); + return *this; +} + +bool NSqlQuery::export2CSV(const QString &filename) +{ + DB_TRACE2("export csv to file: " << filename) + QFile data(filename); + QTextStream output(&data); + if (data.open(QFile::WriteOnly | QFile::Truncate)) + { + if (isSelect() && isActive()) + { + bool isHeaderWritten = false; + while (next()) + { + QSqlRecord rec = record(); + if (!isHeaderWritten) + { + for (int i = 0; i < rec.count(); ++i) + output << QLatin1Char('\"') + rec.fieldName(i) + QLatin1String("\","); + output << QLatin1Char('\n'); + isHeaderWritten = true; + } + for (int i = 0; i < rec.count(); ++i) + output << QLatin1Char('\"') + rec.value(i).toString() + QLatin1String("\","); + output << QLatin1Char('\n'); + } + } + data.close(); + return true; + } + return false; +} + +QVariant NSqlQuery::qDateTimeToQVariant(const QDateTime &dt) +{ + if (dt.isValid()) + return dt.toMSecsSinceEpoch(); + return QVariant(); +} + +QDateTime NSqlQuery::qVariantToQDateTime(const QVariant &var) +{ + if (var.isNull()) + return QDateTime(); + return QDateTime::fromMSecsSinceEpoch(var.toLongLong()); +} + +QString NSqlQuery::qVariantToJsonString(const QVariant &value) +{ + if (value.isNull()) + return QStringLiteral("{}"); + return value.toString(); +} + +QString NSqlQuery::jsonValueToJsonString(const QJsonValue &value) +{ + if (value.isNull()) + return QStringLiteral("{}"); + return value.toString(); +} + +void NSqlQuery::printLastSqlError() +{ + ERROR_LOG(mLogger) << getSqlErrorString(lastError()) << " " << lastQuery(); +} + +QString NSqlQuery::getLastSqlError() +{ + return (getSqlErrorString(lastError()) + QLatin1Char(' ') + lastQuery()); +} diff --git a/Z/src/ngldb/nsqlquery.h b/Z/src/ngldb/nsqlquery.h new file mode 100755 index 000000000..a813283e4 --- /dev/null +++ b/Z/src/ngldb/nsqlquery.h @@ -0,0 +1,222 @@ + + + +#pragma once + +#include + +#include "ngldb_export.h" +#include "dbcommon.h" + +namespace NGL +{ +class INGLLogger; +} +class QDateTime; +class QJsonValue; + + + +class NGLDB_EXPORT NSqlQuery final : public QSqlQuery +{ +public: + + + explicit NSqlQuery(const QSqlDatabase &db); + explicit NSqlQuery(const QSqlDatabase &db, NGL::INGLLogger &logger); + explicit NSqlQuery(const QString &query, const QSqlDatabase &db); + explicit NSqlQuery(const QString &query, const QSqlDatabase &db, NGL::INGLLogger &logger); + + + + NSqlQuery(const NSqlQuery &other) = default; + + + + ~NSqlQuery() = default; + + + + void addBindValue(const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + int at() const; + + + + void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + void bindValue(int pos, const QVariant &val, QSql::ParamType paramType = QSql::In); + + + + QVariant boundValue(const QString &placeholder) const; + + + + QVariant boundValue(int pos) const; + + + + QMap boundValues() const; + + + + void clear(); + + + + const QSqlDriver *driver() const; + + + + bool exec(const QString &query, bool bEmitMessageOnError = true); + + + + bool exec(bool bEmitMessageOnError = true); + + + + bool execAndFetch(); + + + + bool execAndFetch(const QString &query); + + + + bool execBatch(BatchExecutionMode mode = ValuesAsRows); + + + + QString executedQuery() const; + + + + void finish(); + + + + bool first(); + + + + bool isActive() const; + + + + bool isForwardOnly() const; + + + + bool isNull(int field) const; + + + + bool isSelect() const; + + + + bool isValid() const; + + + + bool last(); + + + + QSqlError lastError() const; + + QString sqlstate(); + + + QVariant lastInsertId(); + + + + QString lastQuery() const; + + + + bool next(); + + + + bool nextResult(); + + + + int numRowsAffected() const; + + + + QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const; + + + + bool prepare(const QString &query); + + + + bool previous(); + + + + QSqlRecord record() const; + + + + const QSqlResult *result() const; + + + + bool seek(int index, bool relative = false); + + + + void setForwardOnly(bool forward); + + + + void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy); + + + + int size() const; + + + + QVariant value(int index) const; + + + + NSqlQuery &operator= (const NSqlQuery &other); + + bool export2CSV(const QString &filename); + + + + static QVariant qDateTimeToQVariant(const QDateTime &dt); + + + static QDateTime qVariantToQDateTime(const QVariant &var); + + + static QString qVariantToJsonString(const QVariant &value); + + + static QString jsonValueToJsonString(const QJsonValue &value); + + static inline QString fixupEmptyJsonString(const QString &str) { return str.isEmpty() ? QLatin1String("{}") : str; } + + QString getLastSqlError(); + +private: + void printLastSqlError(); + QSqlDatabase m_db; + NGL::INGLLogger &mLogger; +}; diff --git a/Z/src/ngldb/sql_query_janitor.cpp b/Z/src/ngldb/sql_query_janitor.cpp new file mode 100755 index 000000000..8c15015cb --- /dev/null +++ b/Z/src/ngldb/sql_query_janitor.cpp @@ -0,0 +1,24 @@ + + + +#include "sql_query_janitor.h" +#include "nsqlquery.h" +#include + + +SqlQueryJanitor::SqlQueryJanitor(NSqlQuery *query) + : m_query(query) +{ + Q_ASSERT(m_query); + Q_ASSERT(!m_query->isActive()); +} + +SqlQueryJanitor::SqlQueryJanitor(const std::unique_ptr &query) + : SqlQueryJanitor(query.get()) +{ +} + +SqlQueryJanitor::~SqlQueryJanitor() +{ + m_query->finish(); +} diff --git a/Z/src/ngldb/sql_query_janitor.h b/Z/src/ngldb/sql_query_janitor.h new file mode 100755 index 000000000..f26e4bcf2 --- /dev/null +++ b/Z/src/ngldb/sql_query_janitor.h @@ -0,0 +1,22 @@ + + + +#pragma once + +#include "ngldb_export.h" +#include + +class NSqlQuery; + + + +class NGLDB_EXPORT SqlQueryJanitor +{ +public: + explicit SqlQueryJanitor(NSqlQuery *query); + explicit SqlQueryJanitor(const std::unique_ptr &query); + ~SqlQueryJanitor(); + +private: + NSqlQuery *m_query; +}; diff --git a/Z/src/nglsettings/CMakeLists.txt b/Z/src/nglsettings/CMakeLists.txt new file mode 100755 index 000000000..6a234d4f7 --- /dev/null +++ b/Z/src/nglsettings/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# CMake Script für nglsettings +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(nglsettings_SRCS + nglsettings_connections.cpp + nglsettings_settings.cpp +) + +SET(nglsettings_HDRS + nglsettings_connections.h + nglsettings_export.h + nglsettings_settings.h +) + +NGL_ADD_LIBRARY(ALL nglsettings SHARED ${nglsettings_SRCS} ${nglsettings_HDRS}) +NGL_TARGET_LINK_LIBRARIES(nglsettings + PRIVATE + ngltools + Qt5::Network + PUBLIC + Qt5::Core +) + +NGL_TARGET_INCLUDE_DIRECTORIES(nglsettings + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(nglsettings) diff --git a/Z/src/nglsettings/nglsettings_connections.cpp b/Z/src/nglsettings/nglsettings_connections.cpp new file mode 100755 index 000000000..1ac078cc0 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_connections.cpp @@ -0,0 +1,175 @@ + + +#include "nglsettings_connections.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace NGL +{ +namespace Connections +{ +enum class eHostConfig +{ + public_local, + localhost, + server, + server_avs +}; +struct configStruct +{ + eHostConfig host; + unsigned short port; + QString name; +}; + +static QMap *s_config = nullptr; +static QSettings *s_settings = nullptr; +static unsigned short s_portOffset = 9000; +static QString *s_serverHostname = nullptr; + +static void cleanupSettings() +{ + delete s_settings; + s_settings = nullptr; + delete s_serverHostname; + s_serverHostname = nullptr; + delete s_config; + s_config = nullptr; +} + +static void insertConfig(eConnection conn, eHostConfig host, unsigned short port, const char *name) +{ + if (!s_config) + s_config = new QMap(); + configStruct s; + s.host = host; + s.port = port; + s.name = QString::fromLatin1(name); + s_config->insert(conn, s); +} + +static void initConfig() +{ + if (s_config && !s_config->isEmpty()) + return; + + insertConfig(eConnection::AVS_WORKSTATION, eHostConfig::localhost, 6370, "AVS_WORKSTATION"); + insertConfig(eConnection::AVS_WORKSTATION_VD, eHostConfig::localhost, 6380, "AVS_WORKSTATION_VD"); + insertConfig(eConnection::AVS_ROOT, eHostConfig::server_avs, 6350, "AVS_ROOT"); + insertConfig(eConnection::AVS_FM, eHostConfig::server_avs, 6360, "AVS_FM"); + insertConfig(eConnection::AVS_MOTION_RECORDER, eHostConfig::server_avs, 6390, "AVS_MOTION_RECORDER"); + insertConfig(eConnection::AVS_AVA, eHostConfig::server_avs, 6391, "AVS_AVA"); + + insertConfig(eConnection::PWS_WEBSOCKET, eHostConfig::server, 5701, "PWS_WEBSOCKET"); + insertConfig(eConnection::SCM_WEBSOCKET, eHostConfig::server, 7300, "SCM_WEBSOCKET"); + insertConfig(eConnection::ISM_WEBSOCKET, eHostConfig::server, 2080, "ISM_WEBSOCKET"); + insertConfig(eConnection::FLM_THP_SERVER, eHostConfig::server, 2090, "FLM_THP_SERVER"); + insertConfig(eConnection::FLM_PDF_SERVER, eHostConfig::server, 3000, "FLM_PDF_SERVER"); + + insertConfig(eConnection::LVS, eHostConfig::server, 94, "LVS"); + insertConfig(eConnection::ZWLVSV, eHostConfig::server, 95, "ZWLVSV"); + insertConfig(eConnection::ZWLVWCS, eHostConfig::server, 97, "ZWLVWCS"); + insertConfig(eConnection::ZWLVWMS, eHostConfig::server, 98, "ZWLVWMS"); + insertConfig(eConnection::ZSLV, eHostConfig::server, 99, "ZSLV"); +} + +void setIniFile(const QString &iniFileName) +{ + if (!s_settings) + qAddPostRoutine(cleanupSettings); + delete s_settings; + s_settings = new QSettings(iniFileName, QSettings::IniFormat); +} + +QString iniFile() +{ + return s_settings ? s_settings->fileName() : QString(); +} + +unsigned short portOffset() +{ + return s_portOffset; +} + +void setPortOffset(unsigned short portOffset) +{ + s_portOffset = portOffset; +} + +unsigned short port(eConnection connection) +{ + initConfig(); + unsigned short port = s_config->value(connection).port; + + if (s_settings) + { + bool bOk; + QString key = s_config->value(connection).name + QLatin1String("/port"); + unsigned short port2 = s_settings->value(key, port).toString().toUShort(&bOk); + if (bOk) + port = port2; + } + if (port < 100) + return portOffset() + port; + return port; +} + +QString hostName(eConnection connection) +{ + initConfig(); + + QString host; + switch (s_config->value(connection).host) + { + case eHostConfig::public_local: + host = QString::fromLocal8Bit(qgetenv("HOST")); + break; + case eHostConfig::localhost: + host = QLatin1String("127.0.0.1"); + break; + case eHostConfig::server: + if (s_serverHostname) + host = *s_serverHostname; + if (host.isEmpty()) + host = QLatin1String("EXCTDS01"); + break; + case eHostConfig::server_avs: + host = QStringLiteral("EXCAVS01"); + break; + } + if (s_settings) + { + QString key = s_config->value(connection).name + QLatin1String("/host"); + QString host2 = s_settings->value(key, host).toString(); + if (!host2.isEmpty()) + host = host2; + } + return host; +} + +void setServerHostname(const QString &serverHostName) +{ + if (!s_serverHostname) + s_serverHostname = new QString(serverHostName); + else + *s_serverHostname = serverHostName; +} + +QString connectionName(eConnection connection) +{ + if (s_config) + { + auto it = s_config->constFind(connection); + if (it != s_config->constEnd()) + return it.value().name; + } + return QString::number((int)connection); +} +} +} diff --git a/Z/src/nglsettings/nglsettings_connections.h b/Z/src/nglsettings/nglsettings_connections.h new file mode 100755 index 000000000..205e4a9c3 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_connections.h @@ -0,0 +1,59 @@ + + +#pragma once + +#include +#include "nglsettings_export.h" + +namespace NGL +{ + + +namespace Connections +{ + + +enum class eConnection +{ + UNKNOWN = 0, + AVS_WORKSTATION, + AVS_WORKSTATION_VD, + AVS_ROOT, + AVS_FM, + AVS_MOTION_RECORDER, + AVS_AVA, + ZWLVSV, + ZSLV, + ZWLVWCS, + ZWLVWMS, + PWS_WEBSOCKET, + SCM_WEBSOCKET, + ISM_WEBSOCKET, + FLM_THP_SERVER, + FLM_PDF_SERVER, + LVS , +}; + + + +NGLSETTINGS_EXPORT void setIniFile(const QString &iniFileName); + + +NGLSETTINGS_EXPORT QString iniFile(); + + + +NGLSETTINGS_EXPORT unsigned short portOffset(); +void setPortOffset(unsigned short portOffset); + + +NGLSETTINGS_EXPORT unsigned short port(eConnection connection); + + +NGLSETTINGS_EXPORT QString hostName(eConnection connection); +void setServerHostname(const QString &serverHostName); + + +NGLSETTINGS_EXPORT QString connectionName(eConnection connection); +} +} diff --git a/Z/src/nglsettings/nglsettings_export.h b/Z/src/nglsettings/nglsettings_export.h new file mode 100755 index 000000000..0da7e5511 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLSETTINGS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLSETTINGS_EXPORT +# else +# ifdef MAKE_NGLSETTINGS_LIB +# define NGLSETTINGS_EXPORT Q_DECL_EXPORT +# else +# define NGLSETTINGS_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/nglsettings/nglsettings_settings.cpp b/Z/src/nglsettings/nglsettings_settings.cpp new file mode 100755 index 000000000..b795651f1 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_settings.cpp @@ -0,0 +1,320 @@ + + +#include "nglsettings_settings.h" +#include "nglsettings_connections.h" + +#include + +#include +#include +#include +#include +#include + +namespace NGL +{ + QSettings *Settings::s_globalSettings = nullptr; + + Settings::Settings(const QString &iniFile_) + : m_settings(nullptr) + { + QString iniFile = iniFile_; + if(iniFile == QLatin1String("gfs_ws.ini")) { + const QByteArray defUser = qgetenv("USER"); + if( defUser == "ctc_aar" || defUser == "ctc_rbf" ) { + QByteArray home = qgetenv("HOME"); + if(!home.isEmpty()) { + QString fn = QString::fromLocal8Bit(home) + + QLatin1String("/gfs_") + + QString::fromLocal8Bit(defUser.mid(4)) + + QLatin1String(".ini"); + QFileInfo fi(fn); + if(fi.exists() && fi.isFile() && fi.isReadable()) { + iniFile = fn; + } + } + } + } + + initializeGlobalSettings(); + + initPre(); + if(!iniFile.isEmpty()) { + if(QFileInfo(iniFile).isAbsolute()) + m_settings = new QSettings(iniFile, QSettings::IniFormat); + else + m_settings = new QSettings(basePath() + iniFile, QSettings::IniFormat); + initPost(); + } + + if (!m_settings) + m_settings = new QSettings(QLatin1String("RDE")); + } + + Settings::Settings(const QString &organization, const QString &application) + : m_settings(new QSettings(organization, application)) + { + initPre(); + initPost(); + } + + Settings::~Settings() + { + delete m_settings; + } + + void Settings::initializeGlobalSettings() + { + if (s_globalSettings) + return; + + if (!s_globalSettings) + { + QString globalSettingsFile = NGL::findProjectConfigFile(); + + + if (!globalSettingsFile.isEmpty()) + s_globalSettings = new QSettings(globalSettingsFile, QSettings::IniFormat); + } + if (!s_globalSettings) + s_globalSettings = new QSettings(QLatin1String("RDE"), QLatin1String("LTS-CC")); + Connections::setPortOffset(portOffset()); + Connections::setServerHostname(serverHostname()); + } + + QString Settings::globalSectionName() + { + QString secName = QLatin1String("Global"); + static const char envGlobSecName[] = "LTS_CONF_GLOBAL_SECTION_NAME"; + if (qEnvironmentVariableIsSet(envGlobSecName)) + secName = QString::fromLocal8Bit(qgetenv(envGlobSecName)); + + return secName; + } + + QString Settings::basePath() const + { + return m_paths["GFS_PATH"]; + } + + QString Settings::tempPath() const + { + return m_paths["TMP_PATH"]; + } + + QString Settings::printPath() + { + return getDirectory("PDF", tempPath()); + } + + QString Settings::logoProject() + { + return QLatin1String(":project/logo.png"); + } + + QString Settings::bitmapPath() + { + return getDirectory("BITMAPS", basePath() + QLatin1String("DATA")); + } + + QString Settings::zsks_rxPath() + { + return getDirectory("ZSKS_RX", tempPath()); + } + + QString Settings::zsks_txPath() + { + return getDirectory("ZSKS_TX", tempPath()); + } + + QString Settings::aarServerPath(int exerciseId) + { + return getDirectory(QByteArray::number(exerciseId), QString::fromLocal8Bit("/data/aar/")); + } + + bool Settings::isDatabaseConnectionLocal() + { + return (databaseHostname() == QStringLiteral("localhost")); + } + + QString Settings::databaseName() + { + initializeGlobalSettings(); + + return s_globalSettings->value(globalSectionName()+ QLatin1String("/DatabaseName"), QLatin1String("lts_ets_pro")).toString(); + } + + QString Settings::databaseHostname() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/DatabaseHostname"), QLatin1String("EXCDBS01")).toString(); + } + + QString Settings::databaseUser() + { +#ifdef Q_OS_WIN + QByteArray defUser = qgetenv("USERNAME"); +#else + QByteArray defUser = qgetenv("USER"); +#endif + QString ret = m_settings->value(QLatin1String("db/user"), QString::fromLocal8Bit(defUser)).toString(); + return ret; + } + + QString Settings::databasePassword(const QString &databaseUser) + { + QString defaultPw = QStringLiteral("ctc11de"); + if (!databaseUser.isEmpty()) + { + const QVector &sl = databaseUser.splitRef(QLatin1Char('_')); + if (sl.size() > 1) + defaultPw = sl.at(0).toString() + QStringLiteral("11de"); + } + return m_settings->value(QLatin1String("db/passwd"), defaultPw).toString(); + } + + QString Settings::databaseDriver() + { + return m_settings->value(QLatin1String("db/driver"), QLatin1String("QPSQL")).toString(); + } + + int Settings::avsKeepAliveTimeout() + { + return m_settings->value(QLatin1String("avs/keepalivetimeout"), 20000).toInt(); + } + + QString Settings::avsServerHost() + { + return m_settings->value(QLatin1String("avs/serverhost"), QLatin1String("EXCAVS01")).toString(); + } + + quint16 Settings::avsServerPortAVE() + { + static const quint16 defaultPort = 6350; + bool bOk; + quint16 ret = m_settings->value(QLatin1String("avs/serverport_ave"), defaultPort).toUInt(&bOk); + return bOk ? ret : defaultPort; + } + + QSettings *Settings::settings() + { + return m_settings; + } + + const QSettings *Settings::settings() const + { + return m_settings; + } + + QString Settings::fixupPath(const QString &_path) const + { + QString path = QDir::fromNativeSeparators(_path); + if(!QDir::isAbsolutePath(path)) + path = basePath() + path; + path = QDir::cleanPath(path); + if(!path.endsWith(QLatin1Char('/'))) + path += QLatin1Char('/'); + return path; + } + + QString Settings::getDirectory(const QByteArray &_dir, const QString &defPrefix, bool bPathLowercase) + { + if(m_paths[_dir].isEmpty()) { + const QString lowerDir = QString::fromLatin1(_dir.toLower()); + const QString dir = bPathLowercase ? lowerDir : QString::fromLatin1(_dir); + QString def = defPrefix + QLatin1Char('/') + dir + QLatin1Char('/'); + m_paths[_dir] = fixupPath(m_settings->value(QLatin1String("paths/") + lowerDir, def).toString()); + QDir d(m_paths[_dir]); + if(!d.exists()) + d.mkpath(d.absolutePath()); + } + return m_paths[_dir]; + } + + void Settings::initPre() + { +#ifdef WIN32 + QString path = QString::fromLocal8Bit(qgetenv("GFS_PATH")); + if(path.isEmpty()) + path = QCoreApplication::applicationDirPath(); + m_paths["GFS_PATH"] = fixupPath(path); +#else + QByteArray path = qgetenv("GFS_PATH"); + if(path.isEmpty()) + path = qgetenv("HOME"); + m_paths["GFS_PATH"] = fixupPath(QString::fromLocal8Bit(path)); +#endif + + QByteArray tmppath = qgetenv("TMP_PATH"); + if(tmppath.isEmpty()) + tmppath = qgetenv("TMP"); + if (tmppath.isEmpty()) + tmppath = QDir::tempPath().toLocal8Bit(); + m_paths["TMP_PATH"] = fixupPath(QString::fromLocal8Bit(tmppath)); + } + + void Settings::initPost() + { + NGL::Connections::setIniFile(m_settings->fileName()); + } + + int Settings::getInteger(const QString &key, int defVal) const + { + bool bOk; + int ret = m_settings->value(key, defVal).toInt(&bOk); + return bOk ? ret : defVal; + } + + float Settings::getFloat(const QString &key, float defVal) const + { + bool bOk; + float ret = m_settings->value(key, defVal).toFloat(&bOk); + return bOk ? ret : defVal; + } + + double Settings::getDouble(const QString &key, double defVal) const + { + bool bOk; + double ret = m_settings->value(key, defVal).toDouble(&bOk); + return bOk ? ret : defVal; + } + + bool Settings::getBoolean(const QString &key, bool defVal) const + { + return m_settings->value(key, defVal).toBool(); + } + + QString Settings::getString(const QString &key, const QString &defVal) const + { + return m_settings->value(key, defVal).toString(); + } + + unsigned short Settings::domainId() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/DomainId"), 0).toUInt(); + } + + unsigned short Settings::portOffset() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/PortOffset"), 9000).toUInt(); + } + + QString Settings::serverHostname() + { + initializeGlobalSettings(); + return s_globalSettings->value(QLatin1String("Global/ServerHostname"), QLatin1String("EXCTDS01")).toString(); + } + + QString Settings::logPath() + { + initializeGlobalSettings(); +#ifdef WIN32 + return s_globalSettings->value(QLatin1String("Global/LogPath"), QStandardPaths::writableLocation(QStandardPaths::TempLocation)).toString(); +#else + return s_globalSettings->value(QLatin1String("Global/LogPath"), QLatin1String("/shd/CTC/LOG")).toString(); +#endif + } + +} diff --git a/Z/src/nglsettings/nglsettings_settings.h b/Z/src/nglsettings/nglsettings_settings.h new file mode 100755 index 000000000..e59947099 --- /dev/null +++ b/Z/src/nglsettings/nglsettings_settings.h @@ -0,0 +1,142 @@ + + +#pragma once + +#include +#include +#include "nglsettings_export.h" + +class QSettings; + +namespace NGL { + + + class NGLSETTINGS_EXPORT Settings { + public: + + + explicit Settings(const QString &iniFile); + + + + explicit Settings(const QString &organization, const QString &application); + + Settings(const Settings&) = delete; + Settings &operator=(const Settings&) = delete; + + + + virtual ~Settings(); + + + static void initializeGlobalSettings(); + + + QString basePath() const; + + QString tempPath() const; + + QString printPath(); + + QString logoProject(); + + QString bitmapPath(); + + + + QString zsks_rxPath(); + + QString zsks_txPath(); + + + + static QString databaseName(); + + static QString databaseHostname(); + + QString databaseUser(); + + QString databasePassword(const QString &databaseUser = QString()); + + QString databaseDriver(); + + + + QString aarServerPath(int exerciseId); + bool isDatabaseConnectionLocal(); + + + int avsKeepAliveTimeout(); + QString avsServerHost(); + quint16 avsServerPortAVE(); + + + QSettings *settings(); + + const QSettings *settings() const; + + + int getInteger(const QString &key, int defVal) const; + + + int getInteger(const QString &group, const QString &key, int defVal) const + { + return getInteger(group + QLatin1Char('/') + key, defVal); + } + + + float getFloat(const QString &key, float defVal) const; + + + float getFloat(const QString &group, const QString &key, float defVal) const + { + return getFloat(group + QLatin1Char('/') + key, defVal); + } + + + double getDouble(const QString &key, double defVal) const; + + + double getDouble(const QString &group, const QString &key, double defVal) const + { + return getDouble(group + QLatin1Char('/') + key, defVal); + } + + + bool getBoolean(const QString &key, bool defVal) const; + + + bool getBoolean(const QString &group, const QString &key, bool defVal) const + { + return getBoolean(group + QLatin1Char('/') + key, defVal); + } + + + QString getString(const QString &key, const QString &defVal) const; + + + QString getString(const QString &group, const QString &key, const QString &defVal) const + { + return getString(group + QLatin1Char('/') + key, defVal); + } + + static unsigned short portOffset(); + static unsigned short domainId(); + static QString serverHostname(); + static QString logPath(); + static QString globalSectionName(); + + private: + + QString fixupPath(const QString &path) const; + + + QString getDirectory(const QByteArray &dir, const QString &defPrefix, bool bPathLowercase = false); + private: + void initPre(); + void initPost(); + QSettings *m_settings; + static QSettings *s_globalSettings; + QHash m_paths; + }; +} diff --git a/Z/src/ngltools/CMakeLists.txt b/Z/src/ngltools/CMakeLists.txt new file mode 100755 index 000000000..fa6688a8f --- /dev/null +++ b/Z/src/ngltools/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# CMake Script für ngltools +# $Id$ +# $HeadURL$ +# $Author$ +# + +SET(ngltools_SRCS + ngltools_bitset.h + ngltools_convert.cpp + ngltools_convert.h + ngltools_dtg.cpp + ngltools_dtg.h + ngltools_export.h + ngltools_filesystem.cpp + ngltools_filesystem.h + ngltools_helpevent.cpp + ngltools_helpevent.h +) + +NGL_ADD_LIBRARY(ALL ngltools SHARED ${ngltools_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngltools + PUBLIC + Qt5::Core +) +NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC BUILD_BASE_PATH="${CMAKE_BINARY_DIR}") +NGL_TARGET_COMPILE_DEFINITIONS(ngltools PUBLIC INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") + + +NGL_TARGET_INCLUDE_DIRECTORIES(ngltools + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(ngltools) diff --git a/Z/src/ngltools/ngltools_bitset.h b/Z/src/ngltools/ngltools_bitset.h new file mode 100755 index 000000000..4141cf376 --- /dev/null +++ b/Z/src/ngltools/ngltools_bitset.h @@ -0,0 +1,100 @@ + + + +#pragma once + +namespace NGL { + template + class BitSet { + public: + BitSet(T bitset = T()) + : mBitSet(bitset) + , mSize(sizeof(T)*8) + {} + BitSet(const BitSet &other) + : mBitSet(other.mBitSet) + , mSize(other.mSize) + {} + BitSet &operator=(const BitSet &other) + { + if(this == &other) + return *this; + mBitSet = other.mBitSet; + mSize = other.mSize; + return *this; + } + bool operator==(const BitSet &other) const + { + return (mBitSet == other.mBitSet && mSize == other.mSize); + } + bool setBit(unsigned int bitNum) + { + if(bitNum >= mSize) + return false; + mBitSet |= getBit(bitNum); + return true; + } + + bool clearBit(unsigned int bitNum) + { + if(bitNum >= mSize) + return false; + mBitSet &= ~(getBit(bitNum)); + return true; + } + + bool at(unsigned int bitNum) const + { + if(bitNum >= sizeof(T) * 8) + return false; + T compVal = getBit(bitNum); + return ((mBitSet & compVal) == compVal); + } + + bool operator[] (unsigned int bitNum) const + { + return at(bitNum); + } + + size_t size() const + { + return mSize; + } + + bool resize(size_t newSize) + { + if(newSize >= sizeof(T) * 8) + return false; + for(unsigned int i = mSize; i < newSize; ++i) + clearBit(i); + mSize = newSize; + return true; + } + + void clear() + { + fill(false); + } + + void fill(bool bBitsSet) + { + if(bBitsSet) + mBitSet = ~T(); + else + mBitSet = T(); + } + + T operator()() const { return mBitSet; } + + protected: + static T getBit(unsigned int bitNum_) + { + T bitNum = bitNum_; + const T one = 1; + return (one << bitNum); + } + + T mBitSet; + size_t mSize; + }; +} diff --git a/Z/src/ngltools/ngltools_convert.cpp b/Z/src/ngltools/ngltools_convert.cpp new file mode 100755 index 000000000..f3f77b3ac --- /dev/null +++ b/Z/src/ngltools/ngltools_convert.cpp @@ -0,0 +1,91 @@ +#include "ngltools_convert.h" + +#include + +namespace NGL +{ +QByteArray quoteForTelnet(const QVector &sl) +{ + QVector tmp; + tmp.reserve(sl.size()); + for (const QString &s : sl) + tmp += s.toUtf8(); + return quoteForTelnet(tmp); +} + +QByteArray quoteForTelnet(const QVector &sl) +{ + QByteArray cmd; + for (QByteArray s : sl) + { + s.replace('\"', "\\\""); + if (s.contains(' ')) + s = '"' + s + '"'; + if (s.isEmpty()) + s = "\"\""; + cmd += s + ' '; + } + cmd += '\n'; + return cmd; +} + + +QVector parseFromTelnet(const QByteArray &ba, const int iStart) +{ + QVector ret; + const char *p = ba.constData() + iStart; + const int iLen = ba.length(); + const char *p_end = ba.constData() + iLen; + if (iLen <= iStart) + return ret; + char quoteEndChar = '"'; + + while (p < p_end && *p) + { + while (isspace(*p)) + ++p; + if (*p && p < p_end) + { + bool escaped = false; + bool bQuoted = (*p == '\"') || (*p == '{'); + if (bQuoted) + { + quoteEndChar = (*p == '\"') ? '\"' : '}'; + ++p; + } + const char *start = p; + while (true) + { + while (p < p_end && *p != (bQuoted ? quoteEndChar : ' ')) + ++p; + if (bQuoted) + { + + if (* (p - 1) == '\\') + { + ++p; + escaped = true; + continue; + } + } + QByteArray result = QByteArray(start, p - start).trimmed(); + if (escaped) + { + if (quoteEndChar == '}') + { + result = result.replace("\\{", "{"); + result = result.replace("\\}", "}"); + } + else + result = result.replace("\\\"", "\""); + } + ret += result; + ++p; + break; + } + } + } + return ret; +} + +} diff --git a/Z/src/ngltools/ngltools_convert.h b/Z/src/ngltools/ngltools_convert.h new file mode 100755 index 000000000..46d0af437 --- /dev/null +++ b/Z/src/ngltools/ngltools_convert.h @@ -0,0 +1,23 @@ + + + +#pragma once + +#include "ngltools_export.h" + +#include +#include +#include + +namespace NGL +{ +NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector &sl); +NGLTOOLS_EXPORT QByteArray quoteForTelnet(const QVector &sl); + + +NGLTOOLS_EXPORT QVector parseFromTelnet(const QByteArray &ba, const int iStart = 0); +} + + + + diff --git a/Z/src/ngltools/ngltools_dtg.cpp b/Z/src/ngltools/ngltools_dtg.cpp new file mode 100755 index 000000000..66c4f656c --- /dev/null +++ b/Z/src/ngltools/ngltools_dtg.cpp @@ -0,0 +1,372 @@ +#include "ngltools_dtg.h" + +#include +#include + +namespace DTG +{ + +static char s_timezone = 'Z'; +static char s_userDefinedTimezone = s_timezone; +static char s_exerciseDefaultTimezone = s_timezone; +int timezone2Hours(char tz, bool *bOk) +{ + if (!isTimezoneValid(tz)) + { + if (bOk) + *bOk = false; + return 0; + } + if (bOk) + *bOk = true; + if (tz < 'J') + return tz - 'A' + 1; + if (tz < 'N') + return tz - 'A'; + if (tz < 'Z') + return 'Z' - tz - 13; + + return 0; +} + +int timezone2Secs(char tz, bool *bOk) +{ + return 3600 * timezone2Hours(tz, bOk) ; +} + + +bool setTimezone(char tz, bool bUserDefinedZone) +{ + if (!isTimezoneValid(tz)) + { + + if (!(tz == 0 && bUserDefinedZone)) + return false; + } + if (bUserDefinedZone) + s_userDefinedTimezone = tz; + else + s_exerciseDefaultTimezone = tz; + + s_timezone = s_userDefinedTimezone != 0 ? s_userDefinedTimezone : s_exerciseDefaultTimezone; + return true; +} + +char timezone() +{ + return s_timezone; +} +char timezoneUserDefined() +{ + return s_userDefinedTimezone; +} +char timezoneExerciseDefault() +{ + return s_exerciseDefaultTimezone; +} + +bool isTimezoneValid(char tz) +{ + tz = toupper(tz); + return !(tz < 'A' || tz == 'J' || tz > 'Z'); +} + + + +static DateTimeType s_dateTimeType = DDMMYYYY_Z_HHMMSS; +static DisplayFormat s_defaultDisplayFormat = Long; + + +void setDateTimeType(DateTimeType dtType) +{ + s_dateTimeType = dtType; +} + +DateTimeType dateTimeType() +{ + return s_dateTimeType; +} + +void setDefaultDisplayFormat(DisplayFormat dtFormat) +{ + s_defaultDisplayFormat = dtFormat; +} + +DisplayFormat defaultDisplayFormat() +{ + return s_defaultDisplayFormat; +} + +QString toString(const QDateTime &dt, DisplayFormat format, DateTimeType type) +{ + if (format == Default) + format = s_defaultDisplayFormat; + static const QDateTime dtNull = QDateTime::fromSecsSinceEpoch(0); + if (!dt.isValid() || dt == dtNull) + return QString(); + + const QDateTime dateTime = dt.toUTC().addSecs(timezone2Hours(s_timezone) * 3600); + QString ret; + + switch (type) + { + case DTG: + { + + + + QString str1; + + if (format == Long) + str1 = dateTime.toString(QLatin1String("dd hhmmss")); + else if (format == TurboLong) + str1 = dateTime.toString(QLatin1String("dd hhmmss.z")); + else + { + ret = dateTime.toString(QLatin1String("ddhhmm")) + QLatin1Char(s_timezone); + break; + } + + + const int month = dateTime.date().month() - 1; + const int year = dateTime.date().year() - 2000; + ret = QStringLiteral("%1 %2 %3 %4") + .arg(str1) + .arg(QLatin1Char(s_timezone)) + .arg(months().at(month)) + .arg(year, 2, 10, QLatin1Char('0')); + } + break; + case DDMMYYYY_HHMMSS_Z: + { + if (format == Long) + ret = dateTime.toString(QLatin1String("dd.MM.yyyy HH:mm:ss")) + QLatin1Char(s_timezone); + else + ret = dateTime.toString(QLatin1String("dd.MM HH:mm")) + QLatin1Char(s_timezone); + + } + break; + case DDMMYYYY_Z_HHMMSS: + if (format == Long) + ret = dateTime.toString(QLatin1String("dd.MM.yyyy ")) + + QLatin1Char(s_timezone) + + dateTime.toString(QLatin1String(" HH:mm:ss")); + else + ret = dateTime.toString(QLatin1String("dd.MM ")) + + QLatin1Char(s_timezone) + + dateTime.toString(QLatin1String(" HH:mm")); + break; + } + + + return ret; +} + +QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format) +{ + if (msecSinceEpoch <= 0) + return QString(); + return toString(QDateTime::fromMSecsSinceEpoch(msecSinceEpoch), format); +} + + +static bool check24(const QChar *input, int *output) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 2) + return false; + if (i1 == 2 && i2 > 5) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static bool check31(const QChar *input, int *output = nullptr) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 3) + return false; + if (i1 == 3 && i2 > 1) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static bool check60(const QChar *input, int *output) +{ + const int i1 = input[0].unicode() - '0'; + const int i2 = input[1].unicode() - '0'; + if (i1 > 5) + return false; + if (output) + *output = i1 * 10 + i2; + return true; +} + +static DTGValidation validate18(const QString &input, QDateTime &dt) +{ + int hh, mm, ss; + + for (int i = 0; i < 2; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check31(&input.data() [0])) + return Invalid; + + if (input[2] != QLatin1Char(' ')) + return Invalid; + + if (input.length() == 7) + { + for (int i = 3; i < 7; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + return Intermediate; + } + for (int i = 3; i < 9; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check24(&input.data() [3], &hh)) + return Invalid; + if (!check60(&input.data() [5], &mm)) + return Invalid; + if (!check60(&input.data() [7], &ss)) + return Invalid; + + if (input[9] != QLatin1Char(' ')) + return Invalid; + + const QChar c = input[10]; + if (c < QLatin1Char('A') || c > QLatin1Char('Z')) + return Invalid; + if (c == QLatin1Char('J')) + { + + return Invalid; + } + + const QString mon = input.mid(12, 3); + int month = months().indexOf(mon); + if (month < 0) + { + + return Invalid; + } + + for (int i = 16; i < 18; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + + + const int day = input.leftRef(2).toInt(); + const int year = input.midRef(16, 2).toInt() + 2000; + dt = QDateTime(QDate(year, month + 1, day), QTime(hh, mm, ss), Qt::UTC); + if (!dt.isValid()) + { + + return Invalid; + } + dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600); + + + return Acceptable; +} + +static DTGValidation validate7(const QString &input, QDateTime &dt) +{ + int hh, mm; + + for (int i = 0; i < 6; ++i) + { + if (!input[i].isDigit()) + return Invalid; + } + if (!check31(&input.data() [0])) + return Invalid; + if (!check24(&input.data() [2], &hh)) + return Invalid; + if (!check60(&input.data() [4], &mm)) + return Invalid; + + + const QChar c = input[6]; + if (c < QLatin1Char('A') || c > QLatin1Char('Z')) + return Invalid; + if (c == QLatin1Char('J')) + { + + return Invalid; + } + + + const int day = input.leftRef(2).toInt(); + const QDate curDate = QDate::currentDate(); + dt = QDateTime(QDate(curDate.year(), curDate.month(), day), QTime(hh, mm), Qt::UTC); + if (!dt.isValid()) + { + + return Invalid; + } + dt = dt.addSecs(-timezone2Hours(c.toLatin1()) * 3600); + + + return Acceptable; +} + +QDateTime fromDTGString(const QString &str, bool *bOk) +{ + if (bOk) + *bOk = false; + + QDateTime dt; + if (str.length() == 7) + { + DTGValidation state = validate7(str, dt); + if (state == Acceptable && bOk) + *bOk = true; + } + else if (str.length() == 18) + { + DTGValidation state = validate18(str, dt); + if (state == Acceptable && bOk) + *bOk = true; + } + return dt; +} + +DTGValidation validateString(const QString &str, QDateTime &dt) +{ + const int len = str.length(); + if (len == 7 || len == 18) + { + + if (len == 18 || (str[2] == QLatin1Char(' '))) + return validate18(str, dt); + return validate7(str, dt); + } + return Invalid; +} + +QStringList months() +{ + return { + QLatin1String("jan"), QLatin1String("feb"), QLatin1String("mar"), + QLatin1String("apr"), QLatin1String("may"), QLatin1String("jun"), + QLatin1String("jul"), QLatin1String("aug"), QLatin1String("sep"), + QLatin1String("oct"), QLatin1String("nov"), QLatin1String("dec") + }; +} + +} diff --git a/Z/src/ngltools/ngltools_dtg.h b/Z/src/ngltools/ngltools_dtg.h new file mode 100755 index 000000000..fe14277b8 --- /dev/null +++ b/Z/src/ngltools/ngltools_dtg.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include "ngltools_export.h" + +class QDateTime; + + +namespace DTG +{ + + + +enum DateTimeType +{ + DTG = 1, + DDMMYYYY_HHMMSS_Z = 2, + DDMMYYYY_Z_HHMMSS = 4 +}; + + + + +enum DisplayFormat +{ + Short, + Long, + TurboLong, + Default +}; + +enum DTGValidation +{ + Invalid, + Intermediate, + Acceptable +}; + + + +NGLTOOLS_EXPORT void setDateTimeType(DateTimeType dtType); + + +NGLTOOLS_EXPORT DateTimeType dateTimeType(); + + + +NGLTOOLS_EXPORT void setDefaultDisplayFormat(DisplayFormat dtFormat); + + +NGLTOOLS_EXPORT DisplayFormat defaultDisplayFormat(); + + + +NGLTOOLS_EXPORT QString toString(const QDateTime &dt, DisplayFormat format = Default, DateTimeType = dateTimeType()); + + +NGLTOOLS_EXPORT QString toStringMSec(qint64 msecSinceEpoch, DisplayFormat format = Default); + + + +NGLTOOLS_EXPORT QDateTime fromDTGString(const QString &str, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT DTGValidation validateString(const QString &str, QDateTime &dt); + + + +NGLTOOLS_EXPORT bool setTimezone(char tz, bool bUserDefinedZone); + + +NGLTOOLS_EXPORT char timezone(); +NGLTOOLS_EXPORT char timezoneUserDefined(); +NGLTOOLS_EXPORT char timezoneExerciseDefault(); + +NGLTOOLS_EXPORT bool isTimezoneValid(char tz); + + +NGLTOOLS_EXPORT int timezone2Hours(char tz, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT int timezone2Secs(char tz, bool *bOk = nullptr); + + +NGLTOOLS_EXPORT QStringList months(); + +} diff --git a/Z/src/ngltools/ngltools_export.h b/Z/src/ngltools/ngltools_export.h new file mode 100755 index 000000000..1ae2a789c --- /dev/null +++ b/Z/src/ngltools/ngltools_export.h @@ -0,0 +1,19 @@ + + +#pragma once + +#ifndef NGLTOOLS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLTOOLS_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLTOOLS_LIB +# define NGLTOOLS_EXPORT __declspec(dllexport) +# else +# define NGLTOOLS_EXPORT __declspec(dllimport) +# endif +# else +# define NGLTOOLS_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif diff --git a/Z/src/ngltools/ngltools_filesystem.cpp b/Z/src/ngltools/ngltools_filesystem.cpp new file mode 100755 index 000000000..8f3dda2fe --- /dev/null +++ b/Z/src/ngltools/ngltools_filesystem.cpp @@ -0,0 +1,289 @@ + + + +#include "ngltools_filesystem.h" + +#include +#include +#include + +namespace NGL +{ + +bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir) +{ + + QDir dir(d); + if (!dir.exists()) + return false; + + bool success = true; + const QFileInfoList list = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries); + for (const QFileInfo &fi : list) + { + bool ret = false; + if (fi.isDir()) + { + ret = removeDirContentsRecursively(fi.absoluteFilePath()); + if (!ret) + { + + } + else + { + ret = dir.rmdir(fi.absoluteFilePath()); + if (!ret) + { + + } + } + + } + else if (fi.isFile() || fi.isSymLink()) + { + ret = dir.remove(fi.fileName()); + if (!ret) + { + + } + } + success &= ret; + } + if (bAlsoDeleteBaseDir) + success &= dir.rmpath(d); + return success; +} + +bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative) +{ + QString srcPath(source); + + if (sourceIsRelative) + { + QVector pathsToSearch = directories(FileType::ConfigFile); + pathsToSearch.append(directories(FileType::ProjectConfigFile)); + for (const QString &basePath : qAsConst(pathsToSearch)) + { + QString absolutePath = basePath + QLatin1Char('/') + source; + if (QDir(absolutePath).exists()) + { + srcPath = absolutePath; + break; + } + } + if (srcPath.isEmpty()) + return false; + } + + QDir srcDir(srcPath); + QDir dstDir(destination); + + if (!dstDir.exists()) + { + bool succ = dstDir.mkdir(destination); + if (!succ) + return false; + } + + const QFileInfoList dirList = srcDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + for (const QFileInfo &fi : dirList) + { + + if (!dstDir.exists()) + { + bool succ = dstDir.mkdir(fi.fileName()); + if (!succ) + return false; + } + bool succ = copyDirContentsToDir(fi.filePath(), dstDir.absolutePath() + QLatin1Char('/') + fi.fileName()); + if (!succ) + return false; + } + + const QFileInfoList fileList = srcDir.entryInfoList(QDir::Files | QDir::Hidden); + for (const QFileInfo &fi : fileList) + { + QString targetFileName = dstDir.absolutePath() + QLatin1Char('/') + fi.fileName(); + QFile targetFile(targetFileName); + if (targetFile.exists()) + targetFile.remove(); + bool succ = QFile::copy(fi.absoluteFilePath(), targetFileName); + if (!succ) + return false; + } + return true; +} + +qint64 getDirectorySize(const QString &dir) +{ + QDir d(dir); + qint64 ret = QFileInfo(dir).size(); + + const QFileInfoList dirList = d.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + const QFileInfoList fileList = d.entryInfoList(QDir::Files | QDir::Hidden); + + for (const QFileInfo &fi : dirList) + ret += getDirectorySize(fi.absoluteFilePath()); + + for (const QFileInfo &fi : fileList) + ret += fi.size(); + + return ret; +} + +bool isAppInBuildBasePath() +{ + bool ret = false; +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + ret = QCoreApplication::applicationDirPath().startsWith(bbp); +#endif + return ret; +} + +QString projectConfigFileName() +{ + return QLatin1String("lts-cc.conf"); +} + +QString findProjectConfigFile() +{ + return findFile(FileType::ProjectConfigFile, projectConfigFileName()); +} + +static QString searchFileInDir(const QString &path, const QString &filename, bool bRecursive) +{ + if (QFile::exists(path + QLatin1Char('/') + filename)) + return path + QLatin1Char('/') + filename; + + if (!bRecursive) + return QString(); + + const QDir d(path); + const QStringList entryList = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); + for (const QString &entry : entryList) + { + const QString foundPath = searchFileInDir(path + QLatin1Char('/') + entry, filename, bRecursive); + if (!foundPath.isEmpty()) + return foundPath; + } + return QString(); +} + +QString findFile(FileType fileType, const QString &filename) +{ + const QFileInfo fi(filename); + if (fi.isAbsolute()) + return fi.exists() ? filename : QString(); + const bool bRecursive = (fileType == FileType::ConfigFile); + const QVector pathsToSearch = directories(fileType); + for (const QString &path : pathsToSearch) + { + const QString foundPath = searchFileInDir(path, filename, bRecursive); + if (!foundPath.isEmpty()) + return foundPath; + } + return QString(); +} + +QVector directories(FileType fileType) +{ + QVector pathsToSearch; + switch (fileType) + { + case FileType::ProjectConfigFile: + { +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + { + + + + if (QCoreApplication::applicationDirPath().startsWith(bbp)) + pathsToSearch += bbp; + } +#endif + pathsToSearch += QDir::homePath(); +#ifdef Q_OS_UNIX + pathsToSearch += QLatin1String("/etc"); +#else + pathsToSearch += QStringLiteral("C:/Rheinmetall/Lts/"); + pathsToSearch += QCoreApplication::applicationDirPath(); +#endif + break; + } + case FileType::ConfigFile: + { +#ifdef BUILD_BASE_PATH + const QString bbp(QString::fromLocal8Bit(BUILD_BASE_PATH)); + if (!bbp.isEmpty()) + { + + + + if (QCoreApplication::applicationDirPath().startsWith(bbp)) + pathsToSearch += bbp + QLatin1String("/share/Lts"); + } +#endif + pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/share/Lts"); + pathsToSearch += QCoreApplication::applicationDirPath() + QLatin1String("/../share/Lts"); + pathsToSearch += QDir::homePath() + QLatin1String("/share/Lts"); +#ifdef INSTALL_PREFIX + pathsToSearch += QString::fromLocal8Bit(INSTALL_PREFIX) + QLatin1String("/share/Lts"); +#endif + break; + } + } + return pathsToSearch; +} +QString findServiceXmlFile(const QString &serviceShortName) +{ + return findFile(FileType::ConfigFile, serviceShortName + QLatin1String(".xml")); +} + +QString directory(FileType fileType, const QString &subdir) +{ + const QVector pathsToSearch = directories(fileType); + QFileInfo fi; + for (const QString &path : pathsToSearch) + { + fi.setFile(path + QLatin1Char('/') + subdir); + if (fi.isDir() && fi.exists() && fi.isReadable()) + return fi.absoluteFilePath() + QLatin1Char('/'); + } + return QString(); +} + +QString postgresExecutablePath(const QString &psqlProgram, QString &errStr) +{ + errStr.clear(); +#ifdef Q_OS_LINUX + return QStringLiteral("/usr/bin/") + psqlProgram; +#else + static QString s_postgresBinariesPath; + if (s_postgresBinariesPath.isEmpty()) + { + QSettings s(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\PostgreSQL\\Installations"), QSettings::NativeFormat); + const QStringList installations = s.childGroups(); + if (installations.isEmpty()) + { + errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation..."); + return psqlProgram; + } + if (installations.size() > 1) + errStr = QStringLiteral("More than one PostgreSQL windows installation found - using the first one: %1").arg(installations.first()); + s.beginGroup(installations.first()); + const QString baseDir = s.value(QStringLiteral("Base Directory")).toString(); + if (baseDir.isEmpty() || !QDir(baseDir).exists()) + { + errStr = QStringLiteral("Could not find a valid PostgreSQL windows installation... - Base Directory is empty or does not exist (%1)").arg(baseDir); + return psqlProgram; + } + s_postgresBinariesPath = baseDir + QStringLiteral("/bin/"); + } + return s_postgresBinariesPath + psqlProgram + QStringLiteral(".exe"); +#endif +} +} diff --git a/Z/src/ngltools/ngltools_filesystem.h b/Z/src/ngltools/ngltools_filesystem.h new file mode 100755 index 000000000..cfd571e66 --- /dev/null +++ b/Z/src/ngltools/ngltools_filesystem.h @@ -0,0 +1,38 @@ + + + +#pragma once + +#include "ngltools_export.h" + +#include +#include + +namespace NGL +{ + NGLTOOLS_EXPORT bool removeDirContentsRecursively(const QString &d, bool bAlsoDeleteBaseDir = false); + NGLTOOLS_EXPORT bool copyDirContentsToDir(const QString &source, const QString &destination, bool sourceIsRelative = false); + NGLTOOLS_EXPORT qint64 getDirectorySize(const QString &dir); + + + enum class FileType + { + ProjectConfigFile, + ConfigFile + }; + + NGLTOOLS_EXPORT bool isAppInBuildBasePath(); + NGLTOOLS_EXPORT QString projectConfigFileName(); + NGLTOOLS_EXPORT QString findProjectConfigFile(); + NGLTOOLS_EXPORT QString findFile(FileType fileType, const QString &filename); + + + NGLTOOLS_EXPORT QString findServiceXmlFile(const QString &serviceShortName); + + NGLTOOLS_EXPORT QVector directories(FileType fileType); + + NGLTOOLS_EXPORT QString directory(FileType fileType, const QString &subdir); + + + NGLTOOLS_EXPORT QString postgresExecutablePath(const QString &psqlProgram, QString &errStr); +} diff --git a/Z/src/ngltools/ngltools_helpevent.cpp b/Z/src/ngltools/ngltools_helpevent.cpp new file mode 100755 index 000000000..dec4675d3 --- /dev/null +++ b/Z/src/ngltools/ngltools_helpevent.cpp @@ -0,0 +1,19 @@ + + +#include "ngltools_helpevent.h" +#include + +QEvent::Type NGLHelpEvent::sHelpEventId = (QEvent::Type)(-1); + +void NGLHelpEvent::sendHelpEvent(const QString &helpContext) +{ + NGLHelpEvent he(helpContext); + QCoreApplication::sendEvent(qApp, &he); +} + +QEvent::Type NGLHelpEvent::helpEventId() +{ + if(sHelpEventId < 0) + sHelpEventId = (QEvent::Type)(QEvent::registerEventType()); + return sHelpEventId; +} diff --git a/Z/src/ngltools/ngltools_helpevent.h b/Z/src/ngltools/ngltools_helpevent.h new file mode 100755 index 000000000..5ec87af55 --- /dev/null +++ b/Z/src/ngltools/ngltools_helpevent.h @@ -0,0 +1,34 @@ + + +#pragma once + +#include +#include +#include "ngltools_export.h" + + + +class NGLTOOLS_EXPORT NGLHelpEvent : public QEvent +{ +protected: + + + explicit NGLHelpEvent(const QString &helpContext) + : QEvent(helpEventId()) + , mHelpContext(helpContext) + {} +public: + + + QString helpContext() const { return mHelpContext; } + + + static void sendHelpEvent(const QString &helpContext); + + + static QEvent::Type helpEventId(); + +protected: + QString mHelpContext; + static QEvent::Type sHelpEventId; +}; diff --git a/Z/src/ngltranslator/CMakeLists.txt b/Z/src/ngltranslator/CMakeLists.txt new file mode 100755 index 000000000..3058ff8f7 --- /dev/null +++ b/Z/src/ngltranslator/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# ngltranslator lib +# $Id$ +# $HeadURL$ +# $Author$ +# +SET(my_SRCS + ngltranslator.cpp + ngltranslator.h + ngltranslator_export.h +) + +NGL_ADD_LIBRARY(ALL ngltranslator SHARED ${my_SRCS}) +NGL_TARGET_LINK_LIBRARIES(ngltranslator + PUBLIC + Qt5::Core +) +NGL_TARGET_INCLUDE_DIRECTORIES(ngltranslator + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +NGL_INSTALL_TARGET(ngltranslator) diff --git a/Z/src/ngltranslator/ngltranslator.cpp b/Z/src/ngltranslator/ngltranslator.cpp new file mode 100755 index 000000000..ec8c0e4ed --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator.cpp @@ -0,0 +1,222 @@ + + + +#include "ngltranslator.h" +#include "ngltranslator_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace NGL +{ + +struct TranslationData +{ + QByteArray isoCode; + QString qmPrefix; + QTranslator qtTranslator; + QTranslator kdReportsTranslator; + QTranslator ltsTranslator; + Translator dynamicTranslator; + + TranslationData() + { + QCoreApplication::installTranslator(&qtTranslator); + QCoreApplication::installTranslator(&kdReportsTranslator); + QCoreApplication::installTranslator(<sTranslator); + QCoreApplication::installTranslator(&dynamicTranslator); + } + ~TranslationData() + { + if (qApp) + { + QCoreApplication::removeTranslator(&qtTranslator); + QCoreApplication::removeTranslator(&kdReportsTranslator); + QCoreApplication::removeTranslator(<sTranslator); + QCoreApplication::removeTranslator(&dynamicTranslator); + } + } +}; + +Q_GLOBAL_STATIC(TranslationData, s_translationData) + + +Translator::Translator(QObject *parent) + : QTranslator(parent) +{} + + +void Translator::setTranslationCatalog(const TranslationCatalog &catalog) +{ + m_catalog = catalog; + m_md5Sum.clear(); + isoCodeChanged(s_translationData()->isoCode); +} + +bool Translator::setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed) +{ + if (m_md5Sum == md5Sum) + return true; + + const QJsonObject jObj = QJsonDocument::fromBinaryData(bCompressed ? qUncompress(jsonData) : jsonData).object(); + const QString translationKey(QStringLiteral("translations")); + if (jObj.empty() || + !jObj.contains(translationKey) || + !jObj.value(translationKey).isArray()) + return false; + + const QJsonArray arr = jObj[translationKey].toArray(); + + m_catalog.clear(); + m_catalog.reserve(arr.size()); + TranslationEntry te; + for (const QJsonValue &element : arr) + { + const QJsonObject obj = element.toObject(); + + te.isoCode = obj.value(QStringLiteral("isoCode")).toString().toUtf8(); + te.context = obj.value(QStringLiteral("context")).toString().toUtf8(); + te.key = obj.value(QStringLiteral("key")).toString().toUtf8(); + te.disambiguation = obj.value(QStringLiteral("disambiguation")).toString().toUtf8(); + te.translation = obj.value(QStringLiteral("translation")).toString(); + + m_catalog += te; + } + + m_md5Sum = md5Sum; + isoCodeChanged(s_translationData()->isoCode); + + return false; +} + + + +QString Translator::translate(const char *context, + const char *sourceText, + const char *disambiguation, + int n) const +{ + + if (n != -1) + return QString(); + + const auto itCtx = m_translationLookup.find(QByteArray::fromRawData(context, strlen(context))); + if (itCtx == m_translationLookup.end()) + return QString(); + const auto itKey = itCtx.value().find(QByteArray::fromRawData(sourceText, strlen(sourceText))); + if (itKey == itCtx.value().end()) + return QString(); + const auto itDis = itKey.value().find(disambiguation ? QByteArray::fromRawData(disambiguation, strlen(disambiguation)) : QByteArray()); + if (itDis == itKey.value().end()) + return QString(); + return itDis.value(); +} + + +void Translator::isoCodeChanged(const QByteArray &isoCode) +{ + m_translationLookup.clear(); + for (const TranslationEntry &te : qAsConst(m_catalog)) + { + if (te.isoCode != isoCode) + continue; + m_translationLookup[te.context][te.key][te.disambiguation] = te.translation; + } +} + + + + +void setTranslationCatalog(const TranslationCatalog &catalog) +{ + s_translationData()->dynamicTranslator.setTranslationCatalog(catalog); +} + + +bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed) +{ + return s_translationData()->dynamicTranslator.setTranslationDataJson(jsonData, md5Sum, bCompressed); +} + + +bool setTranslationLocale(const QByteArray &isoCode, const QString &qmPrefix) +{ + + if (s_translationData()->isoCode == isoCode && + s_translationData()->qmPrefix == qmPrefix) + return true; + + s_translationData()->isoCode = isoCode; + s_translationData()->qmPrefix = qmPrefix; + + const QString relTranslationPath = QLatin1Char('/') + QString::fromLatin1(isoCode) + QLatin1Char('/'); + const QStringList possiblePaths = { QCoreApplication::applicationDirPath() + QStringLiteral("/translations/"), + QCoreApplication::applicationDirPath() + QStringLiteral("/../translations/"), + QDir::homePath() + QStringLiteral("/translations/") + }; + const QString qm(QStringLiteral(".qm")); + + QString ltsQmPath; + for (const QString &path : possiblePaths) + { + const QString absPath = path + relTranslationPath; + if (!QDir(absPath).exists()) + continue; + if (QTranslator().load(qmPrefix + qm, absPath)) + { + ltsQmPath = absPath + qmPrefix + qm; + break; + } + } + + + QString kdReportsQmPath; + const QString kdReportsPrefix(QStringLiteral("kdreports")); + for (const QString &path : possiblePaths) + { + const QString absPath = path + relTranslationPath; + if (!QDir(absPath).exists()) + continue; + if (QTranslator().load(kdReportsPrefix + qm, absPath)) + { + kdReportsQmPath = absPath + kdReportsPrefix + qm; + break; + } + } + + + QStringList isoCodeList(QString::fromLatin1(isoCode).split(QLatin1Char('_'))); + if (isoCodeList.count() == 2) + { + s_translationData->qtTranslator.load(QLatin1String("qt_") + isoCodeList.at(0), + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + } + else + { + + qWarning() << "translation iso code not compatible with qt translations"; + } + + s_translationData->kdReportsTranslator.load(kdReportsQmPath); + s_translationData->ltsTranslator.load(ltsQmPath); + s_translationData->dynamicTranslator.isoCodeChanged(isoCode); + + return !s_translationData->ltsTranslator.isEmpty(); +} + + +QByteArray translationLocale() +{ + return s_translationData()->isoCode; +} + +} + diff --git a/Z/src/ngltranslator/ngltranslator.h b/Z/src/ngltranslator/ngltranslator.h new file mode 100755 index 000000000..5f661505d --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator.h @@ -0,0 +1,40 @@ + + + +#pragma once + +#include "ngltranslator_export.h" +#include +#include +#include + +namespace NGL +{ + +struct TranslationEntry +{ + QByteArray isoCode; + QByteArray context; + QByteArray key; + QByteArray disambiguation; + QString translation; +}; +using TranslationCatalog = QVector; + + + +NGLTRANSLATOR_EXPORT void setTranslationCatalog(const TranslationCatalog &catalog); + + + +NGLTRANSLATOR_EXPORT bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed); + + + +NGLTRANSLATOR_EXPORT bool setTranslationLocale(const QByteArray &isoCode, const QString &qmPrefix = QStringLiteral("tds")); + + + +NGLTRANSLATOR_EXPORT QByteArray translationLocale(); + +} diff --git a/Z/src/ngltranslator/ngltranslator_export.h b/Z/src/ngltranslator/ngltranslator_export.h new file mode 100755 index 000000000..90f802157 --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator_export.h @@ -0,0 +1,19 @@ + + +#pragma once + +#ifndef NGLTRANSLATOR_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLTRANSLATOR_EXPORT +# else +# ifdef WIN32 +# ifdef MAKE_NGLTRANSLATOR_LIB +# define NGLTRANSLATOR_EXPORT __declspec(dllexport) +# else +# define NGLTRANSLATOR_EXPORT __declspec(dllimport) +# endif +# else +# define NGLTRANSLATOR_EXPORT __attribute__((visibility("default"))) +# endif +# endif +#endif diff --git a/Z/src/ngltranslator/ngltranslator_p.h b/Z/src/ngltranslator/ngltranslator_p.h new file mode 100755 index 000000000..e8f7501b0 --- /dev/null +++ b/Z/src/ngltranslator/ngltranslator_p.h @@ -0,0 +1,34 @@ + + +#pragma once + +#include "ngltranslator.h" + +#include +#include + +namespace NGL +{ +class Translator final : public QTranslator +{ + Q_OBJECT +public: + explicit Translator(QObject *parent = nullptr); + + QString translate(const char *context, + const char *sourceText, + const char *disambiguation = nullptr, + int n = -1) const override; + + void setTranslationCatalog(const TranslationCatalog &catalog); + bool setTranslationDataJson(const QByteArray &jsonData, const QByteArray &md5Sum, bool bCompressed); + + void isoCodeChanged(const QByteArray &isoCode); +private: + + QHash>> m_translationLookup; + TranslationCatalog m_catalog; + QByteArray m_md5Sum; +}; + +} diff --git a/Z/src/nglwidgets/CMakeLists.txt b/Z/src/nglwidgets/CMakeLists.txt new file mode 100755 index 000000000..90110a1c3 --- /dev/null +++ b/Z/src/nglwidgets/CMakeLists.txt @@ -0,0 +1,52 @@ +PROJECT(nglwidgets) + +FIND_PACKAGE(PopplerQt5 REQUIRED) + +# +# NGL Widgets library +# +SET(nglwidgets_SRCS + ngldialogbuttonbox.cpp + ngldialogbuttonbox.h + ngldialog.cpp + ngldialog.h + nglmainwindow.cpp + nglmainwindow.h + nglpdfdocument.cpp + nglpdfdocument.h + nglpdfpage.cpp + nglpdfpage.h + nglstandardbutton.cpp + nglstandardbutton.h + ngltreeitem.cpp + ngltreeitem.h + ngltreemodel.cpp + ngltreemodel.h + nglpdfwidget.cpp + nglpdfwidget.h + nglwidgets_export.h +) + +NGL_WRAP_UI(nglwidgets_SRCS + nglpdfwidget.ui +) + +NGL_ADD_BIG_RESOURCES(oxygen_SRCS nglresources.qrc) +# SV: logView +NGL_ADD_LIBRARY(WS AAR SV nglwidgets SHARED ${nglwidgets_SRCS} ${oxygen_SRCS}) +NGL_TARGET_INCLUDE_DIRECTORIES(nglwidgets + PRIVATE + ${POPPLER_QT5_INCLUDE_DIR} +) +NGL_TARGET_LINK_LIBRARIES(nglwidgets + PRIVATE + NGLLogger + ngltranslator + ngltools + ${POPPLER_QT5_LIBRARY} + PUBLIC + Qt5::Core + Qt5::Widgets +) + +NGL_INSTALL_TARGET(nglwidgets) diff --git a/Z/src/nglwidgets/icons/16x16/LICENSE b/Z/src/nglwidgets/icons/16x16/LICENSE new file mode 100755 index 000000000..82f24a630 --- /dev/null +++ b/Z/src/nglwidgets/icons/16x16/LICENSE @@ -0,0 +1,24 @@ +Icon theme + +Oxygen icon theme is dual licensed. You may copy it under the Creative Common +Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +Creative Common Attribution-ShareAlike 3.0 License (short form): + +You are free: + + * to Share — to copy, distribute and transmit the work + * to Remix — to adapt the work + +Under the following conditions: + + * Attribution. You must attribute the work in the manner specified by the + author or licensor (but not in any way that suggests that they endorse + you or your use of the work). + + * Share Alike. If you alter, transform, or build upon this work, you may + distribute the resulting work only under the same, similar or a + compatible license. + +See also http://creativecommons.org/licenses/by-sa/3.0/ and +http://creativecommons.org/licenses/by-sa/3.0/legalcode diff --git a/Z/src/nglwidgets/icons/16x16/application-pdf.png b/Z/src/nglwidgets/icons/16x16/application-pdf.png new file mode 100755 index 000000000..9498f0ffd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/application-pdf.png differ diff --git a/Z/src/nglwidgets/icons/16x16/arrow-left.png b/Z/src/nglwidgets/icons/16x16/arrow-left.png new file mode 100755 index 000000000..b56cfee03 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/arrow-left.png differ diff --git a/Z/src/nglwidgets/icons/16x16/arrow-right.png b/Z/src/nglwidgets/icons/16x16/arrow-right.png new file mode 100755 index 000000000..0acee70bc Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/arrow-right.png differ diff --git a/Z/src/nglwidgets/icons/16x16/audio-x-generic.png b/Z/src/nglwidgets/icons/16x16/audio-x-generic.png new file mode 100755 index 000000000..017b00da9 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/audio-x-generic.png differ diff --git a/Z/src/nglwidgets/icons/16x16/bg.gif b/Z/src/nglwidgets/icons/16x16/bg.gif new file mode 100755 index 000000000..808f4b245 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/bg.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/camera-photo.png b/Z/src/nglwidgets/icons/16x16/camera-photo.png new file mode 100755 index 000000000..c8f6334ea Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/camera-photo.png differ diff --git a/Z/src/nglwidgets/icons/16x16/configure.png b/Z/src/nglwidgets/icons/16x16/configure.png new file mode 100755 index 000000000..5ce478b1a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/configure.png differ diff --git a/Z/src/nglwidgets/icons/16x16/dialog-close.png b/Z/src/nglwidgets/icons/16x16/dialog-close.png new file mode 100755 index 000000000..2c2f99eb4 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/dialog-close.png differ diff --git a/Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png b/Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png new file mode 100755 index 000000000..f1d290c64 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/dialog-ok-apply.png differ diff --git a/Z/src/nglwidgets/icons/16x16/dialog-ok.png b/Z/src/nglwidgets/icons/16x16/dialog-ok.png new file mode 100755 index 000000000..c173526fa Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/dialog-ok.png differ diff --git a/Z/src/nglwidgets/icons/16x16/dirs.png b/Z/src/nglwidgets/icons/16x16/dirs.png new file mode 100755 index 000000000..b348848b9 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/dirs.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-edit.png b/Z/src/nglwidgets/icons/16x16/document-edit.png new file mode 100755 index 000000000..84e345d22 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-edit.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-import.png b/Z/src/nglwidgets/icons/16x16/document-import.png new file mode 100755 index 000000000..66305f4ad Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-import.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-new.png b/Z/src/nglwidgets/icons/16x16/document-new.png new file mode 100755 index 000000000..8431237bd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-new.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-open-data.png b/Z/src/nglwidgets/icons/16x16/document-open-data.png new file mode 100755 index 000000000..69685ba6b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-open-data.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-open.png b/Z/src/nglwidgets/icons/16x16/document-open.png new file mode 100755 index 000000000..eb211e233 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-open.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-preview.png b/Z/src/nglwidgets/icons/16x16/document-preview.png new file mode 100755 index 000000000..3b674c3bd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-preview.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-print.png b/Z/src/nglwidgets/icons/16x16/document-print.png new file mode 100755 index 000000000..d35eaeda9 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-print.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-properties.png b/Z/src/nglwidgets/icons/16x16/document-properties.png new file mode 100755 index 000000000..d79aa5151 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-properties.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-save-all.png b/Z/src/nglwidgets/icons/16x16/document-save-all.png new file mode 100755 index 000000000..04ccba984 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-save-all.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-save-as.png b/Z/src/nglwidgets/icons/16x16/document-save-as.png new file mode 100755 index 000000000..821ca125f Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-save-as.png differ diff --git a/Z/src/nglwidgets/icons/16x16/document-save.png b/Z/src/nglwidgets/icons/16x16/document-save.png new file mode 100755 index 000000000..8072aea32 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/document-save.png differ diff --git a/Z/src/nglwidgets/icons/16x16/download.png b/Z/src/nglwidgets/icons/16x16/download.png new file mode 100755 index 000000000..d0746f663 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/download.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png b/Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png new file mode 100755 index 000000000..a77e19a48 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-bezier-curves.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-ellipse.png b/Z/src/nglwidgets/icons/16x16/draw-ellipse.png new file mode 100755 index 000000000..2f9dc846e Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-ellipse.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-line.png b/Z/src/nglwidgets/icons/16x16/draw-line.png new file mode 100755 index 000000000..f45eb91e5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-line.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-polygon.png b/Z/src/nglwidgets/icons/16x16/draw-polygon.png new file mode 100755 index 000000000..7125d33ab Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-polygon.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-polyline.png b/Z/src/nglwidgets/icons/16x16/draw-polyline.png new file mode 100755 index 000000000..35d7c0e05 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-polyline.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-rectangle.png b/Z/src/nglwidgets/icons/16x16/draw-rectangle.png new file mode 100755 index 000000000..22b75cad3 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-rectangle.png differ diff --git a/Z/src/nglwidgets/icons/16x16/draw-text.png b/Z/src/nglwidgets/icons/16x16/draw-text.png new file mode 100755 index 000000000..8db19da05 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/draw-text.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png b/Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png new file mode 100755 index 000000000..6c4b83b7a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-clear-locationbar-rtl.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-copy.png b/Z/src/nglwidgets/icons/16x16/edit-copy.png new file mode 100755 index 000000000..5cdeb5fc7 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-copy.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-cut.png b/Z/src/nglwidgets/icons/16x16/edit-cut.png new file mode 100755 index 000000000..f4a55e3d8 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-cut.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-delete.png b/Z/src/nglwidgets/icons/16x16/edit-delete.png new file mode 100755 index 000000000..d04a554ee Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-delete.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-paste.png b/Z/src/nglwidgets/icons/16x16/edit-paste.png new file mode 100755 index 000000000..a4e0a02fd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-paste.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-redo.png b/Z/src/nglwidgets/icons/16x16/edit-redo.png new file mode 100755 index 000000000..9bfee2d1f Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-redo.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-rename.png b/Z/src/nglwidgets/icons/16x16/edit-rename.png new file mode 100755 index 000000000..2323757e0 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-rename.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-select.png b/Z/src/nglwidgets/icons/16x16/edit-select.png new file mode 100755 index 000000000..e5a6e3397 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-select.png differ diff --git a/Z/src/nglwidgets/icons/16x16/edit-undo.png b/Z/src/nglwidgets/icons/16x16/edit-undo.png new file mode 100755 index 000000000..83e41dcf3 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/edit-undo.png differ diff --git a/Z/src/nglwidgets/icons/16x16/fill-color.png b/Z/src/nglwidgets/icons/16x16/fill-color.png new file mode 100755 index 000000000..6601f53c3 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/fill-color.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-center.png b/Z/src/nglwidgets/icons/16x16/format-justify-center.png new file mode 100755 index 000000000..2de15bf86 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-justify-center.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-fill.png b/Z/src/nglwidgets/icons/16x16/format-justify-fill.png new file mode 100755 index 000000000..a7e111fe5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-justify-fill.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-left.png b/Z/src/nglwidgets/icons/16x16/format-justify-left.png new file mode 100755 index 000000000..53d7d0996 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-justify-left.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-justify-right.png b/Z/src/nglwidgets/icons/16x16/format-justify-right.png new file mode 100755 index 000000000..3ba7eaddb Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-justify-right.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-stroke-color.png b/Z/src/nglwidgets/icons/16x16/format-stroke-color.png new file mode 100755 index 000000000..b89277074 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-stroke-color.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-text-bold.png b/Z/src/nglwidgets/icons/16x16/format-text-bold.png new file mode 100755 index 000000000..3abb164d1 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-text-bold.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-text-italic.png b/Z/src/nglwidgets/icons/16x16/format-text-italic.png new file mode 100755 index 000000000..093b355f1 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-text-italic.png differ diff --git a/Z/src/nglwidgets/icons/16x16/format-text-underline.png b/Z/src/nglwidgets/icons/16x16/format-text-underline.png new file mode 100755 index 000000000..7e47fb898 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/format-text-underline.png differ diff --git a/Z/src/nglwidgets/icons/16x16/freu.gif b/Z/src/nglwidgets/icons/16x16/freu.gif new file mode 100755 index 000000000..6e2b9e93b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/freu.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/go-down.png b/Z/src/nglwidgets/icons/16x16/go-down.png new file mode 100755 index 000000000..5891219e4 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/go-down.png differ diff --git a/Z/src/nglwidgets/icons/16x16/go-home.png b/Z/src/nglwidgets/icons/16x16/go-home.png new file mode 100755 index 000000000..aab6a883e Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/go-home.png differ diff --git a/Z/src/nglwidgets/icons/16x16/go-next.png b/Z/src/nglwidgets/icons/16x16/go-next.png new file mode 100755 index 000000000..a04c99e25 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/go-next.png differ diff --git a/Z/src/nglwidgets/icons/16x16/go-previous.png b/Z/src/nglwidgets/icons/16x16/go-previous.png new file mode 100755 index 000000000..940797b8a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/go-previous.png differ diff --git a/Z/src/nglwidgets/icons/16x16/go-up.png b/Z/src/nglwidgets/icons/16x16/go-up.png new file mode 100755 index 000000000..b3d9cef97 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/go-up.png differ diff --git a/Z/src/nglwidgets/icons/16x16/help-about.png b/Z/src/nglwidgets/icons/16x16/help-about.png new file mode 100755 index 000000000..e1eb7972d Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/help-about.png differ diff --git a/Z/src/nglwidgets/icons/16x16/help-contents.png b/Z/src/nglwidgets/icons/16x16/help-contents.png new file mode 100755 index 000000000..b3fbea8c5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/help-contents.png differ diff --git a/Z/src/nglwidgets/icons/16x16/image-x-generic.png b/Z/src/nglwidgets/icons/16x16/image-x-generic.png new file mode 100755 index 000000000..638dee693 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/image-x-generic.png differ diff --git a/Z/src/nglwidgets/icons/16x16/internet-mail.png b/Z/src/nglwidgets/icons/16x16/internet-mail.png new file mode 100755 index 000000000..d1e9f2b64 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/internet-mail.png differ diff --git a/Z/src/nglwidgets/icons/16x16/led-blue-on.png b/Z/src/nglwidgets/icons/16x16/led-blue-on.png new file mode 100755 index 000000000..9b681a03a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/led-blue-on.png differ diff --git a/Z/src/nglwidgets/icons/16x16/led-gray-on.png b/Z/src/nglwidgets/icons/16x16/led-gray-on.png new file mode 100755 index 000000000..3830ae432 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/led-gray-on.png differ diff --git a/Z/src/nglwidgets/icons/16x16/led-green-on.png b/Z/src/nglwidgets/icons/16x16/led-green-on.png new file mode 100755 index 000000000..86bf08a9f Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/led-green-on.png differ diff --git a/Z/src/nglwidgets/icons/16x16/led-red-on.png b/Z/src/nglwidgets/icons/16x16/led-red-on.png new file mode 100755 index 000000000..909840041 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/led-red-on.png differ diff --git a/Z/src/nglwidgets/icons/16x16/led-yellow-on.png b/Z/src/nglwidgets/icons/16x16/led-yellow-on.png new file mode 100755 index 000000000..9510330cd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/led-yellow-on.png differ diff --git a/Z/src/nglwidgets/icons/16x16/list-add-user.png b/Z/src/nglwidgets/icons/16x16/list-add-user.png new file mode 100755 index 000000000..20ec7f27a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/list-add-user.png differ diff --git a/Z/src/nglwidgets/icons/16x16/list-add.png b/Z/src/nglwidgets/icons/16x16/list-add.png new file mode 100755 index 000000000..1e03be9bc Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/list-add.png differ diff --git a/Z/src/nglwidgets/icons/16x16/list-remove-user.png b/Z/src/nglwidgets/icons/16x16/list-remove-user.png new file mode 100755 index 000000000..6ac1d6846 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/list-remove-user.png differ diff --git a/Z/src/nglwidgets/icons/16x16/list-remove.png b/Z/src/nglwidgets/icons/16x16/list-remove.png new file mode 100755 index 000000000..5a4d15b7b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/list-remove.png differ diff --git a/Z/src/nglwidgets/icons/16x16/mail-mark-read.png b/Z/src/nglwidgets/icons/16x16/mail-mark-read.png new file mode 100755 index 000000000..096ba774a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/mail-mark-read.png differ diff --git a/Z/src/nglwidgets/icons/16x16/mail-mark-unread.png b/Z/src/nglwidgets/icons/16x16/mail-mark-unread.png new file mode 100755 index 000000000..7ac192d52 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/mail-mark-unread.png differ diff --git a/Z/src/nglwidgets/icons/16x16/mail-message-new.png b/Z/src/nglwidgets/icons/16x16/mail-message-new.png new file mode 100755 index 000000000..ca3bb8e4f Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/mail-message-new.png differ diff --git a/Z/src/nglwidgets/icons/16x16/mail-send.png b/Z/src/nglwidgets/icons/16x16/mail-send.png new file mode 100755 index 000000000..459f7bb66 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/mail-send.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-eject.png b/Z/src/nglwidgets/icons/16x16/media-eject.png new file mode 100755 index 000000000..e0022f72c Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-eject.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-flash.png b/Z/src/nglwidgets/icons/16x16/media-flash.png new file mode 100755 index 000000000..04c45981c Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-flash.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-play-faster.png b/Z/src/nglwidgets/icons/16x16/media-play-faster.png new file mode 100755 index 000000000..930bd6010 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-play-faster.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-play-normal.png b/Z/src/nglwidgets/icons/16x16/media-play-normal.png new file mode 100755 index 000000000..500c38015 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-play-normal.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-play-slower.png b/Z/src/nglwidgets/icons/16x16/media-play-slower.png new file mode 100755 index 000000000..ad8523552 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-play-slower.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-playback-pause.png b/Z/src/nglwidgets/icons/16x16/media-playback-pause.png new file mode 100755 index 000000000..a9b3113fb Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-playback-pause.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-playback-start.png b/Z/src/nglwidgets/icons/16x16/media-playback-start.png new file mode 100755 index 000000000..80ff3a1d5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-playback-start.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-playback-stop.png b/Z/src/nglwidgets/icons/16x16/media-playback-stop.png new file mode 100755 index 000000000..180280e8b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-playback-stop.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-record.png b/Z/src/nglwidgets/icons/16x16/media-record.png new file mode 100755 index 000000000..1dc4efd4e Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-record.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-seek-backward.png b/Z/src/nglwidgets/icons/16x16/media-seek-backward.png new file mode 100755 index 000000000..6b7632706 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-seek-backward.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-seek-forward.png b/Z/src/nglwidgets/icons/16x16/media-seek-forward.png new file mode 100755 index 000000000..6c3b1c456 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-seek-forward.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-skip-backward.png b/Z/src/nglwidgets/icons/16x16/media-skip-backward.png new file mode 100755 index 000000000..1de5dbacf Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-skip-backward.png differ diff --git a/Z/src/nglwidgets/icons/16x16/media-skip-forward.png b/Z/src/nglwidgets/icons/16x16/media-skip-forward.png new file mode 100755 index 000000000..0d22924ee Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/media-skip-forward.png differ diff --git a/Z/src/nglwidgets/icons/16x16/oO.gif b/Z/src/nglwidgets/icons/16x16/oO.gif new file mode 100755 index 000000000..cdd8e27e4 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/oO.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/object-group.png b/Z/src/nglwidgets/icons/16x16/object-group.png new file mode 100755 index 000000000..89459cce3 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/object-group.png differ diff --git a/Z/src/nglwidgets/icons/16x16/object-ungroup.png b/Z/src/nglwidgets/icons/16x16/object-ungroup.png new file mode 100755 index 000000000..39071bc70 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/object-ungroup.png differ diff --git a/Z/src/nglwidgets/icons/16x16/ooo-calc.png b/Z/src/nglwidgets/icons/16x16/ooo-calc.png new file mode 100755 index 000000000..23df56dc2 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/ooo-calc.png differ diff --git a/Z/src/nglwidgets/icons/16x16/ooo-impress.png b/Z/src/nglwidgets/icons/16x16/ooo-impress.png new file mode 100755 index 000000000..d1c23c2d5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/ooo-impress.png differ diff --git a/Z/src/nglwidgets/icons/16x16/ooo-writer.png b/Z/src/nglwidgets/icons/16x16/ooo-writer.png new file mode 100755 index 000000000..f7922ad43 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/ooo-writer.png differ diff --git a/Z/src/nglwidgets/icons/16x16/player_status.png b/Z/src/nglwidgets/icons/16x16/player_status.png new file mode 100755 index 000000000..47cda6a8b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/player_status.png differ diff --git a/Z/src/nglwidgets/icons/16x16/preferences-desktop-font.png b/Z/src/nglwidgets/icons/16x16/preferences-desktop-font.png new file mode 100755 index 000000000..fa22278d7 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/preferences-desktop-font.png differ diff --git a/Z/src/nglwidgets/icons/16x16/preferences-web-browser-cache.png b/Z/src/nglwidgets/icons/16x16/preferences-web-browser-cache.png new file mode 100755 index 000000000..82a149e83 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/preferences-web-browser-cache.png differ diff --git a/Z/src/nglwidgets/icons/16x16/printer.png b/Z/src/nglwidgets/icons/16x16/printer.png new file mode 100755 index 000000000..305072b52 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/printer.png differ diff --git a/Z/src/nglwidgets/icons/16x16/process-stop.png b/Z/src/nglwidgets/icons/16x16/process-stop.png new file mode 100755 index 000000000..5b4c488bd Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/process-stop.png differ diff --git a/Z/src/nglwidgets/icons/16x16/rde.ico b/Z/src/nglwidgets/icons/16x16/rde.ico new file mode 100755 index 000000000..1da3072f5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/rde.ico differ diff --git a/Z/src/nglwidgets/icons/16x16/rde_16x16.png b/Z/src/nglwidgets/icons/16x16/rde_16x16.png new file mode 100755 index 000000000..d801e3adc Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/rde_16x16.png differ diff --git a/Z/src/nglwidgets/icons/16x16/system-help.png b/Z/src/nglwidgets/icons/16x16/system-help.png new file mode 100755 index 000000000..75ebaf7f5 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/system-help.png differ diff --git a/Z/src/nglwidgets/icons/16x16/text-plain.png b/Z/src/nglwidgets/icons/16x16/text-plain.png new file mode 100755 index 000000000..513869226 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/text-plain.png differ diff --git a/Z/src/nglwidgets/icons/16x16/transform-move.png b/Z/src/nglwidgets/icons/16x16/transform-move.png new file mode 100755 index 000000000..d6c44ce8e Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/transform-move.png differ diff --git a/Z/src/nglwidgets/icons/16x16/transform-rotate.png b/Z/src/nglwidgets/icons/16x16/transform-rotate.png new file mode 100755 index 000000000..11b457914 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/transform-rotate.png differ diff --git a/Z/src/nglwidgets/icons/16x16/transform-scale.png b/Z/src/nglwidgets/icons/16x16/transform-scale.png new file mode 100755 index 000000000..6dea0c2a6 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/transform-scale.png differ diff --git a/Z/src/nglwidgets/icons/16x16/traurig.gif b/Z/src/nglwidgets/icons/16x16/traurig.gif new file mode 100755 index 000000000..8a3f4b2db Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/traurig.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/video-x-generic.png b/Z/src/nglwidgets/icons/16x16/video-x-generic.png new file mode 100755 index 000000000..760d9689d Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/video-x-generic.png differ diff --git a/Z/src/nglwidgets/icons/16x16/view-fullscreen.png b/Z/src/nglwidgets/icons/16x16/view-fullscreen.png new file mode 100755 index 000000000..77ccfcc0b Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/view-fullscreen.png differ diff --git a/Z/src/nglwidgets/icons/16x16/view-statistics.png b/Z/src/nglwidgets/icons/16x16/view-statistics.png new file mode 100755 index 000000000..5a05fa48d Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/view-statistics.png differ diff --git a/Z/src/nglwidgets/icons/16x16/weinend.gif b/Z/src/nglwidgets/icons/16x16/weinend.gif new file mode 100755 index 000000000..a3ba665f7 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/weinend.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/x-office-address-book.png b/Z/src/nglwidgets/icons/16x16/x-office-address-book.png new file mode 100755 index 000000000..8fa59df19 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/x-office-address-book.png differ diff --git a/Z/src/nglwidgets/icons/16x16/yellow-off-16.png b/Z/src/nglwidgets/icons/16x16/yellow-off-16.png new file mode 100755 index 000000000..144a99946 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/yellow-off-16.png differ diff --git a/Z/src/nglwidgets/icons/16x16/yellow-on-16.png b/Z/src/nglwidgets/icons/16x16/yellow-on-16.png new file mode 100755 index 000000000..27da3ecbb Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/yellow-on-16.png differ diff --git a/Z/src/nglwidgets/icons/16x16/zoom-in.png b/Z/src/nglwidgets/icons/16x16/zoom-in.png new file mode 100755 index 000000000..6b7a6826a Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/zoom-in.png differ diff --git a/Z/src/nglwidgets/icons/16x16/zoom-out.png b/Z/src/nglwidgets/icons/16x16/zoom-out.png new file mode 100755 index 000000000..0ee8c6f5d Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/zoom-out.png differ diff --git a/Z/src/nglwidgets/icons/16x16/zunge.gif b/Z/src/nglwidgets/icons/16x16/zunge.gif new file mode 100755 index 000000000..d81ba9641 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/zunge.gif differ diff --git a/Z/src/nglwidgets/icons/16x16/zwinker.gif b/Z/src/nglwidgets/icons/16x16/zwinker.gif new file mode 100755 index 000000000..d14828804 Binary files /dev/null and b/Z/src/nglwidgets/icons/16x16/zwinker.gif differ diff --git a/Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png b/Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png new file mode 100755 index 000000000..b1f89fbb3 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/dialogbuttonbox.png differ diff --git a/Z/src/nglwidgets/icons/22x22/edit-redo.png b/Z/src/nglwidgets/icons/22x22/edit-redo.png new file mode 100755 index 000000000..45f045028 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/edit-redo.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-center.png b/Z/src/nglwidgets/icons/22x22/format-justify-center.png new file mode 100755 index 000000000..1907b44d8 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-justify-center.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-fill.png b/Z/src/nglwidgets/icons/22x22/format-justify-fill.png new file mode 100755 index 000000000..eddb7bfa7 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-justify-fill.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-left.png b/Z/src/nglwidgets/icons/22x22/format-justify-left.png new file mode 100755 index 000000000..37a9c5e0e Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-justify-left.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-justify-right.png b/Z/src/nglwidgets/icons/22x22/format-justify-right.png new file mode 100755 index 000000000..404315b71 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-justify-right.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-stroke-color.png b/Z/src/nglwidgets/icons/22x22/format-stroke-color.png new file mode 100755 index 000000000..98628e860 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-stroke-color.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-text-bold.png b/Z/src/nglwidgets/icons/22x22/format-text-bold.png new file mode 100755 index 000000000..a5535e33f Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-text-bold.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-text-italic.png b/Z/src/nglwidgets/icons/22x22/format-text-italic.png new file mode 100755 index 000000000..a50211f4f Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-text-italic.png differ diff --git a/Z/src/nglwidgets/icons/22x22/format-text-underline.png b/Z/src/nglwidgets/icons/22x22/format-text-underline.png new file mode 100755 index 000000000..e51139505 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/format-text-underline.png differ diff --git a/Z/src/nglwidgets/icons/22x22/kdialog.png b/Z/src/nglwidgets/icons/22x22/kdialog.png new file mode 100755 index 000000000..d25dcb9a7 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/kdialog.png differ diff --git a/Z/src/nglwidgets/icons/22x22/klineedit.png b/Z/src/nglwidgets/icons/22x22/klineedit.png new file mode 100755 index 000000000..f9462891b Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/klineedit.png differ diff --git a/Z/src/nglwidgets/icons/22x22/layer.png b/Z/src/nglwidgets/icons/22x22/layer.png new file mode 100755 index 000000000..afa9a344c Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/layer.png differ diff --git a/Z/src/nglwidgets/icons/22x22/lkm_einsatz.png b/Z/src/nglwidgets/icons/22x22/lkm_einsatz.png new file mode 100755 index 000000000..40ec4c08d Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/lkm_einsatz.png differ diff --git a/Z/src/nglwidgets/icons/22x22/pushbutton.png b/Z/src/nglwidgets/icons/22x22/pushbutton.png new file mode 100755 index 000000000..61f779ce2 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/pushbutton.png differ diff --git a/Z/src/nglwidgets/icons/22x22/scricon.png b/Z/src/nglwidgets/icons/22x22/scricon.png new file mode 100755 index 000000000..9a2b5c7b8 Binary files /dev/null and b/Z/src/nglwidgets/icons/22x22/scricon.png differ diff --git a/Z/src/nglwidgets/icons/32x32/database.png b/Z/src/nglwidgets/icons/32x32/database.png new file mode 100755 index 000000000..241f97971 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/database.png differ diff --git a/Z/src/nglwidgets/icons/32x32/hand_grenade_locations.png b/Z/src/nglwidgets/icons/32x32/hand_grenade_locations.png new file mode 100755 index 000000000..4fd9d8411 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/hand_grenade_locations.png differ diff --git a/Z/src/nglwidgets/icons/32x32/hideshow.png b/Z/src/nglwidgets/icons/32x32/hideshow.png new file mode 100755 index 000000000..7038b660c Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/hideshow.png differ diff --git a/Z/src/nglwidgets/icons/32x32/marker-end.png b/Z/src/nglwidgets/icons/32x32/marker-end.png new file mode 100755 index 000000000..e8126dd82 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/marker-end.png differ diff --git a/Z/src/nglwidgets/icons/32x32/marker-start.png b/Z/src/nglwidgets/icons/32x32/marker-start.png new file mode 100755 index 000000000..37f698d66 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/marker-start.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-eject.png b/Z/src/nglwidgets/icons/32x32/media-eject.png new file mode 100755 index 000000000..96f7ea9bb Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-eject.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-play-backward.png b/Z/src/nglwidgets/icons/32x32/media-play-backward.png new file mode 100755 index 000000000..83c9d8f53 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-play-backward.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-play-faster.png b/Z/src/nglwidgets/icons/32x32/media-play-faster.png new file mode 100755 index 000000000..41fad66da Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-play-faster.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-play-faster.svg b/Z/src/nglwidgets/icons/32x32/media-play-faster.svg new file mode 100755 index 000000000..e69de29bb diff --git a/Z/src/nglwidgets/icons/32x32/media-play-normal.png b/Z/src/nglwidgets/icons/32x32/media-play-normal.png new file mode 100755 index 000000000..5a69da694 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-play-normal.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-play-normal.svg b/Z/src/nglwidgets/icons/32x32/media-play-normal.svg new file mode 100755 index 000000000..e69de29bb diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.png b/Z/src/nglwidgets/icons/32x32/media-play-slower.png new file mode 100755 index 000000000..3a2512672 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-play-slower.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.svg b/Z/src/nglwidgets/icons/32x32/media-play-slower.svg new file mode 100755 index 000000000..e69de29bb diff --git a/Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png b/Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png new file mode 100755 index 000000000..f73310a0e Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-play-slower.svg.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-pause.png b/Z/src/nglwidgets/icons/32x32/media-playback-pause.png new file mode 100755 index 000000000..5c7d128ee Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-playback-pause.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-start-single.png b/Z/src/nglwidgets/icons/32x32/media-playback-start-single.png new file mode 100755 index 000000000..b36832383 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-playback-start-single.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-start.png b/Z/src/nglwidgets/icons/32x32/media-playback-start.png new file mode 100755 index 000000000..71906857c Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-playback-start.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-playback-stop.png b/Z/src/nglwidgets/icons/32x32/media-playback-stop.png new file mode 100755 index 000000000..650874f67 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-playback-stop.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-record.png b/Z/src/nglwidgets/icons/32x32/media-record.png new file mode 100755 index 000000000..f926a8f27 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-record.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-seek-backward.png b/Z/src/nglwidgets/icons/32x32/media-seek-backward.png new file mode 100755 index 000000000..644d3e2d0 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-seek-backward.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-seek-forward.png b/Z/src/nglwidgets/icons/32x32/media-seek-forward.png new file mode 100755 index 000000000..51881ea8d Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-seek-forward.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-skip-backward.png b/Z/src/nglwidgets/icons/32x32/media-skip-backward.png new file mode 100755 index 000000000..bcf2376d6 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-skip-backward.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-skip-forward.png b/Z/src/nglwidgets/icons/32x32/media-skip-forward.png new file mode 100755 index 000000000..843660679 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-skip-forward.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png b/Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png new file mode 100755 index 000000000..db19b548d Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-vcr-nopause.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-normal.png b/Z/src/nglwidgets/icons/32x32/media-vcr-normal.png new file mode 100755 index 000000000..4609d13cb Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-vcr-normal.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-repeat.png b/Z/src/nglwidgets/icons/32x32/media-vcr-repeat.png new file mode 100755 index 000000000..25c318fe0 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-vcr-repeat.png differ diff --git a/Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png b/Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png new file mode 100755 index 000000000..8c9be9728 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/media-vcr-withpause.png differ diff --git a/Z/src/nglwidgets/icons/32x32/service_message.png b/Z/src/nglwidgets/icons/32x32/service_message.png new file mode 100755 index 000000000..3ab475b0f Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/service_message.png differ diff --git a/Z/src/nglwidgets/icons/32x32/showhide.png b/Z/src/nglwidgets/icons/32x32/showhide.png new file mode 100755 index 000000000..9a92e2c1b Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/showhide.png differ diff --git a/Z/src/nglwidgets/icons/32x32/wireless.png b/Z/src/nglwidgets/icons/32x32/wireless.png new file mode 100755 index 000000000..691910879 Binary files /dev/null and b/Z/src/nglwidgets/icons/32x32/wireless.png differ diff --git a/Z/src/nglwidgets/icons/LICENSE b/Z/src/nglwidgets/icons/LICENSE new file mode 100755 index 000000000..82f24a630 --- /dev/null +++ b/Z/src/nglwidgets/icons/LICENSE @@ -0,0 +1,24 @@ +Icon theme + +Oxygen icon theme is dual licensed. You may copy it under the Creative Common +Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +Creative Common Attribution-ShareAlike 3.0 License (short form): + +You are free: + + * to Share — to copy, distribute and transmit the work + * to Remix — to adapt the work + +Under the following conditions: + + * Attribution. You must attribute the work in the manner specified by the + author or licensor (but not in any way that suggests that they endorse + you or your use of the work). + + * Share Alike. If you alter, transform, or build upon this work, you may + distribute the resulting work only under the same, similar or a + compatible license. + +See also http://creativecommons.org/licenses/by-sa/3.0/ and +http://creativecommons.org/licenses/by-sa/3.0/legalcode diff --git a/Z/src/nglwidgets/icons/png/add.png b/Z/src/nglwidgets/icons/png/add.png new file mode 100755 index 000000000..983618794 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add.png differ diff --git a/Z/src/nglwidgets/icons/png/add_disabled.png b/Z/src/nglwidgets/icons/png/add_disabled.png new file mode 100755 index 000000000..f83b1c272 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/add_tactical_sign_act.png b/Z/src/nglwidgets/icons/png/add_tactical_sign_act.png new file mode 100755 index 000000000..ac97c372a Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add_tactical_sign_act.png differ diff --git a/Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png b/Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png new file mode 100755 index 000000000..4266b9898 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add_tactical_sign_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/add_text_act.png b/Z/src/nglwidgets/icons/png/add_text_act.png new file mode 100755 index 000000000..4eecaaac2 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add_text_act.png differ diff --git a/Z/src/nglwidgets/icons/png/add_text_act_disabled.png b/Z/src/nglwidgets/icons/png/add_text_act_disabled.png new file mode 100755 index 000000000..f0f250741 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/add_text_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/address_book.png b/Z/src/nglwidgets/icons/png/address_book.png new file mode 100755 index 000000000..54869ace7 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/address_book.png differ diff --git a/Z/src/nglwidgets/icons/png/big_letters_act.png b/Z/src/nglwidgets/icons/png/big_letters_act.png new file mode 100755 index 000000000..1228a8bd6 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/big_letters_act.png differ diff --git a/Z/src/nglwidgets/icons/png/big_letters_act_disabled.png b/Z/src/nglwidgets/icons/png/big_letters_act_disabled.png new file mode 100755 index 000000000..7d27f7be1 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/big_letters_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_down.png b/Z/src/nglwidgets/icons/png/camera_arrow_down.png new file mode 100755 index 000000000..498738ef1 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/camera_arrow_down.png differ diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_left.png b/Z/src/nglwidgets/icons/png/camera_arrow_left.png new file mode 100755 index 000000000..ccde9a388 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/camera_arrow_left.png differ diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_right.png b/Z/src/nglwidgets/icons/png/camera_arrow_right.png new file mode 100755 index 000000000..366c39be5 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/camera_arrow_right.png differ diff --git a/Z/src/nglwidgets/icons/png/camera_arrow_up.png b/Z/src/nglwidgets/icons/png/camera_arrow_up.png new file mode 100755 index 000000000..7d79b2afd Binary files /dev/null and b/Z/src/nglwidgets/icons/png/camera_arrow_up.png differ diff --git a/Z/src/nglwidgets/icons/png/center_object_in_map_act.png b/Z/src/nglwidgets/icons/png/center_object_in_map_act.png new file mode 100755 index 000000000..e2adb1181 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/center_object_in_map_act.png differ diff --git a/Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png b/Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png new file mode 100755 index 000000000..d8426a852 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/center_object_in_map_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/clear_plan_act.png b/Z/src/nglwidgets/icons/png/clear_plan_act.png new file mode 100755 index 000000000..1b381dde0 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/clear_plan_act.png differ diff --git a/Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png b/Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png new file mode 100755 index 000000000..6d7b027a0 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/clear_plan_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/copy_exercise.png b/Z/src/nglwidgets/icons/png/copy_exercise.png new file mode 100755 index 000000000..f74eda659 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/copy_exercise.png differ diff --git a/Z/src/nglwidgets/icons/png/copy_exercise_disabled.png b/Z/src/nglwidgets/icons/png/copy_exercise_disabled.png new file mode 100755 index 000000000..d0b567b51 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/copy_exercise_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/delete.png b/Z/src/nglwidgets/icons/png/delete.png new file mode 100755 index 000000000..7fdce4dc9 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete.png differ diff --git a/Z/src/nglwidgets/icons/png/delete_disabled.png b/Z/src/nglwidgets/icons/png/delete_disabled.png new file mode 100755 index 000000000..c3c9f91be Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/delete_exercise.png b/Z/src/nglwidgets/icons/png/delete_exercise.png new file mode 100755 index 000000000..27f32d9ac Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete_exercise.png differ diff --git a/Z/src/nglwidgets/icons/png/delete_exercise_disabled.png b/Z/src/nglwidgets/icons/png/delete_exercise_disabled.png new file mode 100755 index 000000000..52c58e824 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete_exercise_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/delete_graphic_eass.png b/Z/src/nglwidgets/icons/png/delete_graphic_eass.png new file mode 100755 index 000000000..43c32de1d Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete_graphic_eass.png differ diff --git a/Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png b/Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png new file mode 100755 index 000000000..8f8597b90 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/delete_graphic_eass_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/deleteall.png b/Z/src/nglwidgets/icons/png/deleteall.png new file mode 100755 index 000000000..99cbb675a Binary files /dev/null and b/Z/src/nglwidgets/icons/png/deleteall.png differ diff --git a/Z/src/nglwidgets/icons/png/download.png b/Z/src/nglwidgets/icons/png/download.png new file mode 100755 index 000000000..89eb2fdfb Binary files /dev/null and b/Z/src/nglwidgets/icons/png/download.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_ellipse_act.png b/Z/src/nglwidgets/icons/png/draw_ellipse_act.png new file mode 100755 index 000000000..31a598f1c Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_ellipse_act.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_ellipse_act_disabled.png b/Z/src/nglwidgets/icons/png/draw_ellipse_act_disabled.png new file mode 100755 index 000000000..55ebc2d96 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_ellipse_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_line.png b/Z/src/nglwidgets/icons/png/draw_line.png new file mode 100755 index 000000000..59fee973f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_line.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_line_disabled.png b/Z/src/nglwidgets/icons/png/draw_line_disabled.png new file mode 100755 index 000000000..a12b81527 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_line_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_polygon_act.png b/Z/src/nglwidgets/icons/png/draw_polygon_act.png new file mode 100755 index 000000000..1a8823864 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_polygon_act.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png b/Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png new file mode 100755 index 000000000..351e1013b Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_polygon_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_rectangle_act.png b/Z/src/nglwidgets/icons/png/draw_rectangle_act.png new file mode 100755 index 000000000..724020d80 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_rectangle_act.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png b/Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png new file mode 100755 index 000000000..7ed72056e Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_rectangle_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_spline.png b/Z/src/nglwidgets/icons/png/draw_spline.png new file mode 100755 index 000000000..d62994429 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_spline.png differ diff --git a/Z/src/nglwidgets/icons/png/draw_spline_disabled.png b/Z/src/nglwidgets/icons/png/draw_spline_disabled.png new file mode 100755 index 000000000..8064ab171 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/draw_spline_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/eass_line.png b/Z/src/nglwidgets/icons/png/eass_line.png new file mode 100755 index 000000000..199e8856f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/eass_line.png differ diff --git a/Z/src/nglwidgets/icons/png/eass_line_disabled.png b/Z/src/nglwidgets/icons/png/eass_line_disabled.png new file mode 100755 index 000000000..e99f2554e Binary files /dev/null and b/Z/src/nglwidgets/icons/png/eass_line_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/eass_polygon.png b/Z/src/nglwidgets/icons/png/eass_polygon.png new file mode 100755 index 000000000..b88323d76 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/eass_polygon.png differ diff --git a/Z/src/nglwidgets/icons/png/eass_polygon_disabled.png b/Z/src/nglwidgets/icons/png/eass_polygon_disabled.png new file mode 100755 index 000000000..ee1869e6e Binary files /dev/null and b/Z/src/nglwidgets/icons/png/eass_polygon_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/edit_element_act.png b/Z/src/nglwidgets/icons/png/edit_element_act.png new file mode 100755 index 000000000..dc377c108 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/edit_element_act.png differ diff --git a/Z/src/nglwidgets/icons/png/edit_element_act_disabled.png b/Z/src/nglwidgets/icons/png/edit_element_act_disabled.png new file mode 100755 index 000000000..387d9e679 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/edit_element_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/edith_graphic_eass.png b/Z/src/nglwidgets/icons/png/edith_graphic_eass.png new file mode 100755 index 000000000..5f6576ef8 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/edith_graphic_eass.png differ diff --git a/Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png b/Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png new file mode 100755 index 000000000..123f669e6 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/edith_graphic_eass_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/fast_playback.png b/Z/src/nglwidgets/icons/png/fast_playback.png new file mode 100755 index 000000000..e6a7576b5 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fast_playback.png differ diff --git a/Z/src/nglwidgets/icons/png/fast_playback_backward.png b/Z/src/nglwidgets/icons/png/fast_playback_backward.png new file mode 100755 index 000000000..7776327a4 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fast_playback_backward.png differ diff --git a/Z/src/nglwidgets/icons/png/fast_playback_backward_disabled.png b/Z/src/nglwidgets/icons/png/fast_playback_backward_disabled.png new file mode 100755 index 000000000..5f6d6ed2d Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fast_playback_backward_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/fast_playback_disabled.png b/Z/src/nglwidgets/icons/png/fast_playback_disabled.png new file mode 100755 index 000000000..697a1539e Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fast_playback_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/fill_colour_act.png b/Z/src/nglwidgets/icons/png/fill_colour_act.png new file mode 100755 index 000000000..9282c68f6 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fill_colour_act.png differ diff --git a/Z/src/nglwidgets/icons/png/fill_colour_act_disabled.png b/Z/src/nglwidgets/icons/png/fill_colour_act_disabled.png new file mode 100755 index 000000000..79d0a1981 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/fill_colour_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/folder_open.png b/Z/src/nglwidgets/icons/png/folder_open.png new file mode 100755 index 000000000..81e97908f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/folder_open.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_audio_control_act.png b/Z/src/nglwidgets/icons/png/kosy_audio_control_act.png new file mode 100755 index 000000000..b94bcb5a4 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_audio_control_act.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png b/Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png new file mode 100755 index 000000000..7631455e9 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_audio_control_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_radio_error_act.png b/Z/src/nglwidgets/icons/png/kosy_radio_error_act.png new file mode 100755 index 000000000..02a3e7c2d Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_radio_error_act.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_radio_error_act_disabled.png b/Z/src/nglwidgets/icons/png/kosy_radio_error_act_disabled.png new file mode 100755 index 000000000..bea1d7a10 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_radio_error_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_remote_control_act.png b/Z/src/nglwidgets/icons/png/kosy_remote_control_act.png new file mode 100755 index 000000000..0a6708082 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_remote_control_act.png differ diff --git a/Z/src/nglwidgets/icons/png/kosy_remote_control_act_disabled.png b/Z/src/nglwidgets/icons/png/kosy_remote_control_act_disabled.png new file mode 100755 index 000000000..ec62bf367 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/kosy_remote_control_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/line_color.png b/Z/src/nglwidgets/icons/png/line_color.png new file mode 100755 index 000000000..d4edae3f6 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/line_color.png differ diff --git a/Z/src/nglwidgets/icons/png/marker_left.png b/Z/src/nglwidgets/icons/png/marker_left.png new file mode 100755 index 000000000..d9282de87 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/marker_left.png differ diff --git a/Z/src/nglwidgets/icons/png/marker_left_disabled.png b/Z/src/nglwidgets/icons/png/marker_left_disabled.png new file mode 100755 index 000000000..7dbc6c2ec Binary files /dev/null and b/Z/src/nglwidgets/icons/png/marker_left_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/marker_right.png b/Z/src/nglwidgets/icons/png/marker_right.png new file mode 100755 index 000000000..d82f6a3f6 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/marker_right.png differ diff --git a/Z/src/nglwidgets/icons/png/marker_right_disabled.png b/Z/src/nglwidgets/icons/png/marker_right_disabled.png new file mode 100755 index 000000000..ac9964f3b Binary files /dev/null and b/Z/src/nglwidgets/icons/png/marker_right_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/messages_new.png b/Z/src/nglwidgets/icons/png/messages_new.png new file mode 100755 index 000000000..916f6d05f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/messages_new.png differ diff --git a/Z/src/nglwidgets/icons/png/missionmarch.png b/Z/src/nglwidgets/icons/png/missionmarch.png new file mode 100755 index 000000000..ea52a59cc Binary files /dev/null and b/Z/src/nglwidgets/icons/png/missionmarch.png differ diff --git a/Z/src/nglwidgets/icons/png/missionmarch_disabled.png b/Z/src/nglwidgets/icons/png/missionmarch_disabled.png new file mode 100755 index 000000000..0edc9d7cf Binary files /dev/null and b/Z/src/nglwidgets/icons/png/missionmarch_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/normal_letters_act.png b/Z/src/nglwidgets/icons/png/normal_letters_act.png new file mode 100755 index 000000000..5f1a1bfa0 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/normal_letters_act.png differ diff --git a/Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png b/Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png new file mode 100755 index 000000000..cd98e3fe4 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/normal_letters_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/ok.png b/Z/src/nglwidgets/icons/png/ok.png new file mode 100755 index 000000000..6c75ec331 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/ok.png differ diff --git a/Z/src/nglwidgets/icons/png/ok_disabled.png b/Z/src/nglwidgets/icons/png/ok_disabled.png new file mode 100755 index 000000000..86b8c08bf Binary files /dev/null and b/Z/src/nglwidgets/icons/png/ok_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/paste_exercise.png b/Z/src/nglwidgets/icons/png/paste_exercise.png new file mode 100755 index 000000000..5fd6f9d93 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/paste_exercise.png differ diff --git a/Z/src/nglwidgets/icons/png/paste_exercise_disabled.png b/Z/src/nglwidgets/icons/png/paste_exercise_disabled.png new file mode 100755 index 000000000..6f44b785e Binary files /dev/null and b/Z/src/nglwidgets/icons/png/paste_exercise_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/pause_playback.png b/Z/src/nglwidgets/icons/png/pause_playback.png new file mode 100755 index 000000000..3d928be55 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/pause_playback.png differ diff --git a/Z/src/nglwidgets/icons/png/pause_playback_disabled.png b/Z/src/nglwidgets/icons/png/pause_playback_disabled.png new file mode 100755 index 000000000..5478a9512 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/pause_playback_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/polygonmap.png b/Z/src/nglwidgets/icons/png/polygonmap.png new file mode 100755 index 000000000..04a8b9ed9 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/polygonmap.png differ diff --git a/Z/src/nglwidgets/icons/png/polygonmap_disabled.png b/Z/src/nglwidgets/icons/png/polygonmap_disabled.png new file mode 100755 index 000000000..54ad2c490 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/polygonmap_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/position_map.png b/Z/src/nglwidgets/icons/png/position_map.png new file mode 100755 index 000000000..fa3388d44 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/position_map.png differ diff --git a/Z/src/nglwidgets/icons/png/position_map_disabled.png b/Z/src/nglwidgets/icons/png/position_map_disabled.png new file mode 100755 index 000000000..a4cdb4e50 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/position_map_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/preview.png b/Z/src/nglwidgets/icons/png/preview.png new file mode 100755 index 000000000..eba432e12 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/preview.png differ diff --git a/Z/src/nglwidgets/icons/png/printer.png b/Z/src/nglwidgets/icons/png/printer.png new file mode 100755 index 000000000..7db499123 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/printer.png differ diff --git a/Z/src/nglwidgets/icons/png/redo.png b/Z/src/nglwidgets/icons/png/redo.png new file mode 100755 index 000000000..ec5a9afad Binary files /dev/null and b/Z/src/nglwidgets/icons/png/redo.png differ diff --git a/Z/src/nglwidgets/icons/png/redo_disabled.png b/Z/src/nglwidgets/icons/png/redo_disabled.png new file mode 100755 index 000000000..dda926060 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/redo_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/remove.png b/Z/src/nglwidgets/icons/png/remove.png new file mode 100755 index 000000000..c3b1d9d59 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/remove.png differ diff --git a/Z/src/nglwidgets/icons/png/remove_disabled.png b/Z/src/nglwidgets/icons/png/remove_disabled.png new file mode 100755 index 000000000..3d14eca47 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/remove_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/rename_exercise.png b/Z/src/nglwidgets/icons/png/rename_exercise.png new file mode 100755 index 000000000..d8cf25306 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/rename_exercise.png differ diff --git a/Z/src/nglwidgets/icons/png/rename_exercise_disabled.png b/Z/src/nglwidgets/icons/png/rename_exercise_disabled.png new file mode 100755 index 000000000..c55a95365 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/rename_exercise_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/save.png b/Z/src/nglwidgets/icons/png/save.png new file mode 100755 index 000000000..7c034071c Binary files /dev/null and b/Z/src/nglwidgets/icons/png/save.png differ diff --git a/Z/src/nglwidgets/icons/png/save_as.png b/Z/src/nglwidgets/icons/png/save_as.png new file mode 100755 index 000000000..fe0a91eec Binary files /dev/null and b/Z/src/nglwidgets/icons/png/save_as.png differ diff --git a/Z/src/nglwidgets/icons/png/settings.png b/Z/src/nglwidgets/icons/png/settings.png new file mode 100755 index 000000000..59b22153c Binary files /dev/null and b/Z/src/nglwidgets/icons/png/settings.png differ diff --git a/Z/src/nglwidgets/icons/png/settings_disabled.png b/Z/src/nglwidgets/icons/png/settings_disabled.png new file mode 100755 index 000000000..47777656a Binary files /dev/null and b/Z/src/nglwidgets/icons/png/settings_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/start_playback.png b/Z/src/nglwidgets/icons/png/start_playback.png new file mode 100755 index 000000000..a9205d1fb Binary files /dev/null and b/Z/src/nglwidgets/icons/png/start_playback.png differ diff --git a/Z/src/nglwidgets/icons/png/start_playback_disabled.png b/Z/src/nglwidgets/icons/png/start_playback_disabled.png new file mode 100755 index 000000000..d02832c6f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/start_playback_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/stop.png b/Z/src/nglwidgets/icons/png/stop.png new file mode 100755 index 000000000..285dff1c1 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/stop.png differ diff --git a/Z/src/nglwidgets/icons/png/stop_disabled.png b/Z/src/nglwidgets/icons/png/stop_disabled.png new file mode 100755 index 000000000..4146a097c Binary files /dev/null and b/Z/src/nglwidgets/icons/png/stop_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/stop_playback.png b/Z/src/nglwidgets/icons/png/stop_playback.png new file mode 100755 index 000000000..ce57a95a1 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/stop_playback.png differ diff --git a/Z/src/nglwidgets/icons/png/stop_playback_disabled.png b/Z/src/nglwidgets/icons/png/stop_playback_disabled.png new file mode 100755 index 000000000..e01b1bde7 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/stop_playback_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/thick_line_act.png b/Z/src/nglwidgets/icons/png/thick_line_act.png new file mode 100755 index 000000000..1ba4d4fef Binary files /dev/null and b/Z/src/nglwidgets/icons/png/thick_line_act.png differ diff --git a/Z/src/nglwidgets/icons/png/thick_line_act_disabled.png b/Z/src/nglwidgets/icons/png/thick_line_act_disabled.png new file mode 100755 index 000000000..5387fba3f Binary files /dev/null and b/Z/src/nglwidgets/icons/png/thick_line_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/turn_left.png b/Z/src/nglwidgets/icons/png/turn_left.png new file mode 100755 index 000000000..d4a0faa13 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/turn_left.png differ diff --git a/Z/src/nglwidgets/icons/png/turn_left_disabled.png b/Z/src/nglwidgets/icons/png/turn_left_disabled.png new file mode 100755 index 000000000..631b1cb87 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/turn_left_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/undo_act.png b/Z/src/nglwidgets/icons/png/undo_act.png new file mode 100755 index 000000000..448946785 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/undo_act.png differ diff --git a/Z/src/nglwidgets/icons/png/undo_act_disabled.png b/Z/src/nglwidgets/icons/png/undo_act_disabled.png new file mode 100755 index 000000000..1fb7be830 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/undo_act_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/zoom_in.png b/Z/src/nglwidgets/icons/png/zoom_in.png new file mode 100755 index 000000000..ef3885743 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/zoom_in.png differ diff --git a/Z/src/nglwidgets/icons/png/zoom_in_disabled.png b/Z/src/nglwidgets/icons/png/zoom_in_disabled.png new file mode 100755 index 000000000..5b4f56412 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/zoom_in_disabled.png differ diff --git a/Z/src/nglwidgets/icons/png/zoom_out.png b/Z/src/nglwidgets/icons/png/zoom_out.png new file mode 100755 index 000000000..55ddc3690 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/zoom_out.png differ diff --git a/Z/src/nglwidgets/icons/png/zoom_out_disabled.png b/Z/src/nglwidgets/icons/png/zoom_out_disabled.png new file mode 100755 index 000000000..9897b8294 Binary files /dev/null and b/Z/src/nglwidgets/icons/png/zoom_out_disabled.png differ diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer.svg b/Z/src/nglwidgets/icons/svg/3d_viewer.svg new file mode 100755 index 000000000..4301cc243 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg new file mode 100755 index 000000000..3a88e5077 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_config.svg @@ -0,0 +1,497 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg new file mode 100755 index 000000000..209609363 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_config_disabled.svg @@ -0,0 +1,169 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg b/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg new file mode 100755 index 000000000..6dbd0c86f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/3d_viewer_disabled.svg @@ -0,0 +1,78 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/about.svg b/Z/src/nglwidgets/icons/svg/about.svg new file mode 100755 index 000000000..e3270cd06 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/about.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/about_disabled.svg b/Z/src/nglwidgets/icons/svg/about_disabled.svg new file mode 100755 index 000000000..ef49ecf7a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/about_disabled.svg @@ -0,0 +1,100 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg b/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg new file mode 100755 index 000000000..c19bc1256 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/ac_adapter_plugged_in.svg @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/access_rights.svg b/Z/src/nglwidgets/icons/svg/access_rights.svg new file mode 100755 index 000000000..9865249a9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/access_rights.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg b/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg new file mode 100755 index 000000000..d11ee9747 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/access_rights_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/aircraft_sim.svg b/Z/src/nglwidgets/icons/svg/aircraft_sim.svg new file mode 100755 index 000000000..c126deeb7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/aircraft_sim.svg @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement.svg b/Z/src/nglwidgets/icons/svg/announcement.svg new file mode 100755 index 000000000..f9ba271ec --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_disabled.svg b/Z/src/nglwidgets/icons/svg/announcement_disabled.svg new file mode 100755 index 000000000..796fe8c1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_disabled.svg @@ -0,0 +1,101 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_menu.svg b/Z/src/nglwidgets/icons/svg/announcement_menu.svg new file mode 100755 index 000000000..e71089143 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_menu.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg new file mode 100755 index 000000000..3a65c7740 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/announcement_menu_disabled.svg @@ -0,0 +1,91 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/application-exit.svg b/Z/src/nglwidgets/icons/svg/application-exit.svg new file mode 100755 index 000000000..fa5e04b9f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/application-exit.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/arrow_back.svg b/Z/src/nglwidgets/icons/svg/arrow_back.svg new file mode 100755 index 000000000..c94a6877c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/arrow_back.svg @@ -0,0 +1,392 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg b/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg new file mode 100755 index 000000000..8f20d3828 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/arrow_back_disabled.svg @@ -0,0 +1,62 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/artillery_firings.svg b/Z/src/nglwidgets/icons/svg/artillery_firings.svg new file mode 100755 index 000000000..832c59f6c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/artillery_firings.svg @@ -0,0 +1,459 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg new file mode 100755 index 000000000..7a0eb15e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/artillery_firings_disabled.svg @@ -0,0 +1,134 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-high.svg b/Z/src/nglwidgets/icons/svg/audio-volume-high.svg new file mode 100755 index 000000000..db3712259 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-high.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-low.svg b/Z/src/nglwidgets/icons/svg/audio-volume-low.svg new file mode 100755 index 000000000..a5ce37fb9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-low.svg @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg b/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg new file mode 100755 index 000000000..814e30e3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-medium.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg b/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg new file mode 100755 index 000000000..8e8f01930 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/audio-volume-muted.svg @@ -0,0 +1,384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/battery_mode.svg b/Z/src/nglwidgets/icons/svg/battery_mode.svg new file mode 100755 index 000000000..02662cef2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/battery_mode.svg @@ -0,0 +1,368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/camera_control.svg b/Z/src/nglwidgets/icons/svg/camera_control.svg new file mode 100755 index 000000000..06c19c5f8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/camera_control.svg @@ -0,0 +1,428 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg b/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg new file mode 100755 index 000000000..44d93363f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/camera_control_disabled.svg @@ -0,0 +1,102 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/change_password.svg b/Z/src/nglwidgets/icons/svg/change_password.svg new file mode 100755 index 000000000..c78ec507b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/change_password.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/change_password_disabled.svg b/Z/src/nglwidgets/icons/svg/change_password_disabled.svg new file mode 100755 index 000000000..eea7d74a5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/change_password_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chat.svg b/Z/src/nglwidgets/icons/svg/chat.svg new file mode 100755 index 000000000..6dd6c8c3f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chat.svg @@ -0,0 +1,408 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chat_disabled.svg b/Z/src/nglwidgets/icons/svg/chat_disabled.svg new file mode 100755 index 000000000..2397def61 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chat_disabled.svg @@ -0,0 +1,82 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chemical_agents.svg b/Z/src/nglwidgets/icons/svg/chemical_agents.svg new file mode 100755 index 000000000..f13b6de07 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chemical_agents.svg @@ -0,0 +1,458 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg new file mode 100755 index 000000000..ace1a913a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/chemical_agents_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg b/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg new file mode 100755 index 000000000..9454aaa08 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/config_gobal_alarms.svg @@ -0,0 +1,508 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg b/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg new file mode 100755 index 000000000..6fc3547ed --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/config_gobal_alarms_disabled.svg @@ -0,0 +1,180 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_arrow.svg b/Z/src/nglwidgets/icons/svg/configure_arrow.svg new file mode 100755 index 000000000..2e7a4759e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_arrow.svg @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_buildings.svg b/Z/src/nglwidgets/icons/svg/configure_buildings.svg new file mode 100755 index 000000000..ba8ea62e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_buildings.svg @@ -0,0 +1,472 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg new file mode 100755 index 000000000..100885015 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_buildings_disabled.svg @@ -0,0 +1,143 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg new file mode 100755 index 000000000..ac9518afc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_line_of_sight.svg @@ -0,0 +1,509 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg new file mode 100755 index 000000000..7b05ad00c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_line_of_sight_disabled.svg @@ -0,0 +1,184 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg new file mode 100755 index 000000000..d4831ad07 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg new file mode 100755 index 000000000..53ddc1bc4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_symbol_attributes_disabled.svg @@ -0,0 +1,144 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_tunnels.svg b/Z/src/nglwidgets/icons/svg/configure_tunnels.svg new file mode 100755 index 000000000..53fb4d258 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_tunnels.svg @@ -0,0 +1,498 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg b/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg new file mode 100755 index 000000000..3f8bb4cc1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/configure_tunnels_disabled.svg @@ -0,0 +1,173 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_distance_measure.svg b/Z/src/nglwidgets/icons/svg/create_distance_measure.svg new file mode 100755 index 000000000..b88d6233d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_distance_measure.svg @@ -0,0 +1,470 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg b/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg new file mode 100755 index 000000000..2301c4cff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_distance_measure_disabled.svg @@ -0,0 +1,142 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg b/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg new file mode 100755 index 000000000..6cd3fc562 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_evaluation_topic.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_image_topic.svg b/Z/src/nglwidgets/icons/svg/create_image_topic.svg new file mode 100755 index 000000000..7cd1bf70a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_image_topic.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg b/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg new file mode 100755 index 000000000..e08bcd0e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_lecture_topic.svg @@ -0,0 +1,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg b/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg new file mode 100755 index 000000000..0eb493469 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_pdf_topic.svg @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_snapshot.svg b/Z/src/nglwidgets/icons/svg/create_snapshot.svg new file mode 100755 index 000000000..286d1c909 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_snapshot.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg b/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg new file mode 100755 index 000000000..c087d179e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_snapshot_disabled.svg @@ -0,0 +1,147 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg b/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg new file mode 100755 index 000000000..41bd740a2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_terrain_profile.svg @@ -0,0 +1,433 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg b/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg new file mode 100755 index 000000000..64fb39ce8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_terrain_profile_disabled.svg @@ -0,0 +1,106 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_thp.svg b/Z/src/nglwidgets/icons/svg/create_thp.svg new file mode 100755 index 000000000..5159e00cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_thp.svg @@ -0,0 +1,430 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg new file mode 100755 index 000000000..cb2d24b1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/create_thp_disabled.svg @@ -0,0 +1,105 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/danger_areas.svg b/Z/src/nglwidgets/icons/svg/danger_areas.svg new file mode 100755 index 000000000..73505ebb7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/danger_areas.svg @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg b/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg new file mode 100755 index 000000000..c93934070 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/debug-execute-from-cursor.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg b/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg new file mode 100755 index 000000000..6c5e5399e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/debug-execute-to-cursor.svg @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/default_operator_rights.svg b/Z/src/nglwidgets/icons/svg/default_operator_rights.svg new file mode 100755 index 000000000..a199a6a58 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/default_operator_rights.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg b/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg new file mode 100755 index 000000000..e93eeb358 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/default_operator_rights_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_border_lines.svg b/Z/src/nglwidgets/icons/svg/define_border_lines.svg new file mode 100755 index 000000000..aa1c215d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_border_lines.svg @@ -0,0 +1,499 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg b/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg new file mode 100755 index 000000000..1582a5846 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_border_lines_disabled.svg @@ -0,0 +1,172 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_force_templates.svg b/Z/src/nglwidgets/icons/svg/define_force_templates.svg new file mode 100755 index 000000000..1dabd3595 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_force_templates.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg b/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg new file mode 100755 index 000000000..b23e3f59d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_force_templates_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg b/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg new file mode 100755 index 000000000..836d1d3a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_movement_simulation.svg @@ -0,0 +1,500 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg b/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg new file mode 100755 index 000000000..01ea0b11c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_movement_simulation_disabled.svg @@ -0,0 +1,181 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_player_types.svg b/Z/src/nglwidgets/icons/svg/define_player_types.svg new file mode 100755 index 000000000..e02062869 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_player_types.svg @@ -0,0 +1,536 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg b/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg new file mode 100755 index 000000000..b7a4ac9ca --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_player_types_disabled.svg @@ -0,0 +1,213 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_position_system.svg b/Z/src/nglwidgets/icons/svg/define_position_system.svg new file mode 100755 index 000000000..797da2f2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_position_system.svg @@ -0,0 +1,427 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg b/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg new file mode 100755 index 000000000..1243fba5d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_position_system_disabled.svg @@ -0,0 +1,99 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_presentation.svg b/Z/src/nglwidgets/icons/svg/define_presentation.svg new file mode 100755 index 000000000..5efcfc7b9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_presentation.svg @@ -0,0 +1,400 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg b/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg new file mode 100755 index 000000000..8f1ff705a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_presentation_disabled.svg @@ -0,0 +1,72 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg b/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg new file mode 100755 index 000000000..8489b1bd0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_tactical_symbols.svg @@ -0,0 +1,434 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg b/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg new file mode 100755 index 000000000..d9a9fac15 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_tactical_symbols_disabled.svg @@ -0,0 +1,103 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_teams.svg b/Z/src/nglwidgets/icons/svg/define_teams.svg new file mode 100755 index 000000000..285345d24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_teams.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg b/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg new file mode 100755 index 000000000..6cf2e9a19 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_teams_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_training_cycles.svg b/Z/src/nglwidgets/icons/svg/define_training_cycles.svg new file mode 100755 index 000000000..6f568d894 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_training_cycles.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg b/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg new file mode 100755 index 000000000..d4896dc8e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/define_training_cycles_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/delete_thp.svg b/Z/src/nglwidgets/icons/svg/delete_thp.svg new file mode 100755 index 000000000..404ad5adb --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/delete_thp.svg @@ -0,0 +1,424 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg new file mode 100755 index 000000000..28b971f04 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/delete_thp_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-close.svg b/Z/src/nglwidgets/icons/svg/dialog-close.svg new file mode 100755 index 000000000..e3698bf46 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-close.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg b/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg new file mode 100755 index 000000000..2c681d099 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-ok-apply.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/dialog-ok.svg b/Z/src/nglwidgets/icons/svg/dialog-ok.svg new file mode 100755 index 000000000..2c681d099 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/dialog-ok.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg b/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg new file mode 100755 index 000000000..1b1827295 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_oc_evaluations.svg @@ -0,0 +1,403 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg b/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg new file mode 100755 index 000000000..54bf1d1bc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_oc_evaluations_disabled.svg @@ -0,0 +1,74 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_reports.svg b/Z/src/nglwidgets/icons/svg/display_reports.svg new file mode 100755 index 000000000..68c915df1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_reports.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg b/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg new file mode 100755 index 000000000..b7ccd6f7c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/display_reports_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-edit.svg b/Z/src/nglwidgets/icons/svg/document-edit.svg new file mode 100755 index 000000000..7a8dcf427 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-edit.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-new.svg b/Z/src/nglwidgets/icons/svg/document-new.svg new file mode 100755 index 000000000..5a71e4180 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-new.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-open-data.svg b/Z/src/nglwidgets/icons/svg/document-open-data.svg new file mode 100755 index 000000000..7a092bb81 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-open-data.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-open.svg b/Z/src/nglwidgets/icons/svg/document-open.svg new file mode 100755 index 000000000..de55c507f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-open.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/document-properties.svg b/Z/src/nglwidgets/icons/svg/document-properties.svg new file mode 100755 index 000000000..b13f1af77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/document-properties.svg @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/documents.svg b/Z/src/nglwidgets/icons/svg/documents.svg new file mode 100755 index 000000000..b59dd88af --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/documents.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/documents_disabled.svg b/Z/src/nglwidgets/icons/svg/documents_disabled.svg new file mode 100755 index 000000000..9533e9eab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/documents_disabled.svg @@ -0,0 +1,88 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/download.svg b/Z/src/nglwidgets/icons/svg/download.svg new file mode 100755 index 000000000..233f6a637 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/download.svg @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg b/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg new file mode 100755 index 000000000..5658841dc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/draw-bezier-curves.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit-cut.svg b/Z/src/nglwidgets/icons/svg/edit-cut.svg new file mode 100755 index 000000000..798bec2cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit-cut.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg new file mode 100755 index 000000000..7a135b55a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg new file mode 100755 index 000000000..aafb01c28 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/edit_evaluation_marker_disabled.svg @@ -0,0 +1,144 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg new file mode 100755 index 000000000..78c9b3c77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures.svg @@ -0,0 +1,488 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg new file mode 100755 index 000000000..e80a8fd37 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/electronical_warfare_measures_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluate.svg b/Z/src/nglwidgets/icons/svg/evaluate.svg new file mode 100755 index 000000000..788eb9616 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluate.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg b/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg new file mode 100755 index 000000000..bbf8d9af3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluate_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluation_elements.svg b/Z/src/nglwidgets/icons/svg/evaluation_elements.svg new file mode 100755 index 000000000..2165fab2c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluation_elements.svg @@ -0,0 +1,441 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg b/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg new file mode 100755 index 000000000..9cf604e12 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/evaluation_elements_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/execute_presentation.svg b/Z/src/nglwidgets/icons/svg/execute_presentation.svg new file mode 100755 index 000000000..0c402ae31 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/execute_presentation.svg @@ -0,0 +1,406 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg b/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg new file mode 100755 index 000000000..2d188ba40 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/execute_presentation_disabled.svg @@ -0,0 +1,78 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_force.svg b/Z/src/nglwidgets/icons/svg/exercise_force.svg new file mode 100755 index 000000000..64c7ca0e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_force.svg @@ -0,0 +1,429 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg b/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg new file mode 100755 index 000000000..489e516c3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_force_disabled.svg @@ -0,0 +1,103 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_purpose.svg b/Z/src/nglwidgets/icons/svg/exercise_purpose.svg new file mode 100755 index 000000000..3c9e513cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_purpose.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg b/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg new file mode 100755 index 000000000..83760b523 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/exercise_purpose_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/export_documents.svg b/Z/src/nglwidgets/icons/svg/export_documents.svg new file mode 100755 index 000000000..d9ea82218 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/export_documents.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg new file mode 100755 index 000000000..e2bb9b919 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/export_documents_disabled.svg @@ -0,0 +1,80 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fill_pattern.svg b/Z/src/nglwidgets/icons/svg/fill_pattern.svg new file mode 100755 index 000000000..6ab4a527f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fill_pattern.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_barriers.svg b/Z/src/nglwidgets/icons/svg/filter_barriers.svg new file mode 100755 index 000000000..0ff121de7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_barriers.svg @@ -0,0 +1,498 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg new file mode 100755 index 000000000..4bc951801 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_barriers_disabled.svg @@ -0,0 +1,178 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_border_lines.svg b/Z/src/nglwidgets/icons/svg/filter_border_lines.svg new file mode 100755 index 000000000..d7ffce356 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_border_lines.svg @@ -0,0 +1,475 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg new file mode 100755 index 000000000..7fec1b515 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_border_lines_disabled.svg @@ -0,0 +1,151 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg b/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg new file mode 100755 index 000000000..39e5963a4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_collapse_expand.svg @@ -0,0 +1,434 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg new file mode 100755 index 000000000..097142d24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_collapse_expand_disabled.svg @@ -0,0 +1,112 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg b/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg new file mode 100755 index 000000000..27f4e0bee --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_effect_simulation.svg @@ -0,0 +1,494 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg new file mode 100755 index 000000000..258a5b9d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_effect_simulation_disabled.svg @@ -0,0 +1,170 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_firings.svg b/Z/src/nglwidgets/icons/svg/filter_firings.svg new file mode 100755 index 000000000..1f714465f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_firings.svg @@ -0,0 +1,478 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg new file mode 100755 index 000000000..9fc96185d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_firings_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg new file mode 100755 index 000000000..0283b392a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_line_of_sight.svg @@ -0,0 +1,444 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg new file mode 100755 index 000000000..9dffad910 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_line_of_sight_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings.svg new file mode 100755 index 000000000..d32cc6b66 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg new file mode 100755 index 000000000..faef4fedb --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg new file mode 100755 index 000000000..2466a4942 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_load.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg new file mode 100755 index 000000000..fd3921b75 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_map_settings_load_disabled.svg @@ -0,0 +1,93 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg new file mode 100755 index 000000000..54982a1c8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg new file mode 100755 index 000000000..d78639de0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_maps_settings_save_disabled.svg @@ -0,0 +1,97 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg b/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg new file mode 100755 index 000000000..0402593e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nbc_agents.svg @@ -0,0 +1,528 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg new file mode 100755 index 000000000..fde679fb5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nbc_agents_disabled.svg @@ -0,0 +1,204 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg b/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg new file mode 100755 index 000000000..0a2015c26 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nc_agents.svg @@ -0,0 +1,484 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg new file mode 100755 index 000000000..2f0173fdd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_nc_agents_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_player.svg b/Z/src/nglwidgets/icons/svg/filter_player.svg new file mode 100755 index 000000000..818e288f1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_player.svg @@ -0,0 +1,452 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg new file mode 100755 index 000000000..0e722297c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_player_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_teams.svg b/Z/src/nglwidgets/icons/svg/filter_teams.svg new file mode 100755 index 000000000..d6ab1be3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_teams.svg @@ -0,0 +1,471 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg b/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg new file mode 100755 index 000000000..96fe60c5a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/filter_teams_disabled.svg @@ -0,0 +1,148 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg b/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg new file mode 100755 index 000000000..3999c20d4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fixed_video_announcement.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg b/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg new file mode 100755 index 000000000..fc9ad7879 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/fixed_video_announcement_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_composition.svg b/Z/src/nglwidgets/icons/svg/force_composition.svg new file mode 100755 index 000000000..759625f67 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_composition.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg b/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg new file mode 100755 index 000000000..cd54fa9d2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_composition_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_organization.svg b/Z/src/nglwidgets/icons/svg/force_organization.svg new file mode 100755 index 000000000..22b51f6a1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_organization.svg @@ -0,0 +1,504 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg b/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg new file mode 100755 index 000000000..8e8646205 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_organization_disabled.svg @@ -0,0 +1,179 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_player_configuration.svg b/Z/src/nglwidgets/icons/svg/force_player_configuration.svg new file mode 100755 index 000000000..8ccaf9cc6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_player_configuration.svg @@ -0,0 +1,486 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg new file mode 100755 index 000000000..38883f44c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/force_player_configuration_disabled.svg @@ -0,0 +1,160 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/freq_plan.svg b/Z/src/nglwidgets/icons/svg/freq_plan.svg new file mode 100755 index 000000000..5172450d0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/freq_plan.svg @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg b/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg new file mode 100755 index 000000000..959045201 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/function_key_toolbar.svg @@ -0,0 +1,463 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg new file mode 100755 index 000000000..d1e8b0f29 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/function_key_toolbar_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/getpos.svg b/Z/src/nglwidgets/icons/svg/getpos.svg new file mode 100755 index 000000000..8b1d4621d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/getpos.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_alarms_history.svg b/Z/src/nglwidgets/icons/svg/global_alarms_history.svg new file mode 100755 index 000000000..39c4b0e50 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_alarms_history.svg @@ -0,0 +1,450 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg b/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg new file mode 100755 index 000000000..d0c11b8ff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_alarms_history_disabled.svg @@ -0,0 +1,122 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg b/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg new file mode 100755 index 000000000..a6b236c73 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_exercise_settings.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg new file mode 100755 index 000000000..358d3cad5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/global_exercise_settings_disabled.svg @@ -0,0 +1,158 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/go-home.svg b/Z/src/nglwidgets/icons/svg/go-home.svg new file mode 100755 index 000000000..cae4a4c97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/go-home.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg b/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg new file mode 100755 index 000000000..def8e416a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/hand_grenade_locations.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/help_index.svg b/Z/src/nglwidgets/icons/svg/help_index.svg new file mode 100755 index 000000000..396b9af7c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/help_index.svg @@ -0,0 +1,451 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/help_index_disabled.svg b/Z/src/nglwidgets/icons/svg/help_index_disabled.svg new file mode 100755 index 000000000..1b7540b97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/help_index_disabled.svg @@ -0,0 +1,122 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_buildings.svg b/Z/src/nglwidgets/icons/svg/import_buildings.svg new file mode 100755 index 000000000..d3e4d2450 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_buildings.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg b/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg new file mode 100755 index 000000000..af3fe8254 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_buildings_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_documents.svg b/Z/src/nglwidgets/icons/svg/import_documents.svg new file mode 100755 index 000000000..a7c09ea2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_documents.svg @@ -0,0 +1,422 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg new file mode 100755 index 000000000..c51c78925 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_documents_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_images.svg b/Z/src/nglwidgets/icons/svg/import_images.svg new file mode 100755 index 000000000..98ee0b751 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_images.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_images_disabled.svg b/Z/src/nglwidgets/icons/svg/import_images_disabled.svg new file mode 100755 index 000000000..e3a30e6d2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_images_disabled.svg @@ -0,0 +1,90 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_msdl.svg b/Z/src/nglwidgets/icons/svg/import_msdl.svg new file mode 100755 index 000000000..5be893182 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_msdl.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_pdf_document.svg b/Z/src/nglwidgets/icons/svg/import_pdf_document.svg new file mode 100755 index 000000000..1fde92f8d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_pdf_document.svg @@ -0,0 +1,457 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg b/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg new file mode 100755 index 000000000..e42178c28 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_pdf_document_disabled.svg @@ -0,0 +1,132 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_video.svg b/Z/src/nglwidgets/icons/svg/import_video.svg new file mode 100755 index 000000000..b09ac659c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_video.svg @@ -0,0 +1,478 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/import_video_disabled.svg b/Z/src/nglwidgets/icons/svg/import_video_disabled.svg new file mode 100755 index 000000000..b4689be38 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/import_video_disabled.svg @@ -0,0 +1,153 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/insert_script.svg b/Z/src/nglwidgets/icons/svg/insert_script.svg new file mode 100755 index 000000000..243a82fb6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/insert_script.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/karte.svg b/Z/src/nglwidgets/icons/svg/karte.svg new file mode 100755 index 000000000..69e51c878 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/karte.svg @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/layer.svg b/Z/src/nglwidgets/icons/svg/layer.svg new file mode 100755 index 000000000..cae1fb22c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/layer.svg @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/line_styles.svg b/Z/src/nglwidgets/icons/svg/line_styles.svg new file mode 100755 index 000000000..864bb84c2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/line_styles.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/list-add-user.svg b/Z/src/nglwidgets/icons/svg/list-add-user.svg new file mode 100755 index 000000000..c63462dc0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/list-add-user.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/list-remove-user.svg b/Z/src/nglwidgets/icons/svg/list-remove-user.svg new file mode 100755 index 000000000..47295b88f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/list-remove-user.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load.svg b/Z/src/nglwidgets/icons/svg/load.svg new file mode 100755 index 000000000..a40090801 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load.svg @@ -0,0 +1,392 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_disabled.svg b/Z/src/nglwidgets/icons/svg/load_disabled.svg new file mode 100755 index 000000000..896263881 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_disabled.svg @@ -0,0 +1,67 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_global_filter.svg b/Z/src/nglwidgets/icons/svg/load_global_filter.svg new file mode 100755 index 000000000..a85ad746d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_global_filter.svg @@ -0,0 +1,456 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg b/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg new file mode 100755 index 000000000..b897c0f2a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/load_global_filter_disabled.svg @@ -0,0 +1,136 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/logout.svg b/Z/src/nglwidgets/icons/svg/logout.svg new file mode 100755 index 000000000..748ce863e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/logout.svg @@ -0,0 +1,413 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/logout_disabled.svg b/Z/src/nglwidgets/icons/svg/logout_disabled.svg new file mode 100755 index 000000000..394252888 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/logout_disabled.svg @@ -0,0 +1,85 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_context_menu.svg b/Z/src/nglwidgets/icons/svg/map_context_menu.svg new file mode 100755 index 000000000..ad81403ee --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_context_menu.svg @@ -0,0 +1,487 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg new file mode 100755 index 000000000..761740631 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_context_menu_disabled.svg @@ -0,0 +1,143 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_settings.svg b/Z/src/nglwidgets/icons/svg/map_settings.svg new file mode 100755 index 000000000..859ba8d7d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_settings.svg @@ -0,0 +1,484 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg b/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg new file mode 100755 index 000000000..b2c1fd635 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/map_settings_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marke.svg b/Z/src/nglwidgets/icons/svg/marke.svg new file mode 100755 index 000000000..5cb3964a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marke.svg @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marker-end.svg b/Z/src/nglwidgets/icons/svg/marker-end.svg new file mode 100755 index 000000000..7d65e0a79 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marker-end.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/marker-start.svg b/Z/src/nglwidgets/icons/svg/marker-start.svg new file mode 100755 index 000000000..d6a261122 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/marker-start.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-flash.svg b/Z/src/nglwidgets/icons/svg/media-flash.svg new file mode 100755 index 000000000..70d4d1498 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-flash.svg @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-play-backward.svg b/Z/src/nglwidgets/icons/svg/media-play-backward.svg new file mode 100755 index 000000000..c0c472b4b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-play-backward.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-play-slower.svg b/Z/src/nglwidgets/icons/svg/media-play-slower.svg new file mode 100755 index 000000000..05c5a74fc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-play-slower.svg @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-record.svg b/Z/src/nglwidgets/icons/svg/media-record.svg new file mode 100755 index 000000000..cdaaaa8c6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-record.svg @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-seek-backward.svg b/Z/src/nglwidgets/icons/svg/media-seek-backward.svg new file mode 100755 index 000000000..56f4fe98a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-seek-backward.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-seek-forward.svg b/Z/src/nglwidgets/icons/svg/media-seek-forward.svg new file mode 100755 index 000000000..6af8a834b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-seek-forward.svg @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-skip-backward.svg b/Z/src/nglwidgets/icons/svg/media-skip-backward.svg new file mode 100755 index 000000000..7d3182cc3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-skip-backward.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-skip-forward.svg b/Z/src/nglwidgets/icons/svg/media-skip-forward.svg new file mode 100755 index 000000000..91128d7e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-skip-forward.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg b/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg new file mode 100755 index 000000000..0dafe612e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-nopause.svg @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg b/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg new file mode 100755 index 000000000..a18310292 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-normal.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg b/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg new file mode 100755 index 000000000..cc971c920 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/media-vcr-withpause.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/messages.svg b/Z/src/nglwidgets/icons/svg/messages.svg new file mode 100755 index 000000000..3bf65baed --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/messages.svg @@ -0,0 +1,391 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/messages_disabled.svg b/Z/src/nglwidgets/icons/svg/messages_disabled.svg new file mode 100755 index 000000000..726a2cf4c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/messages_disabled.svg @@ -0,0 +1,65 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/metereological_data.svg b/Z/src/nglwidgets/icons/svg/metereological_data.svg new file mode 100755 index 000000000..9ab1ba594 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/metereological_data.svg @@ -0,0 +1,417 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg b/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg new file mode 100755 index 000000000..e94331f77 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/metereological_data_disabled.svg @@ -0,0 +1,91 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mgrs_grid.svg b/Z/src/nglwidgets/icons/svg/mgrs_grid.svg new file mode 100755 index 000000000..64de9363d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mgrs_grid.svg @@ -0,0 +1,504 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg b/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg new file mode 100755 index 000000000..da7a521e2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mgrs_grid_disabled.svg @@ -0,0 +1,178 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg new file mode 100755 index 000000000..a3318771c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor.svg @@ -0,0 +1,485 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg new file mode 100755 index 000000000..e3dc437d3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barrier_corridor_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barriers.svg b/Z/src/nglwidgets/icons/svg/mine_barriers.svg new file mode 100755 index 000000000..487111f2a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barriers.svg @@ -0,0 +1,490 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg b/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg new file mode 100755 index 000000000..6336466db --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mine_barriers_disabled.svg @@ -0,0 +1,169 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mini_map.svg b/Z/src/nglwidgets/icons/svg/mini_map.svg new file mode 100755 index 000000000..5abd748c7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mini_map.svg @@ -0,0 +1,514 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg b/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg new file mode 100755 index 000000000..6ecf294bd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mini_map_disabled.svg @@ -0,0 +1,191 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mlvs_control.svg b/Z/src/nglwidgets/icons/svg/mlvs_control.svg new file mode 100755 index 000000000..0c091060c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mlvs_control.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mobile_video.svg b/Z/src/nglwidgets/icons/svg/mobile_video.svg new file mode 100755 index 000000000..7a8c5e5ab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mobile_video.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg b/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg new file mode 100755 index 000000000..3cf44de7a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mobile_video_disabled.svg @@ -0,0 +1,82 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg new file mode 100755 index 000000000..a92e7a999 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration.svg @@ -0,0 +1,440 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg new file mode 100755 index 000000000..07431ac94 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_administration_disabled.svg @@ -0,0 +1,111 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg new file mode 100755 index 000000000..649beca11 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg new file mode 100755 index 000000000..948e0dcbc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/mortar_ammunition_firings_disabled.svg @@ -0,0 +1,145 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/network-wireless.svg b/Z/src/nglwidgets/icons/svg/network-wireless.svg new file mode 100755 index 000000000..3dcc638fe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/network-wireless.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/new_documents.svg b/Z/src/nglwidgets/icons/svg/new_documents.svg new file mode 100755 index 000000000..e88f5a1d5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/new_documents.svg @@ -0,0 +1,885 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg b/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg new file mode 100755 index 000000000..d759edd43 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/new_mail_indicator.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/nuclear_agents.svg b/Z/src/nglwidgets/icons/svg/nuclear_agents.svg new file mode 100755 index 000000000..2dc41ba3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/nuclear_agents.svg @@ -0,0 +1,422 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/object-group.svg b/Z/src/nglwidgets/icons/svg/object-group.svg new file mode 100755 index 000000000..f82c93259 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/object-group.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/object-ungroup.svg b/Z/src/nglwidgets/icons/svg/object-ungroup.svg new file mode 100755 index 000000000..606246f1e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/object-ungroup.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/objects_define_areas.svg b/Z/src/nglwidgets/icons/svg/objects_define_areas.svg new file mode 100755 index 000000000..36d137071 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/objects_define_areas.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg b/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg new file mode 100755 index 000000000..32ace712c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/objects_define_areas_disabled.svg @@ -0,0 +1,139 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg b/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg new file mode 100755 index 000000000..ee39e7696 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_aar_preparation.svg @@ -0,0 +1,421 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg new file mode 100755 index 000000000..f9a2d977d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_aar_preparation_disabled.svg @@ -0,0 +1,94 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_composition.svg b/Z/src/nglwidgets/icons/svg/oc_composition.svg new file mode 100755 index 000000000..6080fd7fe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_composition.svg @@ -0,0 +1,479 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg new file mode 100755 index 000000000..1c1dfcb21 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_composition_disabled.svg @@ -0,0 +1,154 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg new file mode 100755 index 000000000..3890ab265 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes.svg @@ -0,0 +1,457 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg new file mode 100755 index 000000000..9f87bc67a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_evaluation_schemes_disabled.svg @@ -0,0 +1,135 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg b/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg new file mode 100755 index 000000000..5a1963853 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_player_configuration.svg @@ -0,0 +1,488 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg new file mode 100755 index 000000000..2aa674fe3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/oc_player_configuration_disabled.svg @@ -0,0 +1,163 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/operator_administration.svg b/Z/src/nglwidgets/icons/svg/operator_administration.svg new file mode 100755 index 000000000..3d335eed6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/operator_administration.svg @@ -0,0 +1,458 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg b/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg new file mode 100755 index 000000000..2d1a62843 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/operator_administration_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_documents.svg b/Z/src/nglwidgets/icons/svg/organize_documents.svg new file mode 100755 index 000000000..38cb93d56 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_documents.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg new file mode 100755 index 000000000..0ce4eb0f5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_documents_disabled.svg @@ -0,0 +1,95 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_library.svg b/Z/src/nglwidgets/icons/svg/organize_library.svg new file mode 100755 index 000000000..3e1983811 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_library.svg @@ -0,0 +1,467 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg b/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg new file mode 100755 index 000000000..e3037438d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/organize_library_disabled.svg @@ -0,0 +1,151 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlay_plans.svg b/Z/src/nglwidgets/icons/svg/overlay_plans.svg new file mode 100755 index 000000000..22fd90fc7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlay_plans.svg @@ -0,0 +1,442 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg b/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg new file mode 100755 index 000000000..74067a9f0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlay_plans_disabled.svg @@ -0,0 +1,115 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/overlays.svg b/Z/src/nglwidgets/icons/svg/overlays.svg new file mode 100755 index 000000000..85a487c94 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/overlays.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/phase_def.svg b/Z/src/nglwidgets/icons/svg/phase_def.svg new file mode 100755 index 000000000..430caed90 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/phase_def.svg @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg b/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg new file mode 100755 index 000000000..76dae5f14 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_collapse.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_expand.svg b/Z/src/nglwidgets/icons/svg/pi_force_expand.svg new file mode 100755 index 000000000..3780ee97c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_expand.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_left.svg b/Z/src/nglwidgets/icons/svg/pi_force_left.svg new file mode 100755 index 000000000..8c1c1764c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_left.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_force_right.svg b/Z/src/nglwidgets/icons/svg/pi_force_right.svg new file mode 100755 index 000000000..f96098ff6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_force_right.svg @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg b/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg new file mode 100755 index 000000000..4301cc243 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_markup_3d.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg b/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg new file mode 100755 index 000000000..b1f833788 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_movementtrack.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_nbc.svg b/Z/src/nglwidgets/icons/svg/pi_nbc.svg new file mode 100755 index 000000000..7bea5715f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_nbc.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg b/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg new file mode 100755 index 000000000..99419e6f9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_set_player_mode.svg @@ -0,0 +1,401 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_show_bite.svg b/Z/src/nglwidgets/icons/svg/pi_show_bite.svg new file mode 100755 index 000000000..7eed0bec3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_show_bite.svg @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_show_building.svg b/Z/src/nglwidgets/icons/svg/pi_show_building.svg new file mode 100755 index 000000000..ba8ea62e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_show_building.svg @@ -0,0 +1,472 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg b/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg new file mode 100755 index 000000000..0a6074d3e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_tact_status_history.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg b/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg new file mode 100755 index 000000000..4dce0e5b5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/pi_type_weaponrange.svg @@ -0,0 +1,752 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg b/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg new file mode 100755 index 000000000..611fa0bcc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/planned_training_cycles.svg @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/plans.svg b/Z/src/nglwidgets/icons/svg/plans.svg new file mode 100755 index 000000000..933ebedd3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/plans.svg @@ -0,0 +1,410 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/plans_disabled.svg b/Z/src/nglwidgets/icons/svg/plans_disabled.svg new file mode 100755 index 000000000..e96bf9bb4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/plans_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_audio.svg b/Z/src/nglwidgets/icons/svg/playback_audio.svg new file mode 100755 index 000000000..a9e152c2e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_audio.svg @@ -0,0 +1,426 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg new file mode 100755 index 000000000..f351f8dbc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_audio_disabled.svg @@ -0,0 +1,100 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_situation.svg b/Z/src/nglwidgets/icons/svg/playback_situation.svg new file mode 100755 index 000000000..560613519 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_situation.svg @@ -0,0 +1,413 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg new file mode 100755 index 000000000..62bc4696e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_situation_disabled.svg @@ -0,0 +1,87 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_video.svg b/Z/src/nglwidgets/icons/svg/playback_video.svg new file mode 100755 index 000000000..2acb360cf --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_video.svg @@ -0,0 +1,427 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg b/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg new file mode 100755 index 000000000..2bf0300c4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/playback_video_disabled.svg @@ -0,0 +1,101 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_equipment.svg b/Z/src/nglwidgets/icons/svg/player_equipment.svg new file mode 100755 index 000000000..02314867d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment.svg @@ -0,0 +1,675 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/player_equipment_check.svg b/Z/src/nglwidgets/icons/svg/player_equipment_check.svg new file mode 100755 index 000000000..37bcd9621 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment_check.svg @@ -0,0 +1,425 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg b/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg new file mode 100755 index 000000000..caa410bd1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_equipment_check_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/player_mode.svg b/Z/src/nglwidgets/icons/svg/player_mode.svg new file mode 100755 index 000000000..a64c09845 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/player_mode.svg @@ -0,0 +1,647 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg b/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg new file mode 100755 index 000000000..604c98f8e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/preferences-web-browser-cache.svg @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/prepare_thp.svg b/Z/src/nglwidgets/icons/svg/prepare_thp.svg new file mode 100755 index 000000000..3bb0d4c83 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/prepare_thp.svg @@ -0,0 +1,452 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg b/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg new file mode 100755 index 000000000..500cf6039 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/prepare_thp_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/presets.svg b/Z/src/nglwidgets/icons/svg/presets.svg new file mode 100755 index 000000000..cced0bf24 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/presets.svg @@ -0,0 +1,476 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/presets_disabled.svg b/Z/src/nglwidgets/icons/svg/presets_disabled.svg new file mode 100755 index 000000000..8916051fd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/presets_disabled.svg @@ -0,0 +1,153 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_position.svg b/Z/src/nglwidgets/icons/svg/primary_map_position.svg new file mode 100755 index 000000000..1ac777b52 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_position.svg @@ -0,0 +1,407 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg b/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg new file mode 100755 index 000000000..f50c3151b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_position_disabled.svg @@ -0,0 +1,81 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg b/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg new file mode 100755 index 000000000..0cc2d8dab --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_toolbar.svg @@ -0,0 +1,448 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg new file mode 100755 index 000000000..555468128 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/primary_map_toolbar_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/proj_audio.svg b/Z/src/nglwidgets/icons/svg/proj_audio.svg new file mode 100755 index 000000000..7c39f53b1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/proj_audio.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/projection.svg b/Z/src/nglwidgets/icons/svg/projection.svg new file mode 100755 index 000000000..908755ff8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/projection.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/raster.svg b/Z/src/nglwidgets/icons/svg/raster.svg new file mode 100755 index 000000000..fcc4dce46 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/raster.svg @@ -0,0 +1,390 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/raster_disabled.svg b/Z/src/nglwidgets/icons/svg/raster_disabled.svg new file mode 100755 index 000000000..8113f995a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/raster_disabled.svg @@ -0,0 +1,68 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg new file mode 100755 index 000000000..15dce8e84 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_left.svg @@ -0,0 +1,431 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg new file mode 100755 index 000000000..baccaa1d8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_left_disabled.svg @@ -0,0 +1,107 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg new file mode 100755 index 000000000..16d992ea0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply.svg @@ -0,0 +1,502 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg new file mode 100755 index 000000000..98b7f8af3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_ammunition_resupply_disabled.svg @@ -0,0 +1,179 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_awes.svg b/Z/src/nglwidgets/icons/svg/report_awes.svg new file mode 100755 index 000000000..d4cd4eb63 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_awes.svg @@ -0,0 +1,493 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg b/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg new file mode 100755 index 000000000..e42b699a0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_awes_disabled.svg @@ -0,0 +1,168 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg new file mode 100755 index 000000000..92a74f79c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg new file mode 100755 index 000000000..5e51749a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_effectiveness_disabled.svg @@ -0,0 +1,155 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_power.svg b/Z/src/nglwidgets/icons/svg/report_combat_power.svg new file mode 100755 index 000000000..45f2beb59 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_power.svg @@ -0,0 +1,494 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg b/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg new file mode 100755 index 000000000..a633d678e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_combat_power_disabled.svg @@ -0,0 +1,168 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg b/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg new file mode 100755 index 000000000..998c8b761 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_explosive_devices.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg b/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg new file mode 100755 index 000000000..271ece621 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_explosive_devices_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_maintenance.svg b/Z/src/nglwidgets/icons/svg/report_maintenance.svg new file mode 100755 index 000000000..39fbaccd2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_maintenance.svg @@ -0,0 +1,432 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg b/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg new file mode 100755 index 000000000..c20f42e8f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_maintenance_disabled.svg @@ -0,0 +1,108 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg b/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg new file mode 100755 index 000000000..e811b87cc --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mine_barrier.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg b/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg new file mode 100755 index 000000000..89fd37a38 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mine_barrier_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg b/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg new file mode 100755 index 000000000..d98602720 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mortar_firings.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg b/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg new file mode 100755 index 000000000..37b454005 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_mortar_firings_disabled.svg @@ -0,0 +1,135 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nbc_events.svg b/Z/src/nglwidgets/icons/svg/report_nbc_events.svg new file mode 100755 index 000000000..2e767babd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nbc_events.svg @@ -0,0 +1,493 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg b/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg new file mode 100755 index 000000000..d04d44f0f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nbc_events_disabled.svg @@ -0,0 +1,170 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nc_events.svg b/Z/src/nglwidgets/icons/svg/report_nc_events.svg new file mode 100755 index 000000000..c37190392 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nc_events.svg @@ -0,0 +1,464 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg b/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg new file mode 100755 index 000000000..157345f39 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_nc_events_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatment.svg b/Z/src/nglwidgets/icons/svg/report_treatment.svg new file mode 100755 index 000000000..35c5b843b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatment.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg b/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg new file mode 100755 index 000000000..2e3233a9a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatment_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg new file mode 100755 index 000000000..5d24dbf0e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance.svg @@ -0,0 +1,460 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg new file mode 100755 index 000000000..6ac9da8fd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/report_treatmentmaintanance_disabled.svg @@ -0,0 +1,136 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/save_preferences.svg b/Z/src/nglwidgets/icons/svg/save_preferences.svg new file mode 100755 index 000000000..be9ac7655 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/save_preferences.svg @@ -0,0 +1,468 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg b/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg new file mode 100755 index 000000000..ef52c1173 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/save_preferences_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/screenshot.svg b/Z/src/nglwidgets/icons/svg/screenshot.svg new file mode 100755 index 000000000..908f73cdd --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/screenshot.svg @@ -0,0 +1,398 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg b/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg new file mode 100755 index 000000000..c17f1f486 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/screenshot_disabled.svg @@ -0,0 +1,71 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_position.svg b/Z/src/nglwidgets/icons/svg/secondary_map_position.svg new file mode 100755 index 000000000..76b0d6ae3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_position.svg @@ -0,0 +1,420 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg b/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg new file mode 100755 index 000000000..5f47cc1ad --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_position_disabled.svg @@ -0,0 +1,96 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg new file mode 100755 index 000000000..bc52549c3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg new file mode 100755 index 000000000..deee01088 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/secondary_map_toolbar_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_player.svg b/Z/src/nglwidgets/icons/svg/select_player.svg new file mode 100755 index 000000000..686e0d60d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_player.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_player_disabled.svg b/Z/src/nglwidgets/icons/svg/select_player_disabled.svg new file mode 100755 index 000000000..afd5a48e5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_player_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_areas.svg b/Z/src/nglwidgets/icons/svg/select_training_areas.svg new file mode 100755 index 000000000..f7d853b9c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_areas.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg b/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg new file mode 100755 index 000000000..a7270398d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_areas_disabled.svg @@ -0,0 +1,77 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_cylces.svg b/Z/src/nglwidgets/icons/svg/select_training_cylces.svg new file mode 100755 index 000000000..d0c8d0c66 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_cylces.svg @@ -0,0 +1,442 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg b/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg new file mode 100755 index 000000000..5796cbcf5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/select_training_cylces_disabled.svg @@ -0,0 +1,114 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/send_player_message.svg b/Z/src/nglwidgets/icons/svg/send_player_message.svg new file mode 100755 index 000000000..fc451da51 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/send_player_message.svg @@ -0,0 +1,419 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg b/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg new file mode 100755 index 000000000..b03460762 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/send_player_message_disabled.svg @@ -0,0 +1,92 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_exercise_process.svg b/Z/src/nglwidgets/icons/svg/set_exercise_process.svg new file mode 100755 index 000000000..cb9db79e4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_exercise_process.svg @@ -0,0 +1,485 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg b/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg new file mode 100755 index 000000000..719db3855 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_exercise_process_disabled.svg @@ -0,0 +1,161 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_force_visibility.svg b/Z/src/nglwidgets/icons/svg/set_force_visibility.svg new file mode 100755 index 000000000..e9a9dd76c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_force_visibility.svg @@ -0,0 +1,477 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg b/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg new file mode 100755 index 000000000..cd63475a7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_force_visibility_disabled.svg @@ -0,0 +1,149 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_home_transparency.svg b/Z/src/nglwidgets/icons/svg/set_home_transparency.svg new file mode 100755 index 000000000..f5f87f569 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_home_transparency.svg @@ -0,0 +1,444 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg b/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg new file mode 100755 index 000000000..7c9712df8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_home_transparency_disabled.svg @@ -0,0 +1,119 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_situation.svg b/Z/src/nglwidgets/icons/svg/set_marker_situation.svg new file mode 100755 index 000000000..8687617f0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_situation.svg @@ -0,0 +1,445 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg b/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg new file mode 100755 index 000000000..ea9574219 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_situation_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_video.svg b/Z/src/nglwidgets/icons/svg/set_marker_video.svg new file mode 100755 index 000000000..def00415c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_video.svg @@ -0,0 +1,474 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg b/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg new file mode 100755 index 000000000..7083a66e8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_marker_video_disabled.svg @@ -0,0 +1,155 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_markers_audio.svg b/Z/src/nglwidgets/icons/svg/set_markers_audio.svg new file mode 100755 index 000000000..49738a3aa --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_markers_audio.svg @@ -0,0 +1,461 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg b/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg new file mode 100755 index 000000000..dbd4ccf1c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_markers_audio_disabled.svg @@ -0,0 +1,139 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_mode.svg b/Z/src/nglwidgets/icons/svg/set_player_mode.svg new file mode 100755 index 000000000..99419e6f9 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_mode.svg @@ -0,0 +1,401 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg b/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg new file mode 100755 index 000000000..dc141325e --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_mode_disabled.svg @@ -0,0 +1,73 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_status.svg b/Z/src/nglwidgets/icons/svg/set_player_status.svg new file mode 100755 index 000000000..885991ef1 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_status.svg @@ -0,0 +1,391 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg b/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg new file mode 100755 index 000000000..13256964a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_player_status_disabled.svg @@ -0,0 +1,67 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_view_position.svg b/Z/src/nglwidgets/icons/svg/set_view_position.svg new file mode 100755 index 000000000..ff4c02741 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_view_position.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg b/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg new file mode 100755 index 000000000..620038960 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/set_view_position_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_building_configuration.svg b/Z/src/nglwidgets/icons/svg/show_building_configuration.svg new file mode 100755 index 000000000..2bc11ba20 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_building_configuration.svg @@ -0,0 +1,466 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg b/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg new file mode 100755 index 000000000..e78b52ad7 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_building_configuration_disabled.svg @@ -0,0 +1,138 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_distance_measure.svg b/Z/src/nglwidgets/icons/svg/show_distance_measure.svg new file mode 100755 index 000000000..9aecddd99 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_distance_measure.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg b/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg new file mode 100755 index 000000000..43598b35b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_distance_measure_disabled.svg @@ -0,0 +1,130 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg b/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg new file mode 100755 index 000000000..8fa74270c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_line_of_sight.svg @@ -0,0 +1,454 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg b/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg new file mode 100755 index 000000000..e47630f85 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_line_of_sight_disabled.svg @@ -0,0 +1,126 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg b/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg new file mode 100755 index 000000000..8369fd64f --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_terrain_profile.svg @@ -0,0 +1,439 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg b/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg new file mode 100755 index 000000000..f87cba6ca --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/show_terrain_profile_disabled.svg @@ -0,0 +1,113 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/simulated_players.svg b/Z/src/nglwidgets/icons/svg/simulated_players.svg new file mode 100755 index 000000000..160a8c90b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/simulated_players.svg @@ -0,0 +1,409 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg b/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg new file mode 100755 index 000000000..c0753761d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/simulated_players_disabled.svg @@ -0,0 +1,85 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/situation.svg b/Z/src/nglwidgets/icons/svg/situation.svg new file mode 100755 index 000000000..322407c51 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/situation.svg @@ -0,0 +1,431 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/situation_disabled.svg b/Z/src/nglwidgets/icons/svg/situation_disabled.svg new file mode 100755 index 000000000..68c3562a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/situation_disabled.svg @@ -0,0 +1,106 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/status_bar.svg b/Z/src/nglwidgets/icons/svg/status_bar.svg new file mode 100755 index 000000000..8242e778c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/status_bar.svg @@ -0,0 +1,486 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg b/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg new file mode 100755 index 000000000..f83cbc2a3 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/status_bar_disabled.svg @@ -0,0 +1,159 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/support_documents.svg b/Z/src/nglwidgets/icons/svg/support_documents.svg new file mode 100755 index 000000000..509995816 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/support_documents.svg @@ -0,0 +1,449 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg b/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg new file mode 100755 index 000000000..949fb80ff --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/support_documents_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_display.svg b/Z/src/nglwidgets/icons/svg/switch_display.svg new file mode 100755 index 000000000..9696386f5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_display.svg @@ -0,0 +1,435 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg new file mode 100755 index 000000000..c52204798 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_display_disabled.svg @@ -0,0 +1,111 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg b/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg new file mode 100755 index 000000000..0eb577e82 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_primary_map.svg @@ -0,0 +1,439 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg new file mode 100755 index 000000000..a71629dbe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_primary_map_disabled.svg @@ -0,0 +1,110 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg b/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg new file mode 100755 index 000000000..4cac60d52 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_sec_map.svg @@ -0,0 +1,447 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg b/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg new file mode 100755 index 000000000..17f105295 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/switch_to_sec_map_disabled.svg @@ -0,0 +1,120 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/symbol_display.svg b/Z/src/nglwidgets/icons/svg/symbol_display.svg new file mode 100755 index 000000000..1a3b62f01 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/symbol_display.svg @@ -0,0 +1,411 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg b/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg new file mode 100755 index 000000000..e1e4d2f67 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/symbol_display_disabled.svg @@ -0,0 +1,86 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/system_status.svg b/Z/src/nglwidgets/icons/svg/system_status.svg new file mode 100755 index 000000000..1bd6e4089 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/system_status.svg @@ -0,0 +1,456 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/system_status_disabled.svg b/Z/src/nglwidgets/icons/svg/system_status_disabled.svg new file mode 100755 index 000000000..96deaea44 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/system_status_disabled.svg @@ -0,0 +1,127 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_organization.svg b/Z/src/nglwidgets/icons/svg/tactical_organization.svg new file mode 100755 index 000000000..e0e5e4755 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_organization.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg b/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg new file mode 100755 index 000000000..6a9b558b5 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_organization_disabled.svg @@ -0,0 +1,129 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_symbol.svg b/Z/src/nglwidgets/icons/svg/tactical_symbol.svg new file mode 100755 index 000000000..070ba182b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_symbol.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg b/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg new file mode 100755 index 000000000..1f0136ce2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/tactical_symbol_disabled.svg @@ -0,0 +1,76 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/target.svg b/Z/src/nglwidgets/icons/svg/target.svg new file mode 100755 index 000000000..bc4dedd35 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/target.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/terminal_window.svg b/Z/src/nglwidgets/icons/svg/terminal_window.svg new file mode 100755 index 000000000..c500ee50d --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/terminal_window.svg @@ -0,0 +1,399 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg b/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg new file mode 100755 index 000000000..c28c6cfbe --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/terminal_window_disabled.svg @@ -0,0 +1,70 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/toolbar_editor.svg b/Z/src/nglwidgets/icons/svg/toolbar_editor.svg new file mode 100755 index 000000000..64c2ea51b --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/toolbar_editor.svg @@ -0,0 +1,480 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg b/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg new file mode 100755 index 000000000..f6fa9cd97 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/toolbar_editor_disabled.svg @@ -0,0 +1,157 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/translation_editor.svg b/Z/src/nglwidgets/icons/svg/translation_editor.svg new file mode 100755 index 000000000..380112458 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/translation_editor.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/update_player_position.svg b/Z/src/nglwidgets/icons/svg/update_player_position.svg new file mode 100755 index 000000000..f2b3b3af4 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/update_player_position.svg @@ -0,0 +1,423 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg b/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg new file mode 100755 index 000000000..bfe38e8a2 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/update_player_position_disabled.svg @@ -0,0 +1,97 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/video_menu.svg b/Z/src/nglwidgets/icons/svg/video_menu.svg new file mode 100755 index 000000000..84a23700c --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/video_menu.svg @@ -0,0 +1,404 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg b/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg new file mode 100755 index 000000000..ece02d315 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/video_menu_disabled.svg @@ -0,0 +1,79 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/view-statistics.svg b/Z/src/nglwidgets/icons/svg/view-statistics.svg new file mode 100755 index 000000000..c336800c6 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/view-statistics.svg @@ -0,0 +1,378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/visible_teams.svg b/Z/src/nglwidgets/icons/svg/visible_teams.svg new file mode 100755 index 000000000..3be836387 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/visible_teams.svg @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication.svg b/Z/src/nglwidgets/icons/svg/voice_communication.svg new file mode 100755 index 000000000..94ef1bfea --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication.svg @@ -0,0 +1,470 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_access.svg b/Z/src/nglwidgets/icons/svg/voice_communication_access.svg new file mode 100755 index 000000000..234cb72e0 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_access.svg @@ -0,0 +1,455 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg b/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg new file mode 100755 index 000000000..a78afc26a --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_access_disabled.svg @@ -0,0 +1,125 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg b/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg new file mode 100755 index 000000000..13e2f7706 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/voice_communication_disabled.svg @@ -0,0 +1,140 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/weapon_firing.svg b/Z/src/nglwidgets/icons/svg/weapon_firing.svg new file mode 100755 index 000000000..6a85a50ef --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/weapon_firing.svg @@ -0,0 +1,438 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg b/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg new file mode 100755 index 000000000..240c136a8 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/weapon_firing_disabled.svg @@ -0,0 +1,112 @@ + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/icons/svg/wireless.svg b/Z/src/nglwidgets/icons/svg/wireless.svg new file mode 100755 index 000000000..96ff4e729 --- /dev/null +++ b/Z/src/nglwidgets/icons/svg/wireless.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Z/src/nglwidgets/ngldialog.cpp b/Z/src/nglwidgets/ngldialog.cpp new file mode 100755 index 000000000..f7d6b3756 --- /dev/null +++ b/Z/src/nglwidgets/ngldialog.cpp @@ -0,0 +1,149 @@ + + +#include "ngldialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ngldialogbuttonbox.h" + +NGLDialog::NGLDialog(QWidget *parent, Qt::WindowFlags f) + : QDialog(parent, f) + , m_bReadOnly(false) +{ + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); +} + +void NGLDialog::setHelpContext(const QString &helpContext) +{ + m_helpContext = helpContext; +} + +void NGLDialog::showEvent(QShowEvent *e) +{ + NGLDialogButtonBox *bb = findChild(); + if (bb) + connect(bb, &NGLDialogButtonBox::onHelp, + this, &NGLDialog::onInvokeHelp, + Qt::UniqueConnection); + QDialog::showEvent(e); +} + +void NGLDialog::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_F1) + onInvokeHelp(); + if (e->key() == Qt::Key_P && + e->modifiers().testFlag(Qt::ControlModifier) && + e->modifiers().testFlag(Qt::AltModifier)) + printWidget(); + + QDialog::keyPressEvent(e); +} + +void NGLDialog::centerWidget(QWidget *widgetToCenter) +{ + if (!widgetToCenter) + return; + + QWidget *p = widgetToCenter->parentWidget(); + QPoint pPos; + QSize pSize; + if (p) + { + pPos = p->pos(); + pSize = p->size(); + } + else + { + QRect r = QGuiApplication::primaryScreen()->geometry(); + pPos = r.topLeft(); + pSize = r.size(); + } + + pPos.setX(pPos.x() + (pSize.width() / 2 - widgetToCenter->sizeHint().width() / 2)); + pPos.setY(pPos.y() + (pSize.height() / 2 - widgetToCenter->sizeHint().height() / 2)); + widgetToCenter->move(pPos); +} + +void NGLDialog::centerWidget() +{ + centerWidget(this); +} + +void NGLDialog::printWidget(QWidget *widgetToPrint) +{ + QRect r = widgetToPrint->frameGeometry(); + QPixmap pm = QApplication::desktop()->grab(r); + QString path = QString::fromLocal8Bit(qgetenv("GFS_PATH")); + if (path.isEmpty()) + path = QCoreApplication::applicationDirPath() + QLatin1String("/../images"); + time_t t = time(nullptr); + QString fn; + + NGLDialog *dlg = qobject_cast(widgetToPrint); + if (dlg && !dlg->m_helpContext.isEmpty()) + fn = path + QLatin1Char('/') + QString::number(t) + QLatin1Char('_') + dlg->m_helpContext + QLatin1String(".png"); + else + fn = path + QLatin1Char('/') + QString::number(t) + QLatin1String(".png"); + QDir d(path); + if (!d.exists()) + d.mkpath(path); + pm.save(fn, "PNG"); +} + +void NGLDialog::printWidget() +{ + printWidget(this); +} + +void NGLDialog::onInvokeHelp() +{ + NGLHelpEvent::sendHelpEvent(m_helpContext); +} + +void NGLDialog::setWindowTitle(const QString &title) +{ + m_realWindowTitle = title.trimmed(); + + QString newTitle = title; + if (m_bReadOnly) + { + if (!m_readOnlyReason.isEmpty()) + newTitle += QLatin1Char(' ') + tr("(locked by %1)").arg(m_readOnlyReason); + else + newTitle += QLatin1Char(' ') + tr("(read only)"); + } + newTitle += QLatin1String(" [*]"); + + QDialog::setWindowTitle(newTitle); +} + +QString NGLDialog::windowTitle() const +{ + return m_realWindowTitle; +} + +void NGLDialog::setDialogReadOnly(bool bReadOnly, const QString &reason) +{ + m_bReadOnly = bReadOnly; + if (bReadOnly && !reason.isEmpty()) + m_readOnlyReason = reason; + else + m_readOnlyReason.clear(); + + setWindowTitle(windowTitle()); +} + +bool NGLDialog::isDialogReadOnly() const +{ + return m_bReadOnly; +} diff --git a/Z/src/nglwidgets/ngldialog.h b/Z/src/nglwidgets/ngldialog.h new file mode 100755 index 000000000..97ebd239c --- /dev/null +++ b/Z/src/nglwidgets/ngldialog.h @@ -0,0 +1,62 @@ + + +#pragma once + +#include "nglwidgets_export.h" + +#include +#include "nglstandardbutton.h" + +class NGLWIDGETS_EXPORT NGLDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NGLDialog(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + + void setHelpContext(const QString &helpContext); + + + + static void centerWidget(QWidget *widgetToCenter); + + + + static void printWidget(QWidget *widgetToPrint); + + + + void setWindowTitle(const QString &title); + + + + QString windowTitle() const; + + + + void setDialogReadOnly(bool bReadOnly, const QString &reason = QString()); + + + + bool isDialogReadOnly() const; + +Q_SIGNALS: + + + void invokeHelp(const QString &helpContext); +protected: + virtual void showEvent(QShowEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + void centerWidget(); + void printWidget(); +protected Q_SLOTS: + + + void onInvokeHelp(); + +private: + QString m_helpContext; + bool m_bReadOnly; + QString m_readOnlyReason; + QString m_realWindowTitle; +}; diff --git a/Z/src/nglwidgets/ngldialogbuttonbox.cpp b/Z/src/nglwidgets/ngldialogbuttonbox.cpp new file mode 100755 index 000000000..3d22e646a --- /dev/null +++ b/Z/src/nglwidgets/ngldialogbuttonbox.cpp @@ -0,0 +1,445 @@ +#include "ngldialogbuttonbox.h" + +#include +#include +#include + +NGLDialogButtonBox::NGLDialogButtonBox(QWidget *parent) + : NGLDialogButtonBox(Qt::Horizontal, parent) +{} + +NGLDialogButtonBox::NGLDialogButtonBox(Qt::Orientation orientation, + QWidget *parent) + : QWidget(parent) + , m_orientation(orientation) + , m_buttons(nullptr) + , m_line(nullptr) + , m_bSpacer2ContextAction(nullptr) + , m_bLineVisible(true) +{ + setFocusPolicy(Qt::StrongFocus); + init(); +} + +NGLDialogButtonBox::NGLDialogButtonBox(NGLStandardButton::StandardButtons buttons, + Qt::Orientation orientation, + QWidget *parent) + : QWidget(parent) + , m_orientation(orientation) + , m_buttons(buttons) + , m_line(nullptr) + , m_bSpacer2ContextAction(nullptr) + , m_bLineVisible(true) +{ + setFocusPolicy(Qt::StrongFocus); + setStandardButtons(m_buttons); +} + +Qt::Orientation NGLDialogButtonBox::orientation() const +{ + return m_orientation; +} + +void NGLDialogButtonBox::setOrientation(Qt::Orientation orientation) +{ + if (m_orientation == orientation) + return; + m_orientation = orientation; + init(); +} + +NGLStandardButton::StandardButtons NGLDialogButtonBox::standardButtons() const +{ + return m_buttons; +} + +void NGLDialogButtonBox::setStandardButtons(NGLStandardButton::StandardButtons buttons) +{ + m_buttons = buttons; + + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + const QList actions = it.value()->actions(); + for (QAction *a : actions) + removeAction(a); + delete it.value(); + } + m_standardButtons.clear(); + + NGLStandardButton::StandardButton i = NGLStandardButton::FirstButton; + while (i <= NGLStandardButton::LastButton) + { + if ((m_buttons & i) == i) + { + NGLStandardButton *button = new NGLStandardButton(i); + addButtonInternal(button); + if (i == NGLStandardButton::Ok) + { + button->setDefault(true); + button->setAutoDefault(true); + } + } + i = (NGLStandardButton::StandardButton)((int) i << 1); + } + + init(); +} + +void NGLDialogButtonBox::addButtonInternal(NGLStandardButton *button) +{ + button->setParent(this); + button->setDefault(false); + button->setAutoDefault(false); + + m_standardButtons.insertMulti(button->layoutPriority(), button); +} + +void NGLDialogButtonBox::addButton(NGLStandardButton *button) +{ + addButtonInternal(button); + init(); +} + +NGLStandardButton *NGLDialogButtonBox::addButton(NGLStandardButton::StandardButton button) +{ + NGLStandardButton *pb = new NGLStandardButton(button); + addButton(pb); + return pb; +} + +NGLStandardButton *NGLDialogButtonBox::button(NGLStandardButton::StandardButton button) +{ + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + if (it.value()->type() == button) + return it.value(); + } + return new NGLStandardButton(nullptr); +} + +void NGLDialogButtonBox::removeFromActionList(NGLStandardButton::StandardButton button) +{ + m_disabledActions |= button; + init(); +} + +bool NGLDialogButtonBox::setEnabled(NGLStandardButton::StandardButton button, bool enable) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + b->setEnabled(enable); + return true; +} + +bool NGLDialogButtonBox::isEnabled(NGLStandardButton::StandardButton button) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + return b->isEnabled(); +} + +bool NGLDialogButtonBox::lineVisible() const +{ + return m_bLineVisible; +} + +void NGLDialogButtonBox::setLineVisible(bool bVisible) +{ + if (m_bLineVisible == bVisible) + return; + m_bLineVisible = bVisible; + init(); +} + +bool NGLDialogButtonBox::setVisible(NGLStandardButton::StandardButton button, bool visible) +{ + NGLStandardButton *b = this->button(button); + if (!b) + return false; + b->setVisible(visible); + return true; +} + +void NGLDialogButtonBox::layoutPriorityChanged() +{ + QMap standardButtons = m_standardButtons; + m_standardButtons.clear(); + QMap::const_iterator it = standardButtons.constBegin(); + QMap::const_iterator end = standardButtons.constEnd(); + for (; it != end; ++it) + { + NGLStandardButton *button = it.value(); + m_standardButtons.insertMulti(button->layoutPriority(), button); + } + + init(); +} + +static void addSpacer2(QLayout *l, Qt::Orientation orientation) +{ + if (orientation == Qt::Horizontal) + l->addItem(new QSpacerItem(20, 1, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); + else + l->addItem(new QSpacerItem(1, 20, QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); +} + +void NGLDialogButtonBox::init() +{ + delete layout(); + delete m_line; m_line = nullptr; + if (m_bSpacer2ContextAction) + { + removeAction(m_bSpacer2ContextAction); + delete m_bSpacer2ContextAction; + m_bSpacer2ContextAction = nullptr; + } + + QBoxLayout *l; + QBoxLayout *lMain; + if (m_orientation == Qt::Horizontal) + { + lMain = new QVBoxLayout; + l = new QHBoxLayout; + } + else + { + lMain = new QHBoxLayout; + l = new QVBoxLayout; + } + lMain->setMargin(0); + if (m_bLineVisible) + { + m_line = new QFrame(this); + m_line->setFrameShape(m_orientation == Qt::Horizontal ? QFrame::HLine : QFrame::VLine); + m_line->setFrameShadow(QFrame::Sunken); + lMain->addWidget(m_line); + } + lMain->addLayout(l); + l->setDirection(m_orientation == Qt::Horizontal ? QBoxLayout::RightToLeft : QBoxLayout::BottomToTop); + l->setContentsMargins(0, 0, 0, 0); + setLayout(lMain); + + const auto actions = findChildren(); + for (auto a : actions) + a->disconnect(a, &QAction::triggered, this, &NGLDialogButtonBox::buttonClicked); + + bool bLowestPrioButton = false; + bool bSpacer1Added = false; + bool bSpacer2Added = false; + QMap::const_iterator it = m_standardButtons.constBegin(); + QMap::const_iterator end = m_standardButtons.constEnd(); + for (; it != end; ++it) + { + qint32 prio = it.key(); + NGLStandardButton *button = it.value(); + + if (prio < 30) + bLowestPrioButton = true; + if (prio >= 30 && !bSpacer1Added) + { + bSpacer1Added = true; + if (bLowestPrioButton) + { + + QSpacerItem *item = new QSpacerItem(7, 7, QSizePolicy::Fixed, QSizePolicy::Fixed); + l->addItem(item); + } + } + if (prio >= 100 && !bSpacer2Added) + { + bSpacer2Added = true; + addSpacer2(l, m_orientation); + } + + if (prio >= 30 && prio < 100) + { + + const QList actions = button->actions(); + for (QAction *a : actions) + removeAction(a); + + if ((m_disabledActions & button->type()) == 0) + { + if (prio >= 100 && !m_bSpacer2ContextAction) + { + m_bSpacer2ContextAction = new QAction(this); + m_bSpacer2ContextAction->setSeparator(true); + addAction(m_bSpacer2ContextAction); + } + addActions(actions); + } + } + l->addWidget(button); + + if (button->type() == NGLStandardButton::Library) + { + QAction *ex = button->findChild(QLatin1String("actionExport")); + if (ex) + { + connect(ex, &QAction::triggered, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + QAction *im = button->findChild(QLatin1String("actionImport")); + if (im) + { + connect(im, &QAction::triggered, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + } + else + { + connect(button, &NGLStandardButton::clicked, + this, &NGLDialogButtonBox::buttonClicked, Qt::UniqueConnection); + } + } + if (!bSpacer2Added) + addSpacer2(l, m_orientation); + + QMapIterator mapIt(m_standardButtons); + NGLStandardButton *prevButton = nullptr; + mapIt.toBack(); + while (mapIt.hasPrevious()) + { + NGLStandardButton *curButton = mapIt.previous().value(); + if (prevButton != nullptr) + setTabOrder(prevButton, curButton); + prevButton = curButton; + } +} + +void NGLDialogButtonBox::buttonClicked() +{ + NGLStandardButton *b = qobject_cast (sender()); + if (!b) + { + QAction *a = qobject_cast (sender()); + if (!a) + return; + if (a->objectName() == QLatin1String("actionExport")) + { + emit onLibraryExport(); + return; + } + if (a->objectName() == QLatin1String("actionImport")) + { + emit onLibraryImport(); + return; + } + return; + } + switch (b->type()) + { + case NGLStandardButton::Ok: + emit onOk(); + break; + case NGLStandardButton::Send: + emit onSend(); + break; + case NGLStandardButton::New: + emit onNew(); + break; + case NGLStandardButton::Delete: + emit onDelete(); + break; + case NGLStandardButton::Save: + emit onSave(); + break; + case NGLStandardButton::Open: + emit onOpen(); + break; + case NGLStandardButton::Yes: + emit onYes(); + break; + case NGLStandardButton::No: + emit onNo(); + break; + case NGLStandardButton::Close: + emit onClose(); + break; + case NGLStandardButton::Cancel: + emit onCancel(); + break; + case NGLStandardButton::Help: + emit onHelp(); + break; + case NGLStandardButton::Apply: + emit onApply(); + break; + case NGLStandardButton::Reset: + emit onReset(); + break; + case NGLStandardButton::Print: + emit onPrint(); + break; + case NGLStandardButton::Modify: + emit onModify(); + break; + case NGLStandardButton::Add: + emit onAdd(); + break; + case NGLStandardButton::Remove: + emit onRemove(); + break; + case NGLStandardButton::Edit: + emit onEdit(); + break; + case NGLStandardButton::Download: + emit onDownload(); + break; + case NGLStandardButton::Library: + break; + case NGLStandardButton::Show: + emit onShow(); + break; + case NGLStandardButton::ZoomIn: + emit onZoomIn(); + break; + case NGLStandardButton::ZoomOut: + emit onZoomOut(); + break; + case NGLStandardButton::Hide: + emit onHide(); + break; + default: + emit clicked(b); + break; + } +} + +void NGLDialogButtonBox::enableImport(bool ena) +{ + NGLStandardButton *b = button(NGLStandardButton::Library); + if (!b) + return; + + QAction *im = b->findChild(QLatin1String("actionImport")); + if (im) + { + im->setEnabled(ena); + QAction *ex = b->findChild(QLatin1String("actionExport")); + if (ex) + b->setEnabled(ena || ex->isEnabled()); + } +} + +void NGLDialogButtonBox::enableExport(bool ena) +{ + NGLStandardButton *b = button(NGLStandardButton::Library); + if (!b) + return; + + QAction *ex = b->findChild(QLatin1String("actionExport")); + if (ex) + { + ex->setEnabled(ena); + QAction *im = b->findChild(QLatin1String("actionImport")); + if (im) + b->setEnabled(ena || im->isEnabled()); + } +} diff --git a/Z/src/nglwidgets/ngldialogbuttonbox.h b/Z/src/nglwidgets/ngldialogbuttonbox.h new file mode 100755 index 000000000..21b535f48 --- /dev/null +++ b/Z/src/nglwidgets/ngldialogbuttonbox.h @@ -0,0 +1,189 @@ +#pragma once + +#include +#include + +#include "nglwidgets_export.h" +#include "nglstandardbutton.h" + +class QFrame; + + +class NGLWIDGETS_EXPORT NGLDialogButtonBox : public QWidget +{ + Q_OBJECT + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + Q_PROPERTY(NGLStandardButton::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons) + Q_PROPERTY(bool m_bLineVisible READ lineVisible WRITE setLineVisible) + +public: + + + explicit NGLDialogButtonBox(QWidget *parent = nullptr); + + + explicit NGLDialogButtonBox(Qt::Orientation orientation, QWidget *parent = nullptr); + + + NGLDialogButtonBox(NGLStandardButton::StandardButtons buttons, Qt::Orientation orientation = Qt::Horizontal, QWidget *parent = nullptr); + + + + Qt::Orientation orientation() const; + + + void setOrientation(Qt::Orientation orientation); + + + + NGLStandardButton::StandardButtons standardButtons() const; + + + void setStandardButtons(NGLStandardButton::StandardButtons buttons); + + + + void addButton(NGLStandardButton *button); + + + NGLStandardButton *addButton(NGLStandardButton::StandardButton button); + + + + NGLStandardButton *button(NGLStandardButton::StandardButton button); + + + + void removeFromActionList(NGLStandardButton::StandardButton button); + + + + bool setEnabled(NGLStandardButton::StandardButton button, bool enable); + + + + bool isEnabled(NGLStandardButton::StandardButton button); + + + + bool lineVisible() const; + + + + void setLineVisible(bool bVisible); + + + + bool setVisible(NGLStandardButton::StandardButton button, bool visible); + + + + void setVisible(bool visible) { QWidget::setVisible(visible); } + + + + void enableExport(bool ena); + + + + void enableImport(bool ena); + +public Q_SLOTS: + + + void layoutPriorityChanged(); +Q_SIGNALS: + + + void clicked(NGLStandardButton *button); + + + void onOk(); + + + void onSend(); + + + void onNew(); + + + void onDelete(); + + + void onSave(); + + + void onOpen(); + + + void onYes(); + + + void onNo(); + + + void onClose(); + + + void onCancel(); + + + void onHelp(); + + + void onApply(); + + + void onReset(); + + + void onPrint(); + + + void onModify(); + + + void onAdd(); + + + void onRemove(); + + + void onEdit(); + + + void onDownload(); + + + + void onLibraryImport(); + + + + void onLibraryExport(); + + void onShow(); + void onZoomIn(); + void onZoomOut(); + + + void onHide(); + +protected: + void init(); + void addButtonInternal(NGLStandardButton *button); + +protected Q_SLOTS: + void buttonClicked(); + +protected: + QMap m_standardButtons; + Qt::Orientation m_orientation; + NGLStandardButton::StandardButtons m_buttons; + NGLStandardButton::StandardButtons m_disabledActions; + QFrame *m_line; + QAction *m_bSpacer2ContextAction; + bool m_bLineVisible; +}; + + diff --git a/Z/src/nglwidgets/nglmainwindow.cpp b/Z/src/nglwidgets/nglmainwindow.cpp new file mode 100755 index 000000000..5d3337e3f --- /dev/null +++ b/Z/src/nglwidgets/nglmainwindow.cpp @@ -0,0 +1,107 @@ + + + +#include "nglmainwindow.h" + +#include +#include +#include +#include +#include +#include +#include + +NGLMainWindow::NGLMainWindow(QWidget *parent) + : QMainWindow(parent) + , m_helpProcess(nullptr) + , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("NGLMainWindow")) + , m_versionView(nullptr) + , m_menuBar(new QMenuBar(this)) +{ + m_menu[QLatin1String("File")] = m_menuBar->addMenu(tr("File")); + m_fileActionBefore = m_menu[QLatin1String("File")]->addSeparator(); + m_menu[QLatin1String("File")]->addAction(QIcon(QLatin1String(":/icons/16x16/application-exit.png")), tr("Quit"), + this, &NGLMainWindow::onExit, QKeySequence(tr("Ctrl+q"))); + + m_menu[QLatin1String("Help")] = m_menuBar->addMenu(tr("Help")); + m_menu[QLatin1String("Help")]->addAction(QIcon(QLatin1String(":/icons/16x16/help-contents.png")), + tr("Help"), this, &NGLMainWindow::onHelpIndex, QKeySequence(tr("F1"))); + m_menu[QLatin1String("Help")]->addSeparator(); + m_menu[QLatin1String("Help")]->addAction(QIcon(QLatin1String(":/icons/16x16/help-about.png")), + tr("About"), this, &NGLMainWindow::onHelpAbout); + + setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); + setMenuBar(m_menuBar); +} + +void NGLMainWindow::onExit() +{ + + close(); +} + +void NGLMainWindow::onHelpIndex() +{ + onInvokeHelp(QLatin1String("Index")); +} + +void NGLMainWindow::onInvokeHelp(const QString &helpContext) +{ + + DEBUG_LOG(m_logger) << "onInvokeHelp " << helpContext ; + + if (!m_helpProcess) + { + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString lang = QString::fromLatin1(NGL::translationLocale()) + QLatin1String(".UTF-8"); + env.insert(QLatin1String("LANG"), lang); + m_helpProcess = new QProcess(this); + m_helpProcess->setProcessEnvironment(env); + QStringList args; + QString fn = QString::fromLatin1(NGL::translationLocale()) + QLatin1String(".qhc"); + args << QLatin1String("-collectionFile") + << QCoreApplication::applicationDirPath() + QLatin1String("/../help/scms/") + fn + << QLatin1String("-enableRemoteControl"); + DEBUG_LOG(m_logger) << "Attempting to invoke help at URL: " << args.join(QLatin1String(" ")) ; + m_helpProcess->start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/assistant"), args); + if (!m_helpProcess->waitForStarted()) + { + ERROR_LOG(m_logger) << "Could not start help browser (error: " + << m_helpProcess->error() + << " )" ; + delete m_helpProcess; + m_helpProcess = nullptr; + return; + } + connect(m_helpProcess, QOverload::of(&QProcess::finished), + this, &NGLMainWindow::onHelpFinished); + } + QTextStream str(m_helpProcess); + + str << QLatin1String("activateIdentifier ") + helpContext << QLatin1Char('\0') << endl; +} + +void NGLMainWindow::onHelpFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus != QProcess::NormalExit) + { + WARNING_LOG(m_logger) << "help browser exited with status " + << exitStatus << " code " + << exitCode << "!" ; + } + delete m_helpProcess; + m_helpProcess = nullptr; +} + +void NGLMainWindow::onHelpAbout() +{ + if (m_versionView) + m_versionView->show(); +} + +void NGLMainWindow::onVersionViewDeleted() +{ + m_versionView = nullptr; + setVersionView(); +} diff --git a/Z/src/nglwidgets/nglmainwindow.h b/Z/src/nglwidgets/nglmainwindow.h new file mode 100755 index 000000000..39bec5aa4 --- /dev/null +++ b/Z/src/nglwidgets/nglmainwindow.h @@ -0,0 +1,46 @@ + + + +#pragma once + +#include +#include +#include +#include "nglwidgets_export.h" + +namespace NGL +{ +class INGLLogger; +} + +class NGLWIDGETS_EXPORT NGLMainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit NGLMainWindow(QWidget *parent = nullptr); + + virtual void setVersionView() = 0; + +public slots: + + void onHelpIndex(); + void onHelpAbout(); + void onInvokeHelp(const QString &); + void onHelpFinished(int exitCode, QProcess::ExitStatus exitStatus); + +private: + QProcess *m_helpProcess; + +protected: + NGL::INGLLogger &m_logger; + QWidget *m_versionView; + QMenuBar *m_menuBar; + QMap m_menu; + QAction *m_fileActionBefore; + +protected slots: + void onVersionViewDeleted(); + void onExit(); + +}; + diff --git a/Z/src/nglwidgets/nglpdfdocument.cpp b/Z/src/nglwidgets/nglpdfdocument.cpp new file mode 100755 index 000000000..8f0854878 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfdocument.cpp @@ -0,0 +1,332 @@ +#include "nglpdfdocument.h" +#include "nglpdfpage.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace NGL +{ +PDFDocument::PDFDocument(QWidget *parent) + : QWidget(parent) + , m_doc(nullptr) + , m_currentPage(0) + , m_maxCachedPages(20) + , m_scaleFactor(1.0) + , m_widthFactor(1.0) + , m_rotation(Poppler::Page::Rotate0) +{ + QVBoxLayout *lay = new QVBoxLayout(this); + lay->setMargin(0); + lay->setSpacing(0); + + m_pdfLabel = new QWidget(this); + m_pdfLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + QVBoxLayout *l = new QVBoxLayout(m_pdfLabel); + l->setMargin(l->margin() * 2); + l->setSpacing(l->margin()); + l->setSizeConstraint(QLayout::SetFixedSize); + + m_scrollArea = new QScrollArea(this); + m_scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + + m_scrollArea->setWidgetResizable(true); + m_scrollArea->setWidget(m_pdfLabel); + + lay->addWidget(m_scrollArea); +} + +PDFDocument::~PDFDocument() +{ + qDeleteAll(m_pages); + m_pages.clear(); + delete m_doc; +} + +bool PDFDocument::showPDF(const QUrl &url) +{ + return showPDF(url.toLocalFile()); +} + +bool PDFDocument::showPDF(const QString &path) +{ + if (path.isEmpty()) + return false; + + if (path == m_currentPath) + { + m_scaleFactor = 0; + m_widthFactor = 1; + setZoomFactor(1.0); + setRotation(Poppler::Page::Rotate0); + return true; + } + + delete m_doc; + m_doc = Poppler::Document::load(path); + if (!m_doc) + return false; + m_currentPath = path; + + return showPDFInternal(); +} + +bool PDFDocument::showPDF(const QByteArray &pdf) +{ + m_currentPath.clear(); + + delete m_doc; + m_doc = Poppler::Document::loadFromData(pdf); + if (!m_doc) + return false; + + return showPDFInternal(); +} + +bool PDFDocument::showPDFInternal() +{ + disconnect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, &PDFDocument::onVSliderValueChanged); + + m_doc->setRenderHint(Poppler::Document::Antialiasing); + m_doc->setRenderHint(Poppler::Document::TextAntialiasing); + m_doc->setRenderHint(Poppler::Document::TextHinting); + m_doc->setRenderHint(Poppler::Document::TextSlightHinting); + + m_scrollArea->horizontalScrollBar()->setSliderPosition(0); + m_scrollArea->verticalScrollBar()->setSliderPosition(0); + + m_renderedPages.clear(); + qDeleteAll(m_pages); + m_pages.clear(); + m_ranges.clear(); + + QVBoxLayout *l = qobject_cast (m_pdfLabel->layout()); + const int cnt = m_doc->numPages(); + m_pages.reserve(cnt); + for (int i = 0; i < cnt; ++i) + { + PDFPage *p = new PDFPage(m_pdfLabel); + p->setZoomFactor(m_scaleFactor); + p->setRotation(m_rotation); + p->setPopplerPage(m_doc->page(i)); + connect(p, &PDFPage::pageRendered, + this, &PDFDocument::onPageRendered); + connect(p, &PDFPage::externalLinkClicked, + this, &PDFDocument::linkClicked); + connect(p, &PDFPage::linkClicked, + this, &PDFDocument::onLinkClicked); + m_pages += p; + + l->addWidget(p); + } + rebuildRanges(); + + m_currentPage = std::min(m_currentPage, m_ranges.count() - 1); + + ensureCurPageVisible(); + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + connect(m_scrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, &PDFDocument::onVSliderValueChanged); + return true; +} + +void PDFDocument::resizePdfToWidth() +{ + double scale = m_scaleFactor; + + m_widthFactor = double(m_pdfLabel->size().width()) / size().width() * 1.03; + + m_scaleFactor = 0; + setZoomFactor(scale); +} + +int PDFDocument::curPage() const +{ + return m_currentPage + 1; +} + +int PDFDocument::numPages() const +{ + return m_doc ? m_doc->numPages() : -1; +} + +void PDFDocument::setZoomFactor(double zoom) +{ + if (qFuzzyCompare(m_scaleFactor, zoom)) + return; + m_scaleFactor = zoom; + + for (PDFPage *p : qAsConst(m_pages)) + p->setZoomFactor(m_scaleFactor / m_widthFactor); + + rebuildRanges(); +} + +void PDFDocument::setRotation(Poppler::Page::Rotation rot) +{ + if (m_rotation == rot) + return; + m_rotation = rot; + if (m_pages.isEmpty()) + return; + + for (PDFPage *p : qAsConst(m_pages)) + p->setRotation(m_rotation); + + rebuildRanges(); + emit currentPageChanged(m_currentPage+1, m_ranges.count()); + emit rotationChanged(m_rotation); +} + +bool PDFDocument::setPage(int page) +{ + page--; + if (m_currentPage == page) + { + ensureCurPageVisible(); + return true; + } + if (m_pages.isEmpty()) + { + m_currentPage = page; + return true; + } + if (page < 0 || numPages() < 0 || page >= m_doc->numPages()) + return false; + + m_currentPage = page; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +bool PDFDocument::nextPage() +{ + if (m_doc == nullptr || m_currentPage >= m_doc->numPages() - 1) + return false; + m_currentPage++; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +bool PDFDocument::previousPage() +{ + if (m_doc == nullptr || m_currentPage < 1) + return false; + m_currentPage--; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(); + return true; +} + +void PDFDocument::onVSliderValueChanged(int y) +{ + + y += m_scrollArea->height() / 2; + int curPage = m_ranges.count() - 1; + for (int i = 0; i < m_ranges.count(); ++i) + { + if (m_ranges.at(i) > y) + { + curPage = i - 1; + break; + } + } + if (curPage != m_currentPage && curPage >= 0) + { + m_currentPage = curPage; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + } +} + +void PDFDocument::onPageRendered() +{ + PDFPage *p = qobject_cast (sender()); + if (m_renderedPages.contains(p)) + return; + + while (m_renderedPages.count() > m_maxCachedPages - 1) + { + p = m_renderedPages.takeFirst(); + if (p) + p->clearPixmap(); + } + m_renderedPages.push_back(p); +} + +void PDFDocument::onLinkClicked(const Poppler::LinkDestination &dest) +{ + PDFPage *p = qobject_cast(sender()); + if (!p) + return; + m_currentPage = dest.pageNumber() - 1; + emit currentPageChanged(m_currentPage + 1, m_ranges.count()); + ensureCurPageVisible(qRound(dest.right() * p->width()), + qRound(dest.top() * p->height())); +} + +QVector PDFDocument::getPrintableImages(int resolution) const +{ + QVector imageList; + imageList.reserve(m_pages.size()); + for (const PDFPage *p : m_pages) + imageList.append(p->getPrintableImage(resolution)); + return imageList; +} + +QImage PDFDocument::getPrintableImage(int pageNum, int resolution) const +{ + if (pageNum < 0 || pageNum >= m_pages.size()) + return QImage(); + return m_pages[pageNum]->getPrintableImage(resolution); +} + +void PDFDocument::ensureCurPageVisible(int xOfs, int yOfs) +{ + if (m_currentPage >= m_ranges.size() || m_currentPage < 0) + return; + + + + if (m_scrollArea->verticalScrollBar()->maximum() == 0) + { + QTimer::singleShot(50, this, [this, xOfs, yOfs]() { ensureCurPageVisible(xOfs, yOfs); }); + return; + } + + + + int y = m_ranges.at(m_currentPage) + yOfs; + + y -= m_pdfLabel->layout()->spacing() * 2; + + int x = m_scrollArea->horizontalScrollBar()->value() + xOfs; + + + m_scrollArea->ensureVisible(x, y, 0, 0); + y += m_scrollArea->height(); + + m_scrollArea->ensureVisible(x, y, 0, 0); +} + +void PDFDocument::rebuildRanges() +{ + QVBoxLayout *l = qobject_cast (m_pdfLabel->layout()); + m_ranges.clear(); + int height = l->contentsMargins().top(); + for (PDFPage *p : qAsConst(m_pages)) + { + m_ranges += height; + height += p->height(); + height += l->spacing(); + } + m_pdfLabel->resize(m_pdfLabel->sizeHint()); + m_pdfLabel->setMinimumSize(m_pdfLabel->sizeHint()); +} + +} diff --git a/Z/src/nglwidgets/nglpdfdocument.h b/Z/src/nglwidgets/nglpdfdocument.h new file mode 100755 index 000000000..827804e94 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfdocument.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "nglwidgets_export.h" + +namespace Poppler +{ +class Document; +class LinkDestination; +} +class QUrl; +class QScrollArea; +namespace NGL +{ +class PDFPage; + + +class NGLWIDGETS_EXPORT PDFDocument : public QWidget +{ + Q_OBJECT +public: + + + explicit PDFDocument(QWidget *parent = nullptr); + + + virtual ~PDFDocument(); + + + + int curPage() const; + + + int numPages() const; + +public Q_SLOTS: + + + bool showPDF(const QString &path); + + + + bool showPDF(const QUrl &url); + + + + bool showPDF(const QByteArray &pdf); + + + + void setZoomFactor(double zoom); + + void setRotation(Poppler::Page::Rotation rot); + + + + bool setPage(int page); + + + bool nextPage(); + + + bool previousPage(); + + void resizePdfToWidth(); + +public: + Poppler::Page::Rotation getRotation() const { return m_rotation; } + + + + QVector getPrintableImages(int resolution = 300) const; + + + + QImage getPrintableImage(int pageNum, int resolution = 300) const; + +Q_SIGNALS: + + + void currentPageChanged(int cur, int max); + + + void rotationChanged(Poppler::Page::Rotation rot); + + + void linkClicked(const QString &url); + +protected Q_SLOTS: + void onVSliderValueChanged(int y); + void onPageRendered(); + void onLinkClicked(const Poppler::LinkDestination &dest); + +protected: + bool showPDFInternal(); + void ensureCurPageVisible(int xOfs = 0, int yOfs = 0); + void rebuildRanges(); + + Poppler::Document *m_doc; + int m_currentPage; + int m_maxCachedPages; + double m_scaleFactor; + double m_widthFactor; + QString m_currentPath; + + QWidget *m_pdfLabel; + QScrollArea *m_scrollArea; + QVector m_pages; + QVector m_ranges; + QVector > m_renderedPages; + Poppler::Page::Rotation m_rotation; +}; +} diff --git a/Z/src/nglwidgets/nglpdfpage.cpp b/Z/src/nglwidgets/nglpdfpage.cpp new file mode 100755 index 000000000..8c25eb453 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfpage.cpp @@ -0,0 +1,203 @@ +#include "nglpdfpage.h" + +#include +#include +#include +#include +#include + +namespace NGL +{ +template +static inline T getRotatedSize(const T &in, Poppler::Page::Rotation rot) +{ + switch (rot) + { + case Poppler::Page::Rotate0: + case Poppler::Page::Rotate180: + return in; + case Poppler::Page::Rotate90: + case Poppler::Page::Rotate270: + return in.transposed(); + } + Q_ASSERT(false); + return in; +} + +PDFPage::PDFPage(QWidget *parent) + : QWidget(parent) + , m_page(nullptr) + , m_scaleFactor(1.0) + , m_rotation(Poppler::Page::Rotate0) +{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setMouseTracking(true); +} + +PDFPage::~PDFPage() +{ + delete m_page; +} + +void PDFPage::setPopplerPage(Poppler::Page *page) +{ + if (m_page == page) + return; + delete m_page; + m_page = page; + m_links.clear(); + m_linkRects.clear(); + if (!m_page) + return; + + const QList links = m_page->links(); + for (const auto link : links) + { + if (link->linkType() == Poppler::Link::Browse || + link->linkType() == Poppler::Link::Goto) + m_links += link; + else + std::cerr << "linktype: " << link->linkType() << std::endl; + } + + rebuildInternalData(); +} + +void PDFPage::setZoomFactor(double zoom) +{ + if (qFuzzyCompare(m_scaleFactor, zoom)) + return; + m_scaleFactor = zoom; + rebuildInternalData(); +} + +void PDFPage::setRotation(Poppler::Page::Rotation rot) +{ + if (m_rotation == rot) + return; + m_rotation = rot; + rebuildInternalData(); +} + +void PDFPage::clearPixmap() +{ + m_pdfPixmap = QPixmap(); +} + +QImage PDFPage::getPrintableImage(int resolution) const +{ + if (!m_page) + return QImage(); + + + Poppler::Page::Rotation rot = Poppler::Page::Rotate0; + + if (m_page->orientation() == Poppler::Page::Landscape) + rot = Poppler::Page::Rotate270; + else if (m_page->orientation() == Poppler::Page::Seascape) + rot = Poppler::Page::Rotate90; + else if (m_page->orientation() == Poppler::Page::UpsideDown) + rot = Poppler::Page::Rotate180; + Q_UNUSED(rot) + + + return m_page->renderToImage(resolution, resolution, -1, -1, -1, -1, m_rotation); +} + +QSize PDFPage::sizeHint() const +{ + if (!m_page) + return QSize(); + return getRotatedSize(m_page->pageSize(), m_rotation); +} + +void PDFPage::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + if (!m_page) + return; + if (m_pdfPixmap.isNull()) + { + const QImage img = m_page->renderToImage(m_scaleFactor * 72, m_scaleFactor * 72, -1, -1, -1, -1, m_rotation); + m_pdfPixmap = QPixmap::fromImage(img); + emit pageRendered(); + } + QPainter p(this); + p.drawPixmap(0, 0, m_pdfPixmap); + p.end(); +} + +void PDFPage::mouseMoveEvent(QMouseEvent *event) +{ + const QPointF pos = event->localPos(); + for (const auto &linkRect : qAsConst(m_linkRects)) + { + if (linkRect.contains(pos)) + { + setCursor(Qt::PointingHandCursor); + return; + } + } + setCursor(Qt::ArrowCursor); + QWidget::mouseMoveEvent(event); +} + +void PDFPage::mouseReleaseEvent(QMouseEvent *event) +{ + const QPointF pos = event->localPos(); + for (int i = 0; i < m_linkRects.size(); ++i) + { + if (m_linkRects.at(i).contains(pos)) + { + const auto *link = m_links.at(i); + if (link->linkType() == Poppler::Link::Browse) + { + const Poppler::LinkBrowse *linkBrowse = static_cast(link); + emit externalLinkClicked(linkBrowse->url()); + return; + } + else if (link->linkType() == Poppler::Link::Goto) + { + const Poppler::LinkGoto *linkGoto = static_cast(link); + if (linkGoto->isExternal()) + { + const QUrl url = QUrl::fromLocalFile(linkGoto->fileName()); + emit externalLinkClicked(url.toString()); + return; + } + emit linkClicked(linkGoto->destination()); + return; + } + } + } + QWidget::mouseReleaseEvent(event); +} + +void PDFPage::rebuildInternalData() +{ + clearPixmap(); + + if (!m_page) + return; + + const QSizeF s(rotatedPageSize()); + const int w = qRound(s.width() * m_scaleFactor); + const int h = qRound(s.height() * m_scaleFactor); + setMinimumSize(w, h); + resize(sizeHint()); + + + m_linkRects.clear(); + m_linkRects.reserve(m_links.size()); + for (const auto link : qAsConst(m_links)) + { + const QRectF r = link->linkArea(); + m_linkRects += QRectF(r.x() * w, r.y() * h, r.width() * w, r.height() * h); + } +} + +QSizeF PDFPage::rotatedPageSize() const +{ + return m_page ? getRotatedSize(m_page->pageSizeF(), m_rotation) : QSizeF(); +} +} diff --git a/Z/src/nglwidgets/nglpdfpage.h b/Z/src/nglwidgets/nglpdfpage.h new file mode 100755 index 000000000..be39dbf77 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfpage.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Poppler +{ +class Page; +class Link; +class LinkDestination; +} + +namespace NGL +{ + + +class PDFPage final : public QWidget +{ + Q_OBJECT +public: + explicit PDFPage(QWidget *parent = nullptr); + virtual ~PDFPage(); + + void setPopplerPage(Poppler::Page *page); + void setZoomFactor(double zoom); + void setRotation(Poppler::Page::Rotation rot); + void clearPixmap(); + QImage getPrintableImage(int resolution = 300) const; + QSize sizeHint() const override; +Q_SIGNALS: + void pageRendered(); + + void externalLinkClicked(const QString &url); + + void linkClicked(const Poppler::LinkDestination &dest); +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; +private: + void rebuildInternalData(); + QSizeF rotatedPageSize() const; +protected: + Poppler::Page *m_page; + double m_scaleFactor; + QPixmap m_pdfPixmap; + QList< Poppler::Link * > m_links; + QList< QRectF > m_linkRects; + Poppler::Page::Rotation m_rotation; +}; +} diff --git a/Z/src/nglwidgets/nglpdfwidget.cpp b/Z/src/nglwidgets/nglpdfwidget.cpp new file mode 100755 index 000000000..0f13d721a --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.cpp @@ -0,0 +1,151 @@ + + +#include "nglpdfwidget.h" +#include "ui_nglpdfwidget.h" + +static const double s_maxZoom = 3.0; +static const double s_minZoom = 1.0; + +namespace NGL +{ +PDFWidget::PDFWidget(QWidget *parent) + : QWidget(parent) + , m_zoomFactor(1.0) + , ui(new Ui::pdfWidget) +{ + ui->setupUi(this); + ui->zoomFull->setVisible(false); + ui->zoom100->setVisible(false); + ui->pageLabel->setAutoFillBackground(true); + + connect(ui->previousPage, &QToolButton::clicked, ui->pdfDocument, &PDFDocument::previousPage); + connect(ui->nextPage, &QToolButton::clicked, ui->pdfDocument, &PDFDocument::nextPage); + connect(ui->zoom100, &QToolButton::clicked, this, &PDFWidget::onZoomDefault); + connect(ui->zoomMinus, &QToolButton::clicked, this, &PDFWidget::onZoomMinus); + connect(ui->zoomPlus, &QToolButton::clicked, this, &PDFWidget::onZoomPlus); + connect(ui->zoomFull, &QToolButton::clicked, this, &PDFWidget::onZoomFull); + + + connect(ui->pdfDocument, &PDFDocument::currentPageChanged, this, &PDFWidget::pageChanged); + connect(ui->rotateDoc, &QToolButton::clicked, this, &PDFWidget::rotate); + connect(ui->pdfDocument, &PDFDocument::currentPageChanged, this, &PDFWidget::currentPageChanged); + connect(ui->pdfDocument, &PDFDocument::rotationChanged, this, &PDFWidget::rotationChanged); +} + +PDFWidget::~PDFWidget() +{ + delete ui; +} + +bool PDFWidget::showPDF(const QUrl &pdf) +{ + return ui->pdfDocument->showPDF(pdf); +} + +bool PDFWidget::showPDF(const QByteArray &pdf) +{ + return ui->pdfDocument->showPDF(pdf); +} + +void PDFWidget::setZoomFactor(double newZoomFactor) +{ + m_zoomFactor = newZoomFactor; + ui->pdfDocument->setZoomFactor(newZoomFactor); +} + +void PDFWidget::setRotation(Poppler::Page::Rotation rot) +{ + ui->pdfDocument->setRotation(rot); +} + +bool PDFWidget::setPage(int newPage) +{ + return ui->pdfDocument->setPage(newPage); +} + +int PDFWidget::numPages() const +{ + return ui->pdfDocument->numPages(); +} + +int PDFWidget::curPage() const +{ + return ui->pdfDocument->curPage(); +} + +QVector PDFWidget::getPrintableImages(int resolution) const +{ + return ui->pdfDocument->getPrintableImages(resolution); +} + +void PDFWidget::resizePdfToWidth() +{ + ui->pdfDocument->resizePdfToWidth(); +} + +void PDFWidget::pageChanged(int cur, int max) +{ + if (cur < 1) + { + ui->pdfDocument->setPage(1); + return; + } + ui->pageLabel->setText(tr("Page %1 of %2").arg(cur).arg(max)); + ui->nextPage->setEnabled(cur < max); + ui->previousPage->setEnabled(cur > 1); +} + +void PDFWidget::rotate() +{ + Poppler::Page::Rotation rot0 = ui->pdfDocument->getRotation(); + Poppler::Page::Rotation rot1 = rot0; + switch (rot0) + { + case Poppler::Page::Rotate0: + rot1 = Poppler::Page::Rotate90; + break; + case Poppler::Page::Rotate90: + rot1 = Poppler::Page::Rotate180; + break; + case Poppler::Page::Rotate180: + rot1 = Poppler::Page::Rotate270; + break; + case Poppler::Page::Rotate270: + rot1 = Poppler::Page::Rotate0; + break; + } + ui->pdfDocument->setRotation(rot1); +} + +void PDFWidget::onZoomDefault() +{ + ui->pdfDocument->setZoomFactor(1.0); + m_zoomFactor = 1.0; +} +void PDFWidget::onZoomFull() +{ + ui->pdfDocument->resizePdfToWidth(); + m_zoomFactor = 1.0; +} + + +void PDFWidget::onZoomMinus() +{ + if (m_zoomFactor > s_minZoom) + m_zoomFactor -= 0.20; + if (m_zoomFactor < s_minZoom) + m_zoomFactor = s_minZoom; + ui->pdfDocument->setZoomFactor(m_zoomFactor); +} + +void PDFWidget::onZoomPlus() +{ + if (m_zoomFactor < s_maxZoom) + m_zoomFactor += 0.20; + if(m_zoomFactor > s_maxZoom) + m_zoomFactor = s_maxZoom; + ui->pdfDocument->setZoomFactor(m_zoomFactor); + +} + +} diff --git a/Z/src/nglwidgets/nglpdfwidget.h b/Z/src/nglwidgets/nglpdfwidget.h new file mode 100755 index 000000000..16aca38ff --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.h @@ -0,0 +1,48 @@ + + +#pragma once +#include +#include + +#include "nglwidgets_export.h" + +class QUrl; +namespace Ui +{ +class pdfWidget; +} + +namespace NGL +{ +class NGLWIDGETS_EXPORT PDFWidget : public QWidget +{ + Q_OBJECT +public: + explicit PDFWidget(QWidget *parent = nullptr); + ~PDFWidget(); + + bool showPDF(const QUrl &pdf); + bool showPDF(const QByteArray &pdf); + void setZoomFactor(double newZoomFactor); + void setRotation(Poppler::Page::Rotation rot); + bool setPage(int newPage); + QVector getPrintableImages(int resolution = 300) const; + void resizePdfToWidth(); + int numPages() const; + int curPage() const; + +Q_SIGNALS: + void currentPageChanged(int cur, int max); + void rotationChanged(Poppler::Page::Rotation newRotation); +protected Q_SLOTS: + void pageChanged(int cur, int max); + void rotate(); + void onZoomDefault(); + void onZoomFull(); + void onZoomMinus(); + void onZoomPlus(); +protected: + double m_zoomFactor; + Ui::pdfWidget *ui; +}; +} diff --git a/Z/src/nglwidgets/nglpdfwidget.ui b/Z/src/nglwidgets/nglpdfwidget.ui new file mode 100755 index 000000000..ad7119619 --- /dev/null +++ b/Z/src/nglwidgets/nglpdfwidget.ui @@ -0,0 +1,253 @@ + + + pdfWidget + + + + 0 + 0 + 580 + 396 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 202 + 20 + + + + + + + + Qt::Horizontal + + + + 201 + 20 + + + + + + + + + + + 0 + 30 + + + + + + + + :/style/media-seek-backward.svg:/style/media-seek-backward.svg + + + Ctrl+P + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + - + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 0 + 30 + + + + + + + + :/style/media-seek-forward.svg:/style/media-seek-forward.svg + + + + 16 + 16 + + + + Ctrl+N + + + + + + + + + + + :/style/restart.svg:/style/restart.svg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - + + + + :/icons/16x16/zoom-out.png:/icons/16x16/zoom-out.png + + + + + + + + 0 + 0 + + + + + 16777215 + 32 + + + + 1:1 + + + + + + + ... + + + + :/icons/16x16/view-fullscreen.png:/icons/16x16/view-fullscreen.png + + + + + + + + + + + + :/icons/16x16/zoom-in.png:/icons/16x16/zoom-in.png + + + + + + + + + + NGL::PDFDocument + QWidget +
nglwidgets/nglpdfdocument.h
+ 1 +
+
+ + + + + + + +
diff --git a/Z/src/nglwidgets/nglresources.qrc b/Z/src/nglwidgets/nglresources.qrc new file mode 100755 index 000000000..57fe99851 --- /dev/null +++ b/Z/src/nglwidgets/nglresources.qrc @@ -0,0 +1,669 @@ + + + icons/32x32/hand_grenade_locations.png + icons/svg/switch_display_disabled.svg + icons/svg/switch_display.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/announcement_menu_disabled.svg + icons/svg/announcement_menu.svg + icons/svg/mortar_ammunition_firings_disabled.svg + icons/svg/mortar_ammunition_firings.svg + icons/svg/mortar_ammunition_administration_disabled.svg + icons/svg/mortar_ammunition_administration.svg + icons/svg/arrow_back_disabled.svg + icons/svg/arrow_back.svg + icons/svg/filter_barriers_disabled.svg + icons/svg/filter_barriers.svg + icons/svg/chemical_agents_disabled.svg + icons/svg/chemical_agents.svg + icons/svg/define_border_lines_disabled.svg + icons/svg/define_border_lines.svg + icons/svg/filter_collapse_expand_disabled.svg + icons/svg/filter_collapse_expand.svg + icons/svg/create_distance_measure_disabled.svg + icons/svg/create_distance_measure.svg + icons/svg/show_distance_measure_disabled.svg + icons/svg/show_distance_measure.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/configure_buildings_disabled.svg + icons/svg/configure_buildings.svg + icons/svg/edit-cut.svg + icons/svg/evaluation_elements_disabled.svg + icons/svg/evaluation_elements.svg + icons/svg/electronical_warfare_measures_disabled.svg + icons/svg/electronical_warfare_measures.svg + icons/svg/define_training_cycles_disabled.svg + icons/svg/define_training_cycles.svg + icons/svg/select_training_cylces_disabled.svg + icons/svg/select_training_cylces.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/exercise_purpose_disabled.svg + icons/svg/exercise_purpose.svg + icons/svg/set_exercise_process_disabled.svg + icons/svg/set_exercise_process.svg + icons/svg/export_documents_disabled.svg + icons/svg/export_documents.svg + icons/svg/filter_border_lines_disabled.svg + icons/svg/filter_border_lines.svg + icons/svg/filter_firings_disabled.svg + icons/svg/filter_firings.svg + icons/svg/load_global_filter_disabled.svg + icons/svg/load_global_filter.svg + icons/svg/filter_player_disabled.svg + icons/svg/filter_player.svg + icons/svg/filter_teams_disabled.svg + icons/svg/filter_teams.svg + icons/svg/force_composition_disabled.svg + icons/svg/force_composition.svg + icons/svg/exercise_force_disabled.svg + icons/svg/exercise_force.svg + icons/svg/force_organization_disabled.svg + icons/svg/force_organization.svg + icons/svg/force_player_configuration_disabled.svg + icons/svg/force_player_configuration.svg + icons/svg/freq_plan.svg + icons/svg/config_gobal_alarms_disabled.svg + icons/svg/global_alarms_history_disabled.svg + icons/svg/global_alarms_history.svg + icons/svg/config_gobal_alarms.svg + icons/svg/global_exercise_settings_disabled.svg + icons/svg/global_exercise_settings.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/import_documents_disabled.svg + icons/svg/import_documents.svg + icons/svg/import_pdf_document_disabled.svg + icons/svg/import_pdf_document.svg + icons/svg/import_images_disabled.svg + icons/svg/import_images.svg + icons/svg/organize_library_disabled.svg + icons/svg/organize_library.svg + icons/svg/default_operator_rights_disabled.svg + icons/svg/default_operator_rights.svg + icons/svg/define_tactical_symbols_disabled.svg + icons/svg/define_tactical_symbols.svg + icons/svg/define_force_templates_disabled.svg + icons/svg/define_force_templates.svg + icons/svg/configure_line_of_sight_disabled.svg + icons/svg/configure_line_of_sight.svg + icons/svg/show_line_of_sight_disabled.svg + icons/svg/show_line_of_sight.svg + icons/svg/configure_line_of_sight_disabled.svg + icons/svg/configure_line_of_sight.svg + icons/svg/map_context_menu_disabled.svg + icons/svg/map_context_menu.svg + icons/svg/marker-end.svg + icons/svg/edit_evaluation_marker_disabled.svg + icons/svg/edit_evaluation_marker.svg + icons/svg/metereological_data_disabled.svg + icons/svg/metereological_data.svg + icons/svg/mine_barrier_corridor_disabled.svg + icons/svg/mine_barrier_corridor.svg + icons/svg/mine_barriers_disabled.svg + icons/svg/mine_barriers.svg + icons/svg/define_movement_simulation_disabled.svg + icons/svg/define_movement_simulation.svg + icons/svg/filter_nc_agents_disabled.svg + icons/svg/filter_nbc_agents.svg + icons/svg/oc_aar_preparation_disabled.svg + icons/svg/oc_aar_preparation.svg + icons/svg/oc_evaluation_schemes_disabled.svg + icons/svg/oc_evaluation_schemes.svg + icons/svg/display_oc_evaluations_disabled.svg + icons/svg/display_oc_evaluations.svg + icons/svg/oc_player_configuration_disabled.svg + icons/svg/oc_player_configuration.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/operator_administration_disabled.svg + icons/svg/operator_administration.svg + icons/svg/documents_disabled.svg + icons/svg/documents.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/organize_documents_disabled.svg + icons/svg/organize_documents.svg + icons/svg/plans_disabled.svg + icons/svg/plans.svg + icons/svg/overlay_plans_disabled.svg + icons/svg/overlay_plans.svg + icons/svg/define_border_lines_disabled.svg + icons/svg/define_border_lines.svg + icons/svg/player_equipment_check_disabled.svg + icons/svg/player_equipment_check.svg + icons/svg/send_player_message_disabled.svg + icons/svg/send_player_message.svg + icons/svg/set_player_mode_disabled.svg + icons/svg/set_player_mode.svg + icons/svg/player_mode.svg + icons/svg/update_player_position_disabled.svg + icons/svg/update_player_position.svg + icons/svg/select_player_disabled.svg + icons/svg/select_player.svg + icons/svg/set_player_status_disabled.svg + icons/svg/set_player_status.svg + icons/svg/define_presentation_disabled.svg + icons/svg/define_presentation.svg + icons/svg/execute_presentation_disabled.svg + icons/svg/execute_presentation.svg + icons/svg/primary_map_position_disabled.svg + icons/svg/primary_map_position.svg + icons/svg/create_terrain_profile_disabled.svg + icons/svg/create_terrain_profile.svg + icons/svg/show_terrain_profile_disabled.svg + icons/svg/show_terrain_profile.svg + icons/svg/report_ammunition_left_disabled.svg + icons/svg/report_ammunition_left.svg + icons/svg/report_ammunition_resupply_disabled.svg + icons/svg/report_ammunition_resupply.svg + icons/svg/report_awes_disabled.svg + icons/svg/report_awes.svg + icons/svg/report_combat_power_disabled.svg + icons/svg/report_combat_power.svg + icons/svg/display_reports_disabled.svg + icons/svg/display_reports.svg + icons/svg/report_explosive_devices_disabled.svg + icons/svg/report_explosive_devices.svg + icons/svg/report_maintenance_disabled.svg + icons/svg/report_maintenance.svg + icons/svg/report_mine_barrier_disabled.svg + icons/svg/report_mine_barrier.svg + icons/svg/report_nbc_events_disabled.svg + icons/svg/report_nbc_events.svg + icons/svg/report_nc_events_disabled.svg + icons/svg/report_nc_events.svg + icons/svg/report_treatment_disabled.svg + icons/svg/report_treatment.svg + icons/svg/report_mortar_firings_disabled.svg + icons/svg/report_mortar_firings.svg + icons/svg/secondary_map_position_disabled.svg + icons/svg/secondary_map_position.svg + icons/svg/select_training_areas_disabled.svg + icons/svg/select_training_areas.svg + icons/svg/system_status.svg + icons/svg/change_password_disabled.svg + icons/svg/change_password.svg + icons/svg/show_building_configuration_disabled.svg + icons/svg/show_building_configuration.svg + icons/svg/simulated_players_disabled.svg + icons/svg/simulated_players.svg + icons/svg/create_snapshot_disabled.svg + icons/svg/create_snapshot.svg + icons/svg/system_status_disabled.svg + icons/svg/system_status.svg + icons/svg/configure_symbol_attributes_disabled.svg + icons/svg/configure_symbol_attributes.svg + icons/svg/symbol_display_disabled.svg + icons/svg/symbol_display.svg + icons/svg/tactical_organization_disabled.svg + icons/svg/tactical_organization.svg + icons/svg/tactical_symbol_disabled.svg + icons/svg/tactical_symbol.svg + icons/svg/objects_define_areas_disabled.svg + icons/svg/objects_define_areas.svg + icons/svg/define_teams_disabled.svg + icons/svg/define_teams.svg + icons/svg/terminal_window_disabled.svg + icons/svg/terminal_window.svg + icons/svg/create_thp_disabled.svg + icons/svg/create_thp.svg + icons/svg/delete_thp_disabled.svg + icons/svg/delete_thp.svg + icons/svg/prepare_thp_disabled.svg + icons/svg/prepare_thp.svg + icons/svg/filter_map_settings_disabled.svg + icons/svg/filter_map_settings.svg + icons/svg/toolbar_editor_disabled.svg + icons/svg/toolbar_editor.svg + icons/svg/translation_editor.svg + icons/svg/translation_editor.svg + icons/svg/help_index_disabled.svg + icons/svg/help_index.svg + icons/svg/define_player_types_disabled.svg + icons/svg/define_player_types.svg + icons/svg/announcement_disabled.svg + icons/svg/announcement.svg + icons/svg/access_rights_disabled.svg + icons/svg/access_rights.svg + icons/svg/mgrs_grid_disabled.svg + icons/svg/mgrs_grid.svg + icons/svg/import_video_disabled.svg + icons/svg/import_video.svg + icons/svg/video_menu_disabled.svg + icons/svg/video_menu.svg + icons/svg/filter_effect_simulation_disabled.svg + icons/svg/filter_effect_simulation.svg + icons/16x16/application-pdf.png + icons/16x16/arrow-left.png + icons/16x16/arrow-right.png + icons/16x16/audio-x-generic.png + icons/16x16/bg.gif + icons/16x16/camera-photo.png + icons/16x16/configure.png + icons/16x16/dialog-close.png + icons/16x16/dialog-ok-apply.png + icons/16x16/dialog-ok.png + icons/16x16/dirs.png + icons/16x16/document-edit.png + icons/16x16/document-import.png + icons/16x16/document-new.png + icons/16x16/document-open-data.png + icons/16x16/document-open.png + icons/16x16/document-preview.png + icons/16x16/document-print.png + icons/16x16/document-properties.png + icons/16x16/document-save-all.png + icons/16x16/document-save-as.png + icons/16x16/document-save.png + icons/16x16/download.png + icons/16x16/draw-bezier-curves.png + icons/16x16/draw-ellipse.png + icons/16x16/draw-line.png + icons/16x16/draw-polygon.png + icons/16x16/draw-polyline.png + icons/16x16/draw-rectangle.png + icons/16x16/draw-text.png + icons/16x16/edit-clear-locationbar-rtl.png + icons/16x16/edit-copy.png + icons/16x16/edit-cut.png + icons/16x16/edit-delete.png + icons/16x16/edit-paste.png + icons/16x16/edit-redo.png + icons/16x16/edit-rename.png + icons/16x16/edit-select.png + icons/16x16/edit-undo.png + icons/16x16/fill-color.png + icons/16x16/format-justify-center.png + icons/16x16/format-justify-fill.png + icons/16x16/format-justify-left.png + icons/16x16/format-justify-right.png + icons/16x16/format-stroke-color.png + icons/16x16/format-text-bold.png + icons/16x16/format-text-italic.png + icons/16x16/format-text-underline.png + icons/16x16/freu.gif + icons/16x16/go-down.png + icons/16x16/go-home.png + icons/16x16/go-next.png + icons/16x16/go-previous.png + icons/16x16/go-up.png + icons/16x16/help-about.png + icons/16x16/help-contents.png + icons/16x16/image-x-generic.png + icons/16x16/internet-mail.png + icons/16x16/led-blue-on.png + icons/16x16/led-gray-on.png + icons/16x16/led-green-on.png + icons/16x16/led-red-on.png + icons/16x16/led-yellow-on.png + icons/16x16/list-add.png + icons/16x16/list-add-user.png + icons/16x16/list-remove.png + icons/16x16/list-remove-user.png + icons/16x16/mail-mark-read.png + icons/16x16/mail-mark-unread.png + icons/16x16/mail-message-new.png + icons/16x16/mail-send.png + icons/16x16/media-eject.png + icons/16x16/media-flash.png + icons/16x16/media-playback-pause.png + icons/16x16/media-playback-start.png + icons/16x16/media-playback-stop.png + icons/16x16/media-play-faster.png + icons/16x16/media-play-normal.png + icons/16x16/media-play-slower.png + icons/16x16/media-record.png + icons/16x16/media-seek-backward.png + icons/16x16/media-seek-forward.png + icons/16x16/media-skip-backward.png + icons/16x16/media-skip-forward.png + icons/16x16/object-group.png + icons/16x16/object-ungroup.png + icons/16x16/oO.gif + icons/16x16/ooo-calc.png + icons/16x16/ooo-impress.png + icons/16x16/ooo-writer.png + icons/16x16/preferences-desktop-font.png + icons/16x16/preferences-web-browser-cache.png + icons/16x16/printer.png + icons/16x16/process-stop.png + icons/16x16/rde_16x16.png + icons/16x16/rde.ico + icons/16x16/system-help.png + icons/16x16/text-plain.png + icons/16x16/transform-move.png + icons/16x16/transform-rotate.png + icons/16x16/transform-scale.png + icons/16x16/traurig.gif + icons/16x16/video-x-generic.png + icons/16x16/view-fullscreen.png + icons/16x16/view-statistics.png + icons/16x16/weinend.gif + icons/16x16/x-office-address-book.png + icons/16x16/yellow-off-16.png + icons/16x16/yellow-on-16.png + icons/16x16/zoom-in.png + icons/16x16/zoom-out.png + icons/16x16/zunge.gif + icons/16x16/zwinker.gif + icons/22x22/dialogbuttonbox.png + icons/22x22/edit-redo.png + icons/22x22/format-justify-center.png + icons/22x22/format-justify-fill.png + icons/22x22/format-justify-left.png + icons/22x22/format-justify-right.png + icons/22x22/format-stroke-color.png + icons/22x22/format-text-bold.png + icons/22x22/format-text-italic.png + icons/22x22/format-text-underline.png + icons/22x22/kdialog.png + icons/22x22/klineedit.png + icons/22x22/layer.png + icons/22x22/pushbutton.png + icons/22x22/scricon.png + icons/32x32/marker-end.png + icons/32x32/marker-start.png + icons/32x32/media-eject.png + icons/32x32/media-playback-pause.png + icons/32x32/media-playback-start.png + icons/32x32/media-playback-start-single.png + icons/32x32/media-playback-stop.png + icons/32x32/media-play-backward.png + icons/32x32/media-play-faster.png + icons/32x32/media-play-normal.png + icons/32x32/media-play-slower.png + icons/32x32/media-record.png + icons/32x32/media-seek-backward.png + icons/32x32/media-seek-forward.png + icons/32x32/media-skip-backward.png + icons/32x32/media-skip-forward.png + icons/32x32/media-vcr-nopause.png + icons/32x32/media-vcr-normal.png + icons/32x32/media-vcr-repeat.png + icons/32x32/media-vcr-withpause.png + icons/32x32/service_message.png + icons/32x32/wireless.png + icons/png/add_disabled.png + icons/png/add.png + icons/png/address_book.png + icons/png/add_tactical_sign_act_disabled.png + icons/png/add_tactical_sign_act.png + icons/png/add_text_act_disabled.png + icons/png/add_text_act.png + icons/png/big_letters_act_disabled.png + icons/png/big_letters_act.png + icons/png/camera_arrow_down.png + icons/png/camera_arrow_left.png + icons/png/camera_arrow_right.png + icons/png/camera_arrow_up.png + icons/png/center_object_in_map_act_disabled.png + icons/png/center_object_in_map_act.png + icons/png/clear_plan_act_disabled.png + icons/png/clear_plan_act.png + icons/png/copy_exercise_disabled.png + icons/png/copy_exercise.png + icons/png/deleteall.png + icons/png/delete_disabled.png + icons/png/delete_exercise_disabled.png + icons/png/delete_exercise.png + icons/png/delete_graphic_eass_disabled.png + icons/png/delete_graphic_eass.png + icons/png/delete.png + icons/png/download.png + icons/png/draw_ellipse_act_disabled.png + icons/png/draw_ellipse_act.png + icons/png/draw_line_disabled.png + icons/png/draw_line.png + icons/png/draw_polygon_act_disabled.png + icons/png/draw_polygon_act.png + icons/png/draw_rectangle_act_disabled.png + icons/png/draw_rectangle_act.png + icons/png/draw_spline_disabled.png + icons/png/draw_spline.png + icons/png/eass_line_disabled.png + icons/png/eass_line.png + icons/png/eass_polygon_disabled.png + icons/png/eass_polygon.png + icons/png/edit_element_act_disabled.png + icons/png/edit_element_act.png + icons/png/edith_graphic_eass_disabled.png + icons/png/edith_graphic_eass.png + icons/png/fast_playback_backward_disabled.png + icons/png/fast_playback_backward.png + icons/png/fast_playback_disabled.png + icons/png/fast_playback.png + icons/png/fill_colour_act_disabled.png + icons/png/fill_colour_act.png + icons/png/folder_open.png + icons/png/kosy_audio_control_act_disabled.png + icons/png/kosy_audio_control_act.png + icons/png/kosy_radio_error_act_disabled.png + icons/png/kosy_radio_error_act.png + icons/png/kosy_remote_control_act_disabled.png + icons/png/kosy_remote_control_act.png + icons/png/line_color.png + icons/png/marker_left_disabled.png + icons/png/marker_left.png + icons/png/marker_right_disabled.png + icons/png/marker_right.png + icons/png/messages_new.png + icons/png/missionmarch_disabled.png + icons/png/missionmarch.png + icons/png/normal_letters_act_disabled.png + icons/png/normal_letters_act.png + icons/png/ok_disabled.png + icons/png/ok.png + icons/png/paste_exercise_disabled.png + icons/png/paste_exercise.png + icons/png/pause_playback_disabled.png + icons/png/pause_playback.png + icons/png/polygonmap_disabled.png + icons/png/polygonmap.png + icons/png/position_map_disabled.png + icons/png/position_map.png + icons/png/preview.png + icons/png/printer.png + icons/png/redo_disabled.png + icons/png/redo.png + icons/png/remove_disabled.png + icons/png/remove.png + icons/png/rename_exercise_disabled.png + icons/png/rename_exercise.png + icons/png/save_as.png + icons/png/save.png + icons/png/settings_disabled.png + icons/png/settings.png + icons/png/start_playback_disabled.png + icons/png/start_playback.png + icons/png/stop_playback_disabled.png + icons/png/stop_playback.png + icons/png/stop.png + icons/png/thick_line_act_disabled.png + icons/png/thick_line_act.png + icons/png/undo_act_disabled.png + icons/png/undo_act.png + icons/png/zoom_in_disabled.png + icons/png/zoom_in.png + icons/png/zoom_out_disabled.png + icons/png/zoom_out.png + icons/svg/3d_viewer_config_disabled.svg + icons/svg/3d_viewer_config.svg + icons/svg/3d_viewer_disabled.svg + icons/svg/3d_viewer.svg + icons/svg/about_disabled.svg + icons/svg/about.svg + icons/svg/ac_adapter_plugged_in.svg + icons/svg/aircraft_sim.svg + icons/svg/application-exit.svg + icons/svg/artillery_firings_disabled.svg + icons/svg/artillery_firings.svg + icons/svg/audio-volume-high.svg + icons/svg/audio-volume-low.svg + icons/svg/audio-volume-medium.svg + icons/svg/audio-volume-muted.svg + icons/svg/battery_mode.svg + icons/svg/camera_control_disabled.svg + icons/svg/camera_control.svg + icons/svg/chat_disabled.svg + icons/svg/chat.svg + icons/svg/configure_arrow.svg + icons/svg/configure_tunnels_disabled.svg + icons/svg/configure_tunnels.svg + icons/svg/create_evaluation_topic.svg + icons/svg/create_image_topic.svg + icons/svg/create_lecture_topic.svg + icons/svg/create_pdf_topic.svg + icons/svg/danger_areas.svg + icons/svg/debug-execute-from-cursor.svg + icons/svg/debug-execute-to-cursor.svg + icons/svg/define_position_system_disabled.svg + icons/svg/define_position_system.svg + icons/svg/dialog-close.svg + icons/svg/dialog-ok-apply.svg + icons/svg/dialog-ok.svg + icons/svg/document-edit.svg + icons/svg/document-new.svg + icons/svg/document-open-data.svg + icons/svg/document-open.svg + icons/svg/document-properties.svg + icons/svg/download.svg + icons/svg/draw-bezier-curves.svg + icons/svg/evaluate_disabled.svg + icons/svg/evaluate.svg + icons/svg/fill_pattern.svg + icons/svg/filter_line_of_sight_disabled.svg + icons/svg/filter_line_of_sight.svg + icons/svg/filter_map_settings_load_disabled.svg + icons/svg/filter_map_settings_load.svg + icons/svg/filter_maps_settings_save_disabled.svg + icons/svg/filter_maps_settings_save.svg + icons/svg/filter_nbc_agents_disabled.svg + icons/svg/fixed_video_announcement_disabled.svg + icons/svg/fixed_video_announcement.svg + icons/svg/function_key_toolbar_disabled.svg + icons/svg/function_key_toolbar.svg + icons/svg/getpos.svg + icons/svg/go-home.svg + icons/svg/hand_grenade_locations.svg + icons/svg/import_msdl.svg + icons/svg/insert_script.svg + icons/svg/karte.svg + icons/svg/layer.svg + icons/svg/line_styles.svg + icons/svg/list-add-user.svg + icons/svg/list-remove-user.svg + icons/svg/load_disabled.svg + icons/svg/load.svg + icons/svg/logout_disabled.svg + icons/svg/logout.svg + icons/svg/map_settings_disabled.svg + icons/svg/map_settings.svg + icons/svg/marker-start.svg + icons/svg/marke.svg + icons/svg/media-flash.svg + icons/svg/media-play-backward.svg + icons/svg/media-play-slower.svg + icons/svg/media-record.svg + icons/svg/media-seek-backward.svg + icons/svg/media-seek-forward.svg + icons/svg/media-skip-backward.svg + icons/svg/media-skip-forward.svg + icons/svg/media-vcr-nopause.svg + icons/svg/media-vcr-normal.svg + icons/svg/media-vcr-withpause.svg + icons/svg/messages_disabled.svg + icons/svg/messages.svg + icons/svg/mini_map_disabled.svg + icons/svg/mini_map.svg + icons/svg/mlvs_control.svg + icons/svg/mobile_video_disabled.svg + icons/svg/mobile_video.svg + icons/svg/network-wireless.svg + icons/svg/new_documents.svg + icons/svg/new_mail_indicator.svg + icons/svg/nuclear_agents.svg + icons/svg/object-group.svg + icons/svg/object-ungroup.svg + icons/svg/oc_composition_disabled.svg + icons/svg/oc_composition.svg + icons/svg/overlays.svg + icons/svg/phase_def.svg + icons/svg/pi_force_collapse.svg + icons/svg/pi_force_expand.svg + icons/svg/pi_force_left.svg + icons/svg/pi_force_right.svg + icons/svg/pi_markup_3d.svg + icons/svg/pi_movementtrack.svg + icons/svg/pi_nbc.svg + icons/svg/pi_show_bite.svg + icons/svg/pi_tact_status_history.svg + icons/svg/pi_type_weaponrange.svg + icons/svg/planned_training_cycles.svg + icons/svg/playback_audio_disabled.svg + icons/svg/playback_audio.svg + icons/svg/playback_situation_disabled.svg + icons/svg/playback_situation.svg + icons/svg/playback_video_disabled.svg + icons/svg/playback_video.svg + icons/svg/player_equipment.svg + icons/svg/preferences-web-browser-cache.svg + icons/svg/presets_disabled.svg + icons/svg/presets.svg + icons/svg/primary_map_toolbar_disabled.svg + icons/svg/primary_map_toolbar.svg + icons/svg/proj_audio.svg + icons/svg/projection.svg + icons/svg/raster_disabled.svg + icons/svg/raster.svg + icons/svg/report_combat_effectiveness_disabled.svg + icons/svg/report_combat_effectiveness.svg + icons/svg/report_treatmentmaintanance_disabled.svg + icons/svg/report_treatmentmaintanance.svg + icons/svg/save_preferences_disabled.svg + icons/svg/save_preferences.svg + icons/svg/screenshot_disabled.svg + icons/svg/screenshot.svg + icons/svg/secondary_map_toolbar_disabled.svg + icons/svg/secondary_map_toolbar.svg + icons/svg/set_force_visibility_disabled.svg + icons/svg/set_force_visibility.svg + icons/svg/set_home_transparency_disabled.svg + icons/svg/set_home_transparency.svg + icons/svg/set_markers_audio_disabled.svg + icons/svg/set_markers_audio.svg + icons/svg/set_marker_situation_disabled.svg + icons/svg/set_marker_situation.svg + icons/svg/set_marker_video_disabled.svg + icons/svg/set_marker_video.svg + icons/svg/set_view_position_disabled.svg + icons/svg/set_view_position.svg + icons/svg/situation_disabled.svg + icons/svg/situation.svg + icons/svg/status_bar_disabled.svg + icons/svg/status_bar.svg + icons/svg/support_documents_disabled.svg + icons/svg/support_documents.svg + icons/svg/switch_to_primary_map_disabled.svg + icons/svg/switch_to_primary_map.svg + icons/svg/switch_to_sec_map_disabled.svg + icons/svg/switch_to_sec_map.svg + icons/svg/target.svg + icons/svg/view-statistics.svg + icons/svg/visible_teams.svg + icons/svg/voice_communication_access_disabled.svg + icons/svg/voice_communication_access.svg + icons/svg/voice_communication_disabled.svg + icons/svg/voice_communication.svg + icons/svg/weapon_firing_disabled.svg + icons/svg/weapon_firing.svg + icons/svg/wireless.svg + + icons/svg/voice_communication_access.svg + icons/svg/voice_communication_disabled.svg + + diff --git a/Z/src/nglwidgets/nglstandardbutton.cpp b/Z/src/nglwidgets/nglstandardbutton.cpp new file mode 100755 index 000000000..30e9f24f2 --- /dev/null +++ b/Z/src/nglwidgets/nglstandardbutton.cpp @@ -0,0 +1,336 @@ + + +#include "nglstandardbutton.h" +#include +#include +#include +#include + +NGLStandardButton::NGLStandardButton(QWidget *parent) + : NGLStandardButton(NoButton, parent) +{} + +NGLStandardButton::NGLStandardButton(StandardButton type, QWidget *parent) + : QPushButton(parent) + , m_type(type) + , m_layoutPriority(-1) +{ + init(); +} + +void NGLStandardButton::init() +{ + setType(m_type); +} + +NGLStandardButton::StandardButton NGLStandardButton::type() const +{ + return m_type; +} + +void NGLStandardButton::setType(StandardButton t) +{ + m_type = t; + qDeleteAll(m_actionList); + m_actionList.clear(); + const char *iconName = nullptr; + QString text; + QString actionText; + QKeySequence key; + const char *objectName = nullptr; + switch (t) + { + case Ok: + iconName = ":icons/png/ok.png"; + text = tr("&Ok"); + objectName = "btnOk"; + break; + case Send: + iconName = ":icons/svg/messages.svg"; + text = tr("&Send"); + key = QKeySequence(Qt::CTRL + Qt::Key_Return); + objectName = "btnSend"; + break; + case New: + iconName = ":icons/png/messages_new.png"; + text = tr("&New"); + key = QKeySequence::New; + objectName = "btnNew"; + break; + case Delete: + iconName = ":icons/png/deleteall.png"; + text = tr("&Delete"); + key = QKeySequence::Delete; + objectName = "btnDelete"; + break; + case Save: + iconName = ":icons/png/save.png"; + text = tr("Sa&ve"); + key = QKeySequence::Save; + objectName = "btnSave"; + break; + case Open: + iconName = ":icons/png/address_book.png"; + text = tr("&Open"); + key = QKeySequence::Open; + objectName = "btnOpen"; + break; + case Yes: + iconName = ":icons/png/ok.png"; + text = tr("&Yes"); + objectName = "btnYes"; + break; + case No: + iconName = ":icons/png/delete.png"; + text = tr("&No"); + objectName = "btnNo"; + break; + case Close: + iconName = ":icons/png/delete_exercise.png"; + text = tr("&Close"); + objectName = "btnClose"; + break; + case Cancel: + iconName = ":icons/png/delete_exercise.png"; + text = tr("&Cancel"); + objectName = "btnCancel"; + break; + case Help: + iconName = ":icons/svg/ueb_index.svg"; + text = QString(); + actionText = tr("Help"); + setMaximumWidth(sizeHint().height()); + key = QKeySequence::HelpContents; + objectName = "btnHelp"; + break; + case Apply: + iconName = ":icons/png/ok.png"; + text = tr("&Apply"); + objectName = "btnApply"; + break; + case Reset: + iconName = ":icons/png/undo_act.png"; + text = tr("Re&set"); + objectName = "btnReset"; + break; + case Print: + iconName = ":icons/png/printer.png"; + text = QString(); + actionText = tr("Print"); + setMaximumWidth(sizeHint().height()); + key = QKeySequence::Print; + objectName = "btnPrint"; + break; + case Add: + iconName = ":icons/png/add.png"; + text = tr("A&dd"); + objectName = "btnAdd"; + break; + case Remove: + iconName = ":icons/png/remove.png"; + text = tr("Re&move"); + objectName = "btnRemove"; + break; + case Edit: + iconName = ":icons/png/rename_exercise.png"; + text = tr("&Edit"); + objectName = "btnEdit"; + break; + case Modify: + iconName = ":icons/png/ok.png"; + text = tr("Modify"); + objectName = "btnModify"; + break; + case Hide: + iconName = ":icons/png/ok.png"; + text = tr("Hide"); + objectName = "btnHide"; + break; + case Download: + iconName = ":icons/png/download.png"; + text = tr("Download"); + objectName = "btnDownload"; + break; + case Library: + { + iconName = ":icons/png/address_book.png"; + text.clear(); + setMaximumWidth(minimumSizeHint().width() * 4 / 5); + QMenu *menu = new QMenu(this); + setMenu(menu); + + QAction *actionImport = menu->addAction(QIcon(QLatin1String(":icons/svg/import_docs.svg")), tr("Import from library")); + actionImport->setObjectName(QLatin1String("actionImport")); + connect(actionImport, &QAction::triggered, + this, QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += actionImport; + + QAction *actionExport = menu->addAction(QIcon(QLatin1String(":icons/svg/export_docs.svg")), tr("Export to library")); + actionExport->setObjectName(QLatin1String("actionExport")); + connect(actionExport, &QAction::triggered, + this, QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += actionExport; + + objectName = "btnLibrary"; + break; + } + case Show: + { + iconName = ":icons/png/preview.png"; + text = tr("Show"); + objectName = "btnShow"; + break; + } + case ZoomIn: + { + iconName = ":icons/png/zoom_in.png"; + text.clear(); + objectName = "btnZoomIn"; + break; + } + case ZoomOut: + { + iconName = ":icons/png/zoom_out.png"; + text.clear(); + objectName = "btnZoomOut"; + break; + } + default: + text = QLatin1String("ButtonText"); + break; + }; + if (!m_defaultText.isEmpty()) + text = tr(m_defaultText.constData()); + if (!m_defaultToolTip.isEmpty()) + { + QString toolTip = tr(m_defaultToolTip.constData()); + setToolTip(toolTip); + } + if (iconName) + setIcon(QIcon(QString::fromLatin1(iconName))); + setText(text); + if (!key.isEmpty()) + setShortcut(key); + if (objectName) + setObjectName(QString::fromUtf8(objectName)); + + if (m_actionList.isEmpty()) + { + QAction *action = new QAction(this); + action->setText(text.isEmpty() ? actionText : text); + action->setIcon(icon()); + action->setEnabled(isEnabled()); + action->setToolTip(toolTip()); + action->setWhatsThis(whatsThis()); + connect(action, &QAction::triggered, this, + QOverload::of(&QAbstractButton::clicked), Qt::QueuedConnection); + m_actionList += action; + } +} + +void NGLStandardButton::setLayoutPriority(qint32 priority) +{ + m_layoutPriority = priority; +} + +qint32 NGLStandardButton::layoutPriority() const +{ + + + if (m_layoutPriority >= 0) + return m_layoutPriority; + switch (m_type) + { + case Close: + return 10; + case Cancel: + return 11; + case Apply: + return 13; + case Ok: + return 15; + case No: + return 31; + case Yes: + return 32; + case ZoomIn: + return 36; + case ZoomOut: + return 37; + case Show: + return 38; + case Download: + return 44; + case Save: + return 45; + case Open: + return 47; + case Reset: + return 50; + case Send: + return 50; + case Modify: + return 51; + case Hide: + return 52; + case Delete: + return 55; + case Remove: + return 56; + case New: + return 60; + case Add: + return 61; + case Edit: + return 63; + case Library: + return 105; + case Print: + return 110; + case Help: + return 120; + default: + break; + }; + return 50; +} + +void NGLStandardButton::changeEvent(QEvent *e) +{ + switch (e->type()) + { + case QEvent::LanguageChange: + setType(m_type); + break; + case QEvent::EnabledChange: + { + QAction *a = findChild(); + if (a) + a->setEnabled(isEnabled()); + break; + } + default: + break; + } + QPushButton::changeEvent(e); +} + +QList NGLStandardButton::actions() const +{ + return m_actionList; +} + +void NGLStandardButton::setDefaultText(const char *text) +{ + m_defaultText = QByteArray(text); + if (!m_defaultText.isEmpty()) + setText(tr(m_defaultText.constData())); +} + +void NGLStandardButton::setDefaultToolTip(const char *toolTip) +{ + m_defaultToolTip = QByteArray(toolTip); + if (!m_defaultToolTip.isEmpty()) + setToolTip(tr(m_defaultToolTip.constData())); +} + diff --git a/Z/src/nglwidgets/nglstandardbutton.h b/Z/src/nglwidgets/nglstandardbutton.h new file mode 100755 index 000000000..d621ca2e7 --- /dev/null +++ b/Z/src/nglwidgets/nglstandardbutton.h @@ -0,0 +1,105 @@ + + +#pragma once + +#include + +#include "nglwidgets_export.h" + + + + +class NGLWIDGETS_EXPORT NGLStandardButton : public QPushButton +{ + Q_OBJECT + Q_PROPERTY(StandardButton standardButton READ type WRITE setType) + Q_PROPERTY(qint32 layoutPriority READ layoutPriority WRITE setLayoutPriority) + +public: + + + enum StandardButton + { + NoButton = 0x00000000, + Ok = 0x00000001, + Save = 0x00000002, + Open = 0x00000004, + Yes = 0x00000008, + No = 0x00000010, + Close = 0x00000020, + Cancel = 0x00000040, + Help = 0x00000080, + Apply = 0x00000100, + Reset = 0x00000200, + Print = 0x00000400, + Add = 0x00000800, + Remove = 0x00002000, + Edit = 0x00008000, + Send = 0x00010000, + New = 0x00020000, + Delete = 0x00040000, + Download = 0x00080000, + Library = 0x00100000, + Show = 0x00200000, + ZoomIn = 0x00400000, + ZoomOut = 0x00800000, + Modify = 0x01000000, + Hide = 0x02000000, + +#ifndef Q_MOC_RUN + FirstButton = Ok, + LastButton = Hide +#endif + }; + Q_ENUM(StandardButton) + Q_DECLARE_FLAGS(StandardButtons, StandardButton) + Q_FLAG(StandardButtons) + + + + explicit NGLStandardButton(QWidget *parent = nullptr); + + + explicit NGLStandardButton(StandardButton type, QWidget *parent = nullptr); + + + + StandardButton type() const; + + + void setType(StandardButton t); + + + + void setLayoutPriority(qint32 priority); + + + + virtual qint32 layoutPriority() const; + + + + QList actions() const; + + + + void setDefaultText(const char *text); + + + + void setDefaultToolTip(const char *toolTip); + +protected: + StandardButton m_type; + qint32 m_layoutPriority; + QByteArray m_defaultText; + QByteArray m_defaultToolTip; + QList m_actionList; + + virtual void changeEvent(QEvent *e); +private: + void init(); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(NGLStandardButton::StandardButtons) + + diff --git a/Z/src/nglwidgets/ngltreeitem.cpp b/Z/src/nglwidgets/ngltreeitem.cpp new file mode 100755 index 000000000..4d7d52be0 --- /dev/null +++ b/Z/src/nglwidgets/ngltreeitem.cpp @@ -0,0 +1,131 @@ + + + +#include "ngltreeitem.h" + + +NGLTreeItem::~NGLTreeItem() +{ + qDeleteAll(m_childItems); +} + + + +NGLTreeItem::NGLTreeItem(const NGLTreeItem &orig) +{ + set(orig); +} + + + +NGLTreeItem &NGLTreeItem::operator=(const NGLTreeItem &orig) +{ + set(orig); + return *this; +} + + + +void NGLTreeItem::set(const NGLTreeItem &orig) +{ + m_parentItem = orig.m_parentItem; + m_modified = orig.m_modified; + m_data = orig.m_data; + m_icon = orig.m_icon; + const auto origChildren = orig.children(); + for (NGLTreeItem *origChild : origChildren) + appendChild(new NGLTreeItem(*origChild)); +} + + +bool NGLTreeItem::insertChild(int row, NGLTreeItem *item) +{ + if ((row >= 0) && (row <= childCount())) + { + item->m_parentItem = this; + m_childItems.insert(row, item); + return true; + } + return false; +} + + +void NGLTreeItem::appendChild(NGLTreeItem *item) +{ + item->m_parentItem = this; + m_childItems.push_back(item); +} + + + +NGLTreeItem *NGLTreeItem::takeChild(int row) +{ + return validRow(row) ? m_childItems.takeAt(row) : nullptr; +} + + +bool NGLTreeItem::removeChild(int row) +{ + if (!validRow(row)) + return false; + + delete m_childItems.takeAt(row); + return true; +} + + +bool NGLTreeItem::removeChild(const NGLTreeItem *child) +{ + for (int row = 0; row < m_childItems.size(); ++row) + { + if (m_childItems.at(row) == child) + { + removeChild(row); + return true; + } + } + return false; +} + + +bool NGLTreeItem::removeChildren(int row, int count) +{ + int lastRow = row + count - 1; + if (validRow(row) && + (lastRow >= 0) && (lastRow < childCount())) + { + while (lastRow >= row) + { + delete m_childItems.takeAt(row); + --lastRow; + } + return true; + } + return false; +} + + +bool NGLTreeItem::removeAllChildren() +{ + qDeleteAll(m_childItems); + m_childItems.clear(); + return true; +} + + +int NGLTreeItem::row() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast(this)); + return 0; +} + + +void NGLTreeItem::setData(const QVariant &data) +{ + if (m_data != data) + { + m_data = data; + setModified(true); + } +} diff --git a/Z/src/nglwidgets/ngltreeitem.h b/Z/src/nglwidgets/ngltreeitem.h new file mode 100755 index 000000000..51da5e2ab --- /dev/null +++ b/Z/src/nglwidgets/ngltreeitem.h @@ -0,0 +1,72 @@ + + + +#pragma once + +#include +#include +#include + +#include "nglwidgets_export.h" + + + + + +class NGLWIDGETS_EXPORT NGLTreeItem +{ +public: + + + NGLTreeItem(const QVariant &data, const QIcon &icon = QIcon()) + : m_data(data) + , m_icon(icon) + {} + + + + virtual ~NGLTreeItem(); + + + + NGLTreeItem(const NGLTreeItem &orig); + + + + NGLTreeItem &operator=(const NGLTreeItem &orig); + + + + bool insertChild(int row, NGLTreeItem *item); + void appendChild(NGLTreeItem *item); + NGLTreeItem *takeChild(int row); + bool removeChild(const NGLTreeItem *child); + bool removeChild(int row); + bool removeChildren(int row, int count); + bool removeAllChildren(); + + NGLTreeItem *child(int row) const { return validRow(row) ? m_childItems.value(row) : nullptr; } + QVector children() const { return m_childItems; } + const QVector constChildren() const { return m_childItems; } + int childCount() const { return m_childItems.size(); } + int row() const; + NGLTreeItem *parent() const { return m_parentItem; } + + void setModified(bool modified) { m_modified = modified; } + bool modified() const { return m_modified; } + virtual void setData(const QVariant &data); + virtual QVariant data() const { return m_data; } + virtual void setIcon(const QIcon &icon) { m_icon = icon; } + virtual QIcon icon() const { return m_icon; } + +private: + void set(const NGLTreeItem &orig); + bool validRow(int row) const { return ((row >= 0) && (row < childCount())); } + +private: + QVector m_childItems; + QVariant m_data; + QIcon m_icon; + NGLTreeItem *m_parentItem = nullptr; + bool m_modified = false; +}; diff --git a/Z/src/nglwidgets/ngltreemodel.cpp b/Z/src/nglwidgets/ngltreemodel.cpp new file mode 100755 index 000000000..13d88b1ea --- /dev/null +++ b/Z/src/nglwidgets/ngltreemodel.cpp @@ -0,0 +1,458 @@ + + + +#include "ngltreemodel.h" +#include "ngltreeitem.h" + +#include +#include +#include +#include +#include + + +NGLTreeModel::NGLTreeModel(QObject *parent, NGLTreeItem *rootItem, + const QStringList &titles) + : QAbstractItemModel(parent) + , m_rootItem(rootItem) + , m_titles(titles) + , m_mimeType(QStringLiteral("NGLTreeModel/dragDrop")) + , m_bMimeDataWithicon(true) +{ + connect(this, &NGLTreeModel::dataChanged, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsInserted, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsMoved, + this, &NGLTreeModel::modelDataChanged); + connect(this, &NGLTreeModel::rowsRemoved, + this, &NGLTreeModel::modelDataChanged); +} + + +NGLTreeModel::~NGLTreeModel() +{ + resetModel(); + delete m_rootItem; +} + + +void NGLTreeModel::setRootItem(NGLTreeItem *rootItem) +{ + resetModel(); + delete m_rootItem; + m_rootItem = nullptr; + beginResetModel(); + endResetModel(); + m_rootItem = rootItem; +} + + +NGLTreeItem *NGLTreeModel::getRootItem() const +{ + return m_rootItem; +} + + +NGLTreeItem *NGLTreeModel::createItem(const QVariant &data, const QIcon &icon) const +{ + return new NGLTreeItem(data, icon); +} + + +void NGLTreeModel::resetModel() +{ + if (m_rootItem) + { + beginResetModel(); + m_rootItem->removeAllChildren(); + endResetModel(); + } +} + + +Qt::ItemFlags NGLTreeModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + if (index.isValid()) + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + return defaultFlags; +} + + +QVariant NGLTreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + if ((section >= 0) && (section < m_titles.size())) + return m_titles.at(section); + } + return QVariant(); +} + + +QModelIndex NGLTreeModel::index(int row, int column, + const QModelIndex &parent) const + +{ + if (!hasIndex(row, column, parent)) + { + return QModelIndex(); + } + NGLTreeItem *parentItem = privateData(parent); + NGLTreeItem *childItem = parentItem->child(row); + if (childItem) + { + return createIndex(row, column, childItem); + } + return QModelIndex(); +} + + +QModelIndex NGLTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + NGLTreeItem *childItem = privateData(index); + NGLTreeItem *parentItem = childItem->parent(); + if (!parentItem || parentItem == m_rootItem) + return QModelIndex(); + return createIndex(parentItem->row(), 0, parentItem); +} + + +int NGLTreeModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return m_titles.size(); +} + + +int NGLTreeModel::rowCount(const QModelIndex &parent) const +{ + if (parent.column() > 0) + return 0; + NGLTreeItem *ti = privateData(parent); + if (!ti) + return 0; + return ti->childCount(); +} + + +bool NGLTreeModel::setData(const QModelIndex &index, const QVariant &value, + int role) +{ + Q_UNUSED(index) + Q_UNUSED(value) + Q_UNUSED(role) + return false; +} + + +void NGLTreeModel::setMimeType(const QString &mimeType) +{ + m_mimeType = mimeType; +} + + +void NGLTreeModel::resetModifedFlag(NGLTreeItem *rootItem) +{ + if (!rootItem) + return; + rootItem->setModified(false); + for (int i = 0; i < rootItem->childCount(); ++i) + resetModifedFlag(rootItem->child(i)); +} + + + +bool NGLTreeModel::setItemData(const QModelIndex &index, const QVariant &value, + const QIcon &icon) +{ + if (!index.isValid()) + return false; + + NGLTreeItem *item = privateData(index); + item->setData(value); + item->setIcon(icon); + item->setModified(true); + emit dataChanged(index, index); + return true; +} + + +QVariant NGLTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (role == Qt::DecorationRole) + { + if (index.column() == 0) + { + NGLTreeItem *item = privateData(index); + if (item) + return item->icon(); + } + } + return QVariant(); +} + + +QMimeData *NGLTreeModel::mimeData(const QModelIndexList &indexes) const +{ + return getMimeData(indexes, m_mimeType); +} + + +QMimeData *NGLTreeModel::getMimeData(const QModelIndexList &indexes, + const QString &mimeType) const +{ + QMimeData *mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + + stream << m_bMimeDataWithicon; + + bool dataStreamed = false; + for (const QModelIndex &index : indexes) + { + if (index.isValid() && (index.column() == 0)) + { + streamAddChilds(stream, privateData(index)); + dataStreamed = true; + } + } + if (dataStreamed) + mimeData->setData(mimeType, encodedData); + return mimeData; +} + + +void NGLTreeModel::streamAddChilds(QDataStream &stream, const NGLTreeItem *item) const +{ + stream << qint64(item->parent()) << qint64(item) << getItemData(item); + if (m_bMimeDataWithicon) + stream << item->icon(); + + for (int i = 0; i < item->childCount(); i++) + streamAddChilds(stream, item->child(i)); +} + + +bool NGLTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + qDebug() << "dropMimeData: action = " << action + << ", row = " << row + << ", column = " << column + << ", parent: valid = " << parent.isValid(); + + if ((action != Qt::MoveAction) && (action != Qt::CopyAction)) + return false; + if (!data->hasFormat(m_mimeType)) + return false; + + int beginRow; + QModelIndex parentR; + if (row != -1) + { + + parentR = parent; + beginRow = row; + } + else if (parent.isValid()) + { + + + parentR = parent; + + beginRow = rowCount(parentR); + + + } + else + { + + parentR = QModelIndex(); + beginRow = rowCount(parentR); + } + return insertMimeData(data, m_mimeType, parentR, beginRow); +} + + +bool NGLTreeModel::insertMimeData(const QMimeData *data, const QString &mimeType, + QModelIndex parentR, int beginRow) +{ + bool bStreamContainsIcons; + + QByteArray encodedData = data->data(mimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + qint64 idParent, idItem; + QHash rowCache; + QVariant itemData; + QIcon icon; + + stream >> bStreamContainsIcons; + + bool first = true; + qint64 prevIdParent = 0; + while (!stream.atEnd()) + { + stream >> idParent >> idItem >> itemData; + if (bStreamContainsIcons) + stream >> icon; + + NGLTreeItem *item = createItem(itemData, icon); + + if (first) + { + first = false; + rowCache.insert(idParent, parentR); + } + else if (idParent == prevIdParent) + { + parentR = rowCache[idParent]; + beginRow++; + } + else + { + parentR = rowCache[idParent]; + beginRow = privateData(rowCache[idParent])->childCount(); + } + prevIdParent = idParent; + + if (!insertRow(beginRow, parentR, item)) + { + delete item; + return false; + } + rowCache.insert(idItem, index(beginRow, 0, parentR)); + emit signalDataDropped(beginRow, parentR); + } + return true; +} + + +QVector NGLTreeModel::getMimeDataItems(const QMimeData *data, + const QString &mimeType) const +{ + QVector ret; + QByteArray encodedData = data->data(mimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + qint64 idParent, idItem; + QVariant itemData; + QIcon icon; + bool bStreamContainsIcons; + + stream >> bStreamContainsIcons; + while (!stream.atEnd()) + { + stream >> idParent >> idItem >> itemData; + if (bStreamContainsIcons) + stream >> icon; + ret += createItem(itemData, icon); + } + return ret; +} + + +NGLTreeItem *NGLTreeModel::privateData(const QModelIndex &index) const +{ + if (!index.isValid()) + return m_rootItem; + Q_ASSERT(index.model() == this); + return static_cast(index.internalPointer()); +} + + +bool NGLTreeModel::moveRow(const QModelIndex &sourceParent, int sourceRow, + const QModelIndex &destParent, int destRow) +{ + Q_ASSERT(sourceParent.column() == 0 || !sourceParent.isValid()); + Q_ASSERT(destParent.column() == 0 || !destParent.isValid()); + + NGLTreeItem *sourceParentItem = privateData(sourceParent); + NGLTreeItem *destParentItem = privateData(destParent); + if ((sourceRow >= 0) && (sourceRow < sourceParentItem->childCount()) && + (destRow >= 0) && (destRow < destParentItem->childCount())) + { + beginRemoveRows(sourceParent, sourceRow, sourceRow); + NGLTreeItem *item = sourceParentItem->takeChild(sourceRow); + endRemoveRows(); + if (item) + { + beginInsertRows(destParent, destRow, destRow); + bool ret = destParentItem->insertChild(destRow, item); + endInsertRows(); + return ret; + } + } + return false; +} + + +bool NGLTreeModel::removeRows(int row, int count, const QModelIndex &parent) +{ + qDebug() << "removeRows: row = " << row << ", " + << "count = " << count; + NGLTreeItem *parentItem = privateData(parent); + if ((row < 0 && row >= parentItem->childCount()) || count <= 0) + return false; + Q_ASSERT(parent.column() == 0 || !parent.isValid()); + if (parent.column() != 0 && parent.isValid()) + return false; + beginRemoveRows(parent, row, row + count - 1); + bool ret = parentItem->removeChildren(row, count); + if (ret) + { + for (int r = row; r < parentItem->childCount(); ++r) + parentItem->child(r)->setModified(true); + } + endRemoveRows(); + return ret; +} + + +bool NGLTreeModel::insertRow(int row, const QModelIndex &parent, NGLTreeItem *item) +{ + NGLTreeItem *parentItem = privateData(parent); + if (!parentItem) + return false; + + Q_ASSERT(parent.column() == 0 || !parent.isValid()); + if (parent.column() != 0 && parent.isValid()) + return false; + + + + + + parentItem->setModified(true); + beginInsertRows(parent, row, row); + bool ret = parentItem->insertChild(row, item); + for (int r = row; r < parentItem->childCount(); ++r) + parentItem->child(r)->setModified(true); + endInsertRows(); + return ret; +} + + +QModelIndex NGLTreeModel::indexFromItem(const NGLTreeItem *item, int column) const +{ + if (item == m_rootItem || item == nullptr) + return QModelIndex(); + const NGLTreeItem *parent = item->parent(); + const QModelIndex parentIdx = indexFromItem(parent); + return index(item->row(), column, parentIdx); +} + + +QVariant NGLTreeModel::getItemData(const NGLTreeItem *item) const +{ + return item->data(); +} diff --git a/Z/src/nglwidgets/ngltreemodel.h b/Z/src/nglwidgets/ngltreemodel.h new file mode 100755 index 000000000..409c7a50c --- /dev/null +++ b/Z/src/nglwidgets/ngltreemodel.h @@ -0,0 +1,98 @@ + + + +#pragma once + +#include +#include +#include "nglwidgets_export.h" + +class NGLTreeItem; + + + + + +class NGLWIDGETS_EXPORT NGLTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + NGLTreeModel(QObject *parent, NGLTreeItem *rootItem, + const QStringList &titles); + virtual ~NGLTreeModel(); + void resetModel(); + + Qt::ItemFlags flags(const QModelIndex &index) const override; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::EditRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override; + QStringList mimeTypes() const override { return { m_mimeType }; } + + Qt::DropActions supportedDropActions() const override { return Qt::CopyAction | Qt::MoveAction; } + QMimeData *mimeData(const QModelIndexList &indexes) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) override; + + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + + + NGLTreeItem *privateData(const QModelIndex &index) const; + void setMimeType(const QString &mimeType); + + + bool setItemData(const QModelIndex &index, const QMap &roles) override + { + return QAbstractItemModel::setItemData(index, roles); + } + +protected: + + void setMimeDataWithIcon(bool bWithIcon) { m_bMimeDataWithicon = bWithIcon; } + + + void resetModifedFlag(NGLTreeItem *rootItem); + + bool setItemData(const QModelIndex &index, const QVariant &value, + const QIcon &icon); + QMimeData *getMimeData(const QModelIndexList &indexes, + const QString &mimeType) const; + bool insertMimeData(const QMimeData *data, const QString &mimeType, + QModelIndex parentR, int beginRow); + + QVector getMimeDataItems(const QMimeData *data, + const QString &mimeType) const; + + bool moveRow(const QModelIndex &sourceParent, int sourceRow, + const QModelIndex &destParent, int destRow); + bool insertRow(int row, const QModelIndex &parent, NGLTreeItem *item); + + void setRootItem(NGLTreeItem *rootItem); + NGLTreeItem *getRootItem() const; + + virtual NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const; + + void streamAddChilds(QDataStream &stream, const NGLTreeItem *item) const; + + QModelIndex indexFromItem(const NGLTreeItem *item, int column = 0) const; + + virtual QVariant getItemData(const NGLTreeItem *item) const; +Q_SIGNALS: + void signalDataDropped(int row, const QModelIndex &parent); + void modelDataChanged(); + +protected: + NGLTreeItem *m_rootItem; + QStringList m_titles; + QString m_mimeType; + bool m_bMimeDataWithicon; +}; diff --git a/Z/src/nglwidgets/nglwidgets_export.h b/Z/src/nglwidgets/nglwidgets_export.h new file mode 100755 index 000000000..ef4b4d8fb --- /dev/null +++ b/Z/src/nglwidgets/nglwidgets_export.h @@ -0,0 +1,17 @@ + + +#pragma once + +#include + +#ifndef NGLWIDGETS_EXPORT +# ifdef BUILD_STATIC_LIBRARIES +# define NGLWIDGETS_EXPORT +# else +# if defined(MAKE_NGLWIDGETS_LIB) +# define NGLWIDGETS_EXPORT Q_DECL_EXPORT +# else +# define NGLWIDGETS_EXPORT Q_DECL_IMPORT +# endif +# endif +#endif diff --git a/Z/src/qsql_informix/CMakeLists.txt b/Z/src/qsql_informix/CMakeLists.txt new file mode 100755 index 000000000..eae1e3087 --- /dev/null +++ b/Z/src/qsql_informix/CMakeLists.txt @@ -0,0 +1,49 @@ +# CMake script for informix sql driver +CMAKE_MINIMUM_REQUIRED(VERSION 3.5) + +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED 11) +SET(CMAKE_CXX_VISIBILITY_PRESET hidden) +SET(CMAKE_INCLUDE_CURRENT_DIR ON) +SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +SET(CMAKE_POSITION_INDEPENDENT_CODE ON) +SET(CMAKE_AUTOMOC TRUE) +SET(QT_USE_IMPORTED_TARGETS TRUE) +FIND_PACKAGE(Qt5 5.9.0 COMPONENTS Core Sql Test REQUIRED) + +FIND_PACKAGE(IClientSDK REQUIRED) + +ADD_DEFINITIONS(-DQT_NO_CAST_FROM_ASCII) +ADD_DEFINITIONS(-DIT_DO_NOT_SIMULATE_BOOL) +INCLUDE_DIRECTORIES(${ICLIENT_SDK_INCLUDE_DIR}) +SET(ifx_SRCS + qsql_informix.cpp + qsql_informix.h + qsql_informix_plugin.cpp + qsql_informix_utils.cpp + qsql_informix_utils.h +) + +ADD_LIBRARY(qsql_informix SHARED ${ifx_SRCS}) +TARGET_LINK_LIBRARIES(qsql_informix + Qt5::Core + Qt5::Sql + ${ICLIENT_SDK_LIBRARIES} + ${ICLIENT_SDK_LIBRARIES_CPP} + ${ICLIENT_SDK_ESQL_OBJECT_FILE} +) +TARGET_COMPILE_DEFINITIONS(qsql_informix PRIVATE MAKE_QSQL_INFORMIX_LIB) +INSTALL(TARGETS qsql_informix DESTINATION lib/sqldrivers) + +SET(test_SRCS + qsql_informix_test.cpp +) +ADD_EXECUTABLE(qsql_informix_test ${test_SRCS}) +TARGET_LINK_LIBRARIES(qsql_informix_test + qsql_informix + Qt5::Test + dl +) +ADD_TEST(NAME qsql_informix_test COMMAND $) diff --git a/Z/src/qsql_informix/FindCrypt.cmake b/Z/src/qsql_informix/FindCrypt.cmake new file mode 100755 index 000000000..6cf85a570 --- /dev/null +++ b/Z/src/qsql_informix/FindCrypt.cmake @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + SET(CRYPT_FOUND TRUE) +ELSE(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + FIND_PATH(CRYPT_INCLUDE_DIR crypt.h) + FIND_LIBRARY(CRYPT_LIBRARY crypt) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Crypt DEFAULT_MSG CRYPT_LIBRARY CRYPT_INCLUDE_DIR) + + MARK_AS_ADVANCED(CRYPT_INCLUDE_DIR CRYPT_LIBRARY) +ENDIF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) diff --git a/Z/src/qsql_informix/FindIClientSDK.cmake b/Z/src/qsql_informix/FindIClientSDK.cmake new file mode 100755 index 000000000..8b3567ec2 --- /dev/null +++ b/Z/src/qsql_informix/FindIClientSDK.cmake @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(NOT WIN32) + IF(IClientSDK_FIND_REQUIRED) + FIND_PACKAGE(Crypt REQUIRED) + ELSE() + FIND_PACKAGE(Crypt) + ENDIF() +ENDIF() + +INCLUDE(FindPackageHandleStandardArgs) + +IF(NOT ICLIENT_SDK_DIR) + FIND_PROGRAM(ICLIENT_ESQL_EXECUTABLE bin/esql PATHS "$ENV{INFORMIXDIR}" "$ENV{INFORMIXDIR}/csdk") + IF(IClientSDK_FIND_REQUIRED) + IF(NOT ICLIENT_ESQL_EXECUTABLE) + MESSAGE(FATAL_ERROR "Could not find Informix Client SDK - $INFORMIXDIR not set?") + ENDIF() + ENDIF() + IF(ICLIENT_ESQL_EXECUTABLE) + GET_FILENAME_COMPONENT(ICLIENT_SDK_DIR_tmp ${ICLIENT_ESQL_EXECUTABLE} PATH) + GET_FILENAME_COMPONENT(ICLIENT_SDK_DIR ${ICLIENT_SDK_DIR_tmp} PATH CACHE) + ENDIF() + MESSAGE(STATUS "Using Informix Client SDK directory ${ICLIENT_SDK_DIR}") +ENDIF() + +FIND_PATH(ICLIENT_SDK_INCLUDE_DIR_INTERNAL NAMES c++/it.h cpp/it.h HINTS ${ICLIENT_SDK_DIR}/incl) + +IF(ICLIENT_SDK_INCLUDE_DIR_INTERNAL) + SET(ICLIENT_SDK_INCLUDE_DIR + ${CRYPT_INCLUDE_DIR} + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL} + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/c++ + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/cpp + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/cli + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/dmi + ${ICLIENT_SDK_INCLUDE_DIR_INTERNAL}/esql + CACHE INTERNAL "All IClient SDK include dirs needed" + ) + SET(ICLIENT_SDK_LIBRARY_DIRS + ${ICLIENT_SDK_DIR}/lib/ + ${ICLIENT_SDK_DIR}/lib/c++ + ${ICLIENT_SDK_DIR}/lib/cpp + ${ICLIENT_SDK_DIR}/lib/cli + ${ICLIENT_SDK_DIR}/lib/client + ${ICLIENT_SDK_DIR}/lib/dmi + ${ICLIENT_SDK_DIR}/lib/esql + CACHE INTERNAL "All IClient SDK library dirs" + ) +ENDIF() + +MACRO(ICLIENT_FIND_LIBRARY lib varname) + SET(LIBNAME ICLIENT_SDK_${lib}_LIBRARY) + FIND_LIBRARY(${LIBNAME} ${lib} ${f} + PATHS ${ICLIENT_SDK_DIR}/lib/ + ${ICLIENT_SDK_DIR}/lib/c++ + ${ICLIENT_SDK_DIR}/lib/cpp + ${ICLIENT_SDK_DIR}/lib/cli + ${ICLIENT_SDK_DIR}/lib/client + ${ICLIENT_SDK_DIR}/lib/dmi + ${ICLIENT_SDK_DIR}/lib/esql + ) + LIST(APPEND ${varname} ${${LIBNAME}}) + MARK_AS_ADVANCED(${LIBNAME}) + IF(IClientSDK_FIND_REQUIRED) + SET(ICLIENT_SDK_${LIBNAME}_FIND_REQUIRED TRUE) + SET(ICLIENT_SDK_${LIBNAME}_FIND_QUIETLY TRUE) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICLIENT_SDK_${LIBNAME} DEFAULT_MSG ${LIBNAME}) + ENDIF() +ENDMACRO() + +IF(WIN32) + ICLIENT_FIND_LIBRARY( libthdmi ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( libthc++ ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( isqlt09a ICLIENT_SDK_LIBRARIES ) + ICLIENT_FIND_LIBRARY( isqlt09s ICLIENT_SDK_LIBRARIES ) +ELSE() + ICLIENT_FIND_LIBRARY("ifc++" ICLIENT_SDK_LIBRARIES_CPP) + SET(iclient_libs + asf + gen + gls + os + sql + ) + SET(iclient_libs_if_only + dmi + glx + ) + SET(iclient_prefix + if + ix + ) + SET(ICLIENT_SDK_LIBRARIES CACHE INTERNAL "All IClient SDK libraries needed") + IF(CRYPT_FOUND) + SET(ICLIENT_SDK_LIBRARIES ${CRYPT_LIBRARY}) + ENDIF() + + MARK_AS_ADVANCED(ICLIENT_SDK_LIBRARIES) + FOREACH(pre ${iclient_prefix}) + FOREACH(f ${iclient_libs}) + ICLIENT_FIND_LIBRARY( "${pre}${f}" ICLIENT_SDK_LIBRARIES) + ENDFOREACH() + ENDFOREACH() + FOREACH(f ${iclient_libs_if_only}) + ICLIENT_FIND_LIBRARY( "if${f}" ICLIENT_SDK_LIBRARIES) + ENDFOREACH() + LIST(APPEND ICLIENT_SDK_LIBRARIES "dl") + + FIND_PATH(ICLIENT_SDK_ESQL_OBJECT_FILE_PATH checkapi.o PATHS ${ICLIENT_SDK_DIR}/lib/esql) + SET(ICLIENT_SDK_ESQL_OBJECT_FILE ${ICLIENT_SDK_ESQL_OBJECT_FILE_PATH}/checkapi.o CACHE INTERNAL "") +ENDIF() + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(IClientSDK DEFAULT_MSG ICLIENT_SDK_LIBRARIES ICLIENT_SDK_INCLUDE_DIR_INTERNAL) + +IF(ICLIENTSDK_FOUND) + SET(ICLIENT_SDK_DIR ${ICLIENT_SDK_DIR} CACHE INTERNAL "Informix Client SDK directory") +ENDIF() + + +MACRO(MacroInstallIClientSDK) + IF(NOT ICLIENT_SDK_DIR) + MESSAGE(FATAL_ERROR "ICLIENT_SDK_DIR nicht gesetzt - Installation von IClient SDK nicht moeglich!") + ENDIF() + + SET(iclient_bin_dir "${ICLIENT_SDK_DIR}/bin/") + SET(iclient_lib_dir "${ICLIENT_SDK_DIR}/lib/") + SET(INSTALL_BIN ON) + SET(INSTALL_LIB ON) + + SET(doing_prefix OFF) + SET(iclient_prefix "") + FOREACH(args ${ARGN}) + IF(doing_prefix) + SET(doing_prefix OFF) + SET(iclient_prefix "${args}/") + ENDIF() + IF("${args}" STREQUAL "no-bin") + SET(INSTALL_BIN OFF) + ENDIF() + IF("${args}" STREQUAL "no-lib") + SET(INSTALL_LIB OFF) + ENDIF() + IF("${args}" STREQUAL "prefix") + SET(doing_prefix ON) + ENDIF("${args}" STREQUAL "prefix") + ENDFOREACH() + + IF(INSTALL_BIN) + INSTALL(DIRECTORY ${iclient_bin_dir} DESTINATION ${iclient_prefix}bin PATTERN .svn EXCLUDE) + ENDIF() + IF(INSTALL_LIB) + INSTALL(DIRECTORY ${iclient_lib_dir} DESTINATION ${iclient_prefix}lib PATTERN .svn EXCLUDE) + ENDIF() +ENDMACRO() + +MACRO(ICLIENT_ESQL_PREPROCESS outlist) + FIND_PROGRAM(ESQLC_EXECUTABLE esqlc PATHS ${ICLIENT_SDK_DIR}/lib ${ICLIENT_SDK_DIR}/lib/esql/) + IF(ESQLC_EXECUTABLE) + FOREACH(infile ${ARGN}) + GET_FILENAME_COMPONENT(ext ${infile} EXT) + GET_FILENAME_COMPONENT(output ${infile} NAME_WE) + GET_FILENAME_COMPONENT(input ${infile} ABSOLUTE) + SET(extension "c") + IF("${ext}" STREQUAL ".ecpp") + SET(extension "C") + ENDIF("${ext}" STREQUAL ".ecpp") + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${output}.${extension} + COMMAND ${ESQLC_EXECUTABLE} + ARGS -local ${input} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${input} + ) + LIST(APPEND ${outlist} ${CMAKE_CURRENT_BINARY_DIR}/${output}.${extension}) + ENDFOREACH(infile) + ELSE() + MESSAGE(FATAL_ERROR "Could not find esql executable!") + ENDIF() +ENDMACRO() diff --git a/Z/src/qsql_informix/qsql_informix.cpp b/Z/src/qsql_informix/qsql_informix.cpp new file mode 100755 index 000000000..c4ccfc3ab --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.cpp @@ -0,0 +1,1333 @@ + + + +#include "qsql_informix.h" + + +#include +#include +#include +#include + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +#define DEBUG_FUNCTION + +#ifdef Q_CC_MSVC +float truncf(float in) +{ + return in < 0 ? in + 0.5 : in - 0.5; +} +#endif + +Q_DECLARE_METATYPE(ITConnection *) +Q_DECLARE_METATYPE(ITSet *) + + + + +class QInformixDriverPrivate +{ +public: + QInformixDriverPrivate(QInformixDriver *parent) + : connection(0) + , driver(parent) + , dbLocale(0) + , openCount(0) + , connTimeout(-1) + , connectOnFirstUse(false) + { + connectionTimeoutTimer.setSingleShot(true); + QObject::connect(&connectionTimeoutTimer, SIGNAL(timeout()), + driver, SLOT(timeout())); + } + + ITConnection *connection; + QInformixDriver *driver; + QTextCodec *dbLocale; + ITDBInfo conn_params; + QMutex connCountMutex; + QAtomicInt openCount; + int connTimeout; + bool connectOnFirstUse; + QTimer connectionTimeoutTimer; + + inline ITString toInformixEncoding(const QString &str) const + { + return ITString(dbLocale->fromUnicode(str).constData(), true); + } + + inline QByteArray toInformixEncodingBA(const QString &str) const + { + return dbLocale->fromUnicode(str).constData(); + } + + inline QString fromInformixEncoding(const ITString &str) const + { + return dbLocale->toUnicode(str.Data()).trimmed(); + } + + inline QString fromInformixEncoding(const QByteArray &str) const + { + return dbLocale->toUnicode(str); + } + + void addConnection() + { + QMutexLocker l(&connCountMutex); + checkOpen(); + openCount.ref(); +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s opencount: %d\n", this, __PRETTY_FUNCTION__, (int)openCount); +#endif + } + + void removeConnection() + { + QMutexLocker l(&connCountMutex); + if (openCount.deref() == false && connTimeout >= 0) + { +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p singleShot timeout: %d, driver: %p\n", this, connTimeout, driver); +#endif + connectionTimeoutTimer.start(connTimeout); + } +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s opencount: %d\n", this, __PRETTY_FUNCTION__, (int)openCount); +#endif + } + + void closeConnection(); + + void checkOpen() + { + if (!connection) + { + if (connectOnFirstUse) + { + connectOnFirstUse = false; + if (!driver->openDatabaseInternal()) + return; + } + else + return; + } + if (!connection->IsOpen()) + connection->Open(conn_params); + } +}; + +void QInformixDriverPrivate::closeConnection() +{ + QMutexLocker l(&connCountMutex); +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s\n", this, __PRETTY_FUNCTION__); +#endif + if (!driver->isOpen()) + return; +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p opencount: %d\n", this, (int)openCount); +#endif + if (openCount > 0) + return; + connection->Close(); +} + +static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, + const QInformixDriverPrivate *p) +{ + const char *e = p->connection->ErrorText(); + QString msg = QStringLiteral("IFX Error: ") + QLatin1String(e ? e : ""); +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, "qMakeError: %s\n", qPrintable(msg)); +#endif + const struct sqlca_s *my_sqlca = &sqlca; + return QSqlError(QStringLiteral("QInformix: %1").arg(err), msg, type, my_sqlca->sqlcode); +} + +static QVariant::Type qSqlType2Variant(int t) +{ + t &= SQLTYPE; + switch (t) + { + case SQLSMINT: + case SQLINT: + case SQLINTERVAL: + case SQLSERIAL: + return QVariant::Int; + case SQLINT8: + case SQLSERIAL8: + return QVariant::LongLong; + case SQLFLOAT: + case SQLSMFLOAT: + case SQLDECIMAL: + case SQLMONEY: + return QVariant::Double; + case SQLDATE: + return QVariant::Date; + case SQLDTIME: + return QVariant::DateTime; + case SQLBYTES: + return QVariant::ByteArray; + case SQLCHAR: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLLVARCHAR: + case SQLTEXT: + return QVariant::String; + default: + break; + } + qWarning("Unknown sql data type %d", t); + return QVariant::Invalid; +} + +static int qIfxType2SqlType(const char *typeName) +{ + switch (typeName[0]) + { + case 'b': + if (strcmp(typeName, "byte") == 0) + return SQLBYTES; + break; + case 'c': + if (strcmp(typeName, "clob") == 0) + return SQLBYTES; + if (strcmp(typeName, "char") == 0) + return SQLCHAR; + break; + case 'd': + if (strcmp(typeName, "date") == 0) + return SQLDATE; + if (strcmp(typeName, "datetime") == 0) + return SQLDTIME; + if (strcmp(typeName, "decimal") == 0) + return SQLDECIMAL; + break; + case 'f': + if (strcmp(typeName, "float") == 0) + return SQLFLOAT; + break; + case 'i': + if (strcmp(typeName, "integer") == 0) + return SQLINT; + if (strcmp(typeName, "int8") == 0) + return SQLINT8; + break; + case 'l': + if (strcmp(typeName, "lvarchar") == 0) + return SQLLVARCHAR; + break; + case 'n': + if (strcmp(typeName, "nchar") == 0) + return SQLNCHAR; + if (strcmp(typeName, "nvarchar") == 0) + return SQLNVCHAR; + break; + case 's': + if (strcmp(typeName, "serial") == 0) + return SQLSERIAL; + if (strcmp(typeName, "serial8") == 0) + return SQLSERIAL8; + if (strcmp(typeName, "smallint") == 0) + return SQLSMINT; + if (strcmp(typeName, "smallfloat") == 0) + return SQLFLOAT; + break; + case 't': + if (strcmp(typeName, "text") == 0) + return SQLTEXT; + break; + case 'v': + if (strcmp(typeName, "varchar") == 0) + return SQLVCHAR; + break; + default: + break; + } + qWarning("Unknown informix data type '%s'", typeName); + return -1; +} + + +static inline qint64 getLastSerial(ITConnection *itconn) +{ + MI_CONNECTION *conn = itconn->CheckOutConn(); + + mi_integer lastSerial; + mi_last_serial(conn, &lastSerial); + if (lastSerial != 0) + { + itconn->CheckInConn(); + return lastSerial; + } + mi_int8 lastSerial8; + mi_last_serial8(conn, &lastSerial8); + itconn->CheckInConn(); + const quint64 low = static_cast(lastSerial8.data[0]); + const quint64 high = static_cast(lastSerial8.data[1]); + qint64 ret = (high << 32) + low; + return lastSerial8.sign == -1 ? -ret : ret; +} + + + + +class QInformixResultPrivate +{ +public: + QInformixResultPrivate(QInformixResult *qq) + : q(qq) + , driverPrivate(NULL) + , query(NULL) + , result(NULL) + , row(NULL) + , preparedStmt(NULL) + , preparedCursor(NULL) + , currentSize(-1) + , numAffectedRows(-1) + , lastInsertId(-1) + {} + + QInformixResult *q; + QInformixDriverPrivate *driverPrivate; + + ITQuery *query; + + ITSet *result; + + ITRow *row; + + + ITStatement *preparedStmt; + + ITCursor *preparedCursor; + + int currentSize; + int numAffectedRows; + qint64 lastInsertId; + + inline ITConnection *getConnection() const + { + return driverPrivate->connection; + } + void cleanupInternal() + { + q->cleanup(); + if (preparedStmt) + { + preparedStmt->Drop(); + delete preparedStmt; + preparedStmt = NULL; + } + if (preparedCursor) + { + preparedCursor->Drop(); + preparedCursor->Close(); + delete preparedCursor; + preparedCursor = NULL; + } + } +}; + + + + +QInformixResult::QInformixResult(const QInformixDriver *db, QInformixDriverPrivate *p) + : QSqlResult(db) +{ + DEBUG_FUNCTION + + p->addConnection(); + d = new QInformixResultPrivate(this); + d->driverPrivate = p; +} + +QInformixResult::~QInformixResult() +{ + DEBUG_FUNCTION + + d->cleanupInternal(); + d->driverPrivate->removeConnection(); + delete d; +} + +QVariant QInformixResult::handle() const +{ + DEBUG_FUNCTION + + return qVariantFromValue(d->result); +} + +void QInformixResult::cleanup() +{ + DEBUG_FUNCTION + + if (d->query) + { + d->query->Finish(); + delete d->query; + d->query = NULL; + } + if (d->result) + { + d->result->Close(); + d->result->Release(); + d->result = NULL; + } + if (d->row) + { + d->row->Release(); + d->row = NULL; + } + + setActive(false); +} + +bool QInformixResult::fetch(int i) +{ + + + if (!isActive()) + return false; + if (i < 0) + return false; + if (at() == i) + return true; + + if (d->row) + { + d->row->Release(); + d->row = NULL; + } + + if (d->result) + { + if (i >= d->currentSize) + return false; + + ITValue *value = d->result->Fetch(NULL, ITPositionAbsolute, i + 1); + + if (!value) + { + qDebug("QInformixResult::fetch(%d): Fetch failed\n", i); + return false; + } + + int ret = value->QueryInterface(ITRowIID, (void **) & d->row); + if (ret == IT_QUERYINTERFACE_FAILED) + { + value->Release(); + return false; + } + value->Release(); + } + else + { + if (!d->preparedCursor) + return false; + + if (isForwardOnly()) + d->row = d->preparedCursor->NextRow(); + else + d->row = d->preparedCursor->NextRow(NULL, ITPositionAbsolute, i + 1); + if (!d->row) + return false; + } + + setAt(i); + return true; +} + +bool QInformixResult::fetchFirst() +{ + return fetch(0); +} + +bool QInformixResult::fetchLast() +{ + return fetch(d->currentSize - 1); +} + +QVariant QInformixResult::data(int i) +{ + + + if (!d->row) + return QVariant(); + + if (i >= d->row->NumColumns()) + { + qWarning("QInformixResult::data: column %d out of range", i); + return QVariant(); + } + + ITValue *col = d->row->Column(i); + if (!col) + { + qWarning("QInformixResult::data: column %d out of range", i); + return QVariant(); + } + + const int sqlType = qIfxType2SqlType(col->TypeOf().Name()); + if (col->IsNull()) + { + col->Release(); + return QVariant(qSqlType2Variant(sqlType)); + } + + + + QVariant variant; + switch (sqlType) + { + case SQLBYTES: + { + ITDatum *lobj = NULL; + col->QueryInterface(ITDatumIID, (void **) &lobj); + variant = QByteArray((const char *) lobj->Data(), lobj->DataLength()); + lobj->Release(); + break; + } + case SQLTEXT: + { + ITDatum *lobj = NULL; + col->QueryInterface(ITDatumIID, (void **) &lobj); + const QByteArray ba = QByteArray((const char *) lobj->Data()); + variant = d->driverPrivate->fromInformixEncoding(ba); + lobj->Release(); + break; + } + case SQLCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLVCHAR: + case SQLLVARCHAR: + variant = QVariant(d->driverPrivate->fromInformixEncoding(col->Printable())); + break; + case SQLDATE: + { + ITDateTime *dt = NULL; + col->QueryInterface(ITDateTimeIID, (void **) &dt); + variant = QVariant(QDate(dt->Year(), dt->Month(), dt->Day())); + dt->Release(); + break; + } + case SQLDTIME: + { + ITDateTime *dt = NULL; + col->QueryInterface(ITDateTimeIID, (void **) &dt); + const QDate date(QDate(dt->Year(), dt->Month(), dt->Day())); + const int seconds = (int) truncf(dt->Second()); + const int msecs = (int) truncf((dt->Second() - seconds) * 1000); + const QTime time(QTime(dt->Hour(), dt->Minute(), seconds, msecs)); + variant = QVariant(QDateTime(date, time)); + dt->Release(); + break; + } + case SQLDECIMAL: + case SQLFLOAT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + double dbl; + conv->ConvertTo(dbl); + variant = QVariant(dbl); + conv->Release(); + break; + } + case SQLSERIAL: + case SQLINT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + int int32; + conv->ConvertTo(int32); + variant = QVariant(int32); + conv->Release(); + break; + } + case SQLSERIAL8: + case SQLINT8: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + long int int64; + conv->ConvertTo(int64); + variant = QVariant((qint64) int64); + conv->Release(); + break; + } + case SQLSMINT: + { + ITConversions *conv = NULL; + col->QueryInterface(ITConversionsIID, (void **) &conv); + short int int16; + conv->ConvertTo(int16); + variant = QVariant(int16); + conv->Release(); + break; + } + default: + variant = QVariant(qSqlType2Variant(sqlType)); + qWarning("QInformixResult::data: Unknown sql data type %d at row %d\n", sqlType, i); + break; + } + col->Release(); + + return variant; +} + +bool QInformixResult::isNull(int i) +{ + DEBUG_FUNCTION + + if (!d->row) + return true; + + if (i >= d->row->NumColumns()) + { + qWarning("QInformixResult::isNull: column %d out of range", i); + return true; + } + + ITValue *col = d->row->Column(i); + if (!col) + { + qWarning("QInformixResult::isNull: column %d out of range", i); + return false; + } + return col->IsNull(); +} + +bool QInformixResult::reset(const QString &query) +{ +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, " QInformixResult::reset(%s)\n", qPrintable(query)); +#endif + + d->cleanupInternal(); + + if (!driver()) + return false; + if (!driver()->isOpen() || driver()->isOpenError()) + return false; + + d->currentSize = -1; + d->numAffectedRows = -1; + d->lastInsertId = -1; + setSelect(false); + + d->query = new ITQuery(*d->getConnection()); + bool bIsSelect = query.trimmed().startsWith(QLatin1String("SELECT"), Qt::CaseInsensitive); + + try + { + if (bIsSelect) + { + d->result = d->query->ExecToSet(d->driverPrivate->toInformixEncoding(query)); + + if (!d->result || !d->result->Open()) + throw false; + + } + else + { + bool bOk = d->query->ExecForStatus(d->driverPrivate->toInformixEncoding(query)); + if (!bOk) + throw false; + } + + if (d->query->Error()) + throw false; + + } + catch (bool bOk) + { + if (!bOk) + { + setLastError(qMakeError(QObject::tr("Unable to create query"), + QSqlError::StatementError, d->driverPrivate)); + return false; + } + } + + setSelect(bIsSelect); + setActive(true); + if (bIsSelect) + d->currentSize = d->query->RowCount(); + else + d->numAffectedRows = d->query->RowCount(); + d->lastInsertId = getLastSerial(d->getConnection()); + + return true; +} + +int QInformixResult::size() +{ + return d->currentSize; +} + +int QInformixResult::numRowsAffected() +{ + DEBUG_FUNCTION + + return d->numAffectedRows; +} + +QVariant QInformixResult::lastInsertId() const +{ + return d->lastInsertId ? QVariant(d->lastInsertId) : QVariant(); +} + +QSqlRecord QInformixResult::record() const +{ + DEBUG_FUNCTION + + QSqlRecord info; + if (!isActive() || !isSelect()) + return info; + + if (!d->query && !d->preparedCursor) + return info; + + const ITTypeInfo *rowInfo = d->query ? d->query->RowType() : d->preparedCursor->RowType(); + const int count = rowInfo->ColumnCount(); + QSqlField f; + for (int i = 0; i < count; ++i) + { + const ITTypeInfo *colInfo = rowInfo->ColumnType(i); + const char *typeName = colInfo->Name(); + const int len = colInfo->Size(); + const int prec = colInfo->Precision(); + const int sqlType = qIfxType2SqlType(typeName); + + f.setName(d->driverPrivate->fromInformixEncoding(rowInfo->ColumnName(i))); + f.setLength(len == -1 ? prec : len); + f.setPrecision(len == -1 ? len : prec); + f.setType(qSqlType2Variant(sqlType)); + f.setSqlType(sqlType); + + if (f.type() == QVariant::Invalid) + qWarning("QInformixResult::record(): Unknown datatype %s", typeName); + + info.append(f); + } + return info; +} + + + +inline QString replaceAt(const QString &str) +{ + QString ret(str); + QChar *data = ret.data(); + const int len = str.length(); + + for (int i = 0; i < len; ++i) + { + if (data[i] == QLatin1Char('@')) + data[i] = QLatin1Char(':'); + } + return ret; +} + +bool QInformixResult::prepare(const QString &_query) +{ + QString query = replaceAt(_query.trimmed()); +#ifdef DEBUG_QSQL_INFORMIX + fprintf(stderr, "QInformixResult::prepare(%s)\n", qPrintable(query)); +#endif + + d->cleanupInternal(); + + bool bIsSelect = query.startsWith(QLatin1String("SELECT"), Qt::CaseInsensitive); + setSelect(bIsSelect); + if (bIsSelect) + { + d->preparedCursor = new ITCursor(*d->getConnection()); + + if (!d->preparedCursor->Prepare(d->driverPrivate->toInformixEncoding(query))) + { + setLastError(qMakeError(QObject::tr("Unable to prepare statement"), + QSqlError::StatementError, d->driverPrivate)); + delete d->preparedCursor; + d->preparedCursor = NULL; + return false; + } + } + else + { + d->preparedStmt = new ITStatement(*d->getConnection()); + + if (!d->preparedStmt->Prepare(d->driverPrivate->toInformixEncoding(query))) + { + setLastError(qMakeError(QObject::tr("Unable to prepare statement"), + QSqlError::StatementError, d->driverPrivate)); + delete d->preparedStmt; + d->preparedStmt = NULL; + return false; + } + } + setActive(true); + + return true; +} + +template +bool bindValues(T *prep, const QVector &boundValues, const QInformixResultPrivate *p, const QSqlDriver *driver) +{ + const int cnt = boundValues.count(); + + if (cnt != prep->NumParams()) + return false; + + QSqlField f; + for (int i = 0; i < cnt; ++i) + { + const QVariant &val = boundValues.at(i); + ITValue *param = prep->Param(i); + + if (val.type() == QVariant::ByteArray) + { + ITDatum *lobj; + + ITTypeInfo ti(*p->getConnection(), "byte"); + + ITMVDesc desc; + desc.vf_origtypeinfo = &ti; + desc.vf_connection = p->getConnection(); + desc.vf_typedesc = NULL; + desc.vf_preservedata = NULL; + desc.vf_outerunknown = NULL; + desc.vf_datalength = ti.Size(); + desc.vf_libmivaluetype = MI_NULL_VALUE; + desc.vf_data = NULL; + ITValue *v = ITFactoryList::DatumToValue(desc); + v->QueryInterface(ITDatumIID, (void **) & lobj); + + QByteArray ba = val.toByteArray(); + if (ba.size()) + lobj->SetData(ba.data(), ba.size()); + else + lobj->SetNull(); + prep->SetParam(i, lobj); + v->Release(); + lobj->Release(); + + } + else + { + const char *t = param->TypeOf().Name(); + if (strcmp(t, "text") == 0) + { + ITDatum *lobj; + + + + ITTypeInfo ti(*p->getConnection(), "byte"); + + ITMVDesc desc; + desc.vf_origtypeinfo = &ti; + desc.vf_connection = p->getConnection(); + desc.vf_typedesc = NULL; + desc.vf_preservedata = NULL; + desc.vf_outerunknown = NULL; + desc.vf_datalength = ti.Size(); + desc.vf_libmivaluetype = MI_NULL_VALUE; + desc.vf_data = NULL; + ITValue *v = ITFactoryList::DatumToValue(desc); + v->QueryInterface(ITDatumIID, (void **) & lobj); + + QByteArray ba = p->driverPrivate->toInformixEncodingBA(val.toString()); + if (ba.size()) + lobj->SetData(ba.data(), ba.size()); + else + lobj->SetNull(); + lobj->FromPrintable(ba.data()); + prep->SetParam(i, lobj); + v->Release(); + lobj->Release(); + + } + else + { + f.setType(val.type()); + f.setValue(val); + if (!param->FromPrintable(p->driverPrivate->toInformixEncoding(driver->formatValue(f)))) + return false; + } + } + param->Release(); + } + return true; +} + +bool QInformixResult::exec() +{ + DEBUG_FUNCTION + + if (isSelect()) + { + if (d->query) + return false; + if (!d->preparedCursor) + return false; + + cleanup(); + + setActive(true); + + const int openMode = isForwardOnly() ? ITCursor::ReadOnly : ITCursor::ReadOnly + ITCursor::Scrollable; + if (!bindValues(d->preparedCursor, boundValues(), d, driver()) || + !d->preparedCursor->Open(openMode)) + { + setLastError(qMakeError(QObject::tr("Unable to execute statement"), + QSqlError::StatementError, d->driverPrivate)); + d->preparedCursor->Drop(); + d->preparedCursor->Close(); + delete d->preparedCursor; + d->preparedCursor = NULL; + return false; + } + d->lastInsertId = -1; + d->numAffectedRows = -1; + d->currentSize = -1; + } + else + { + if (!d->preparedStmt) + return false; + + cleanup(); + + setActive(true); + + if (!bindValues(d->preparedStmt, boundValues(), d, driver()) || + !d->preparedStmt->Exec()) + { + setLastError(qMakeError(QObject::tr("Unable to execute statement"), + QSqlError::StatementError, d->driverPrivate)); + d->preparedStmt->Drop(); + delete d->preparedStmt; + d->preparedStmt = NULL; + return false; + } + d->currentSize = -1; + d->lastInsertId = getLastSerial(d->getConnection()); + d->numAffectedRows = d->preparedStmt->RowCount(); + } + return true; +} + + + + +QInformixDriver::QInformixDriver(QObject *parent) + : QSqlDriver(parent) +{ + init(); +} + +void QInformixDriver::init() +{ + d = new QInformixDriverPrivate(this); +} + +QInformixDriver::~QInformixDriver() +{ + if (d->connection) + close(); + delete d; +} + +QVariant QInformixDriver::handle() const +{ + return qVariantFromValue(d->connection); +} + +bool QInformixDriver::hasFeature(DriverFeature f) const +{ + switch (f) + { + case LastInsertId: + case Transactions: + case QuerySize: + case PreparedQueries: + return true; + case LowPrecisionNumbers: + case EventNotifications: + case SimpleLocking: + case FinishQuery: + case MultipleResultSets: + case PositionalPlaceholders: + case BatchOperations: + case NamedPlaceholders: + case CancelQuery: + return false; + case BLOB: + case Unicode: + return true; + } + return false; +} + +bool QInformixDriver::open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts) +{ + Q_UNUSED(port) + const QVector options = connOpts.splitRef(QLatin1Char(';')); + QString dbLocale = QStringLiteral("UTF-8"); + + d->connTimeout = -1; + d->connectOnFirstUse = false; + for (const QStringRef &opt : options) + { + if (opt.startsWith(QLatin1String("DB_LOCALE="))) + dbLocale = opt.mid(strlen("DB_LOCALE=")).toString(); + if (opt.startsWith(QLatin1String("CONN_TIMEOUT="))) + { + bool bOk; + d->connTimeout = opt.mid(strlen("CONN_TIMEOUT=")).toInt(&bOk); + if (bOk && d->connTimeout > 0) + { + d->connTimeout *= 1000; + QTimer::singleShot(d->connTimeout, this, SLOT(timeout())); + } + else + d->connTimeout = -1; + } + if (opt.startsWith(QLatin1String("CONNECT_ON_FIRST_USE="))) + { + bool bOk; + int val = opt.mid(strlen("CONNECT_ON_FIRST_USE=")).toInt(&bOk); + if (bOk) + d->connectOnFirstUse = (val != 0); + else + d->connectOnFirstUse = false; + } + } +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s connTimeout: %d\n", this, __PRETTY_FUNCTION__, d->connTimeout); +#endif + d->dbLocale = QTextCodec::codecForName(dbLocale.toUtf8()); + if (!d->dbLocale) + { + setLastError(qMakeError(tr("Can't create Codec for Name %1").arg(dbLocale), QSqlError::ConnectionError, d)); + setOpenError(true); + return false; + } + + if (isOpen()) + close(); + + if (!host.isEmpty()) + d->conn_params.SetSystem(d->toInformixEncoding(host)); + if (!db.isEmpty()) + d->conn_params.SetDatabase(d->toInformixEncoding(db)); + if (!user.isEmpty()) + d->conn_params.SetUser(d->toInformixEncoding(user)); + if (!password.isEmpty()) + d->conn_params.SetPassword(d->toInformixEncoding(password)); + d->conn_params.Freeze(); + + d->connection = new ITConnection(); + + if (d->connectOnFirstUse) + return true; + + return openDatabaseInternal(); +} + +bool QInformixDriver::openDatabaseInternal() +{ + int ret = d->connection->Open(d->conn_params); + + if (!ret || !d->connection->IsOpen()) + { + setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); + setOpenError(true); + d->connection->Close(); + delete d->connection; + d->connection = 0; + return false; + } + + setOpen(true); + setOpenError(false); + return true; +} + +void QInformixDriver::close() +{ + DEBUG_FUNCTION + + if (isOpen()) + { + d->connection->Close(); + setOpen(false); + setOpenError(false); + } + delete d->connection; + d->connection = 0; +} + +bool QInformixDriver::isOpen() const +{ + return (d->connection); + +} + +QSqlResult *QInformixDriver::createResult() const +{ + return new QInformixResult(this, d); +} + +QStringList QInformixDriver::tables(QSql::TableType type) const +{ + DEBUG_FUNCTION + + QStringList tl; + if (!isOpen()) + return tl; + QSqlQuery t(createResult()); + t.setForwardOnly(true); + + if (type == 0) + type = QSql::Tables; + QString cmd; + if ((type & (QSql::SystemTables | QSql::Tables)) == (QSql::SystemTables | QSql::Tables)) + cmd = QStringLiteral("select tabname from systables where tabid >= 0"); + else if ((type & QSql::SystemTables) == QSql::SystemTables) + cmd = QStringLiteral("select tabname from systables where tabid < 100"); + else + cmd = QStringLiteral("select tabname from systables where tabid >= 100"); + + if ((type & (QSql::Tables | QSql::Views)) == (QSql::Tables | QSql::Views)) + cmd += QStringLiteral(" and (tabtype = 'T' or tabtype = 'V')"); + else if ((type & QSql::Tables) == QSql::Tables) + cmd += QStringLiteral(" and tabtype = 'T'"); + else if ((type & QSql::Views) == QSql::Views) + cmd += QStringLiteral(" and tabtype = 'V'"); + cmd += QStringLiteral(" order by tabid"); + + t.exec(cmd); + while (t.next()) + tl.append(t.value(0).toString()); + + return tl; +} + +static void qSplitTableName(QString &tablename, QString &schema) +{ + int dot = tablename.indexOf(QLatin1Char('.')); + if (dot == -1) + return; + schema = tablename.left(dot); + tablename = tablename.mid(dot + 1); +} + +QSqlIndex QInformixDriver::primaryIndex(const QString &tablename) const +{ + QSqlIndex idx(tablename); + if (!isOpen()) + return idx; + QSqlQuery i(createResult()); + + QString tbl = tablename; + QString schema; + qSplitTableName(tbl, schema); + + QString cmd(QStringLiteral("select syscolumns.colname, syscolumns.coltype, si.idxname " + "from syscolumns " + "left outer join sysindexes si on syscolumns.tabid = si.tabid " + "where syscolumns.tabid = (select tabid from systables where tabname='%1') " + "and colno = (select part1 from sysindexes where tabid = ( " + "select tabid from systables where tabname='%1') " + "and idxname = (select idxname from sysconstraints where tabid=( " + "select tabid from systables where tabname='%1') " + "and constrtype='P'))" + )); + + i.exec(cmd.arg(tbl.toLower())); + while (i.isActive() && i.next()) + { + QSqlField f(i.value(0).toString(), qSqlType2Variant(i.value(1).toInt())); + idx.append(f); + idx.setName(i.value(2).toString()); + } + + return idx; +} + +QSqlRecord QInformixDriver::record(const QString &tablename) const +{ + QSqlRecord info; + if (!isOpen()) + return info; + + QString tbl = tablename; + QString schema; + qSplitTableName(tbl, schema); + + QString cmd(QStringLiteral("select " + "syscolumns.colname, syscolumns.coltype, syscolumns.collength " + "from systables, syscolumns " + "where systables.tabname = '%1' " + "and systables.tabid = syscolumns.tabid")); + + QSqlQuery query(createResult()); + query.exec(cmd.arg(tbl.toLower())); + + while (query.next()) + { + const int sqltype = query.value(1).toInt(); + QSqlField f(query.value(0).toString(), qSqlType2Variant(sqltype)); + f.setRequired((sqltype & SQLNONULL) == SQLNONULL); + f.setLength(query.value(2).toInt()); + + + f.setSqlType(sqltype & SQLTYPE); + f.setAutoValue((sqltype & SQLTYPE) == SQLSERIAL || (sqltype & SQLTYPE) == SQLSERIAL8); + + info.append(f); + } + + return info; +} + +QString QInformixDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const +{ + QString res = identifier; + res.replace(QLatin1Char('"'), QStringLiteral("\"\"")); + res.replace(QLatin1Char('.'), QStringLiteral("\".\"")); + return res; +} + +QString QInformixDriver::formatValue(const QSqlField &field, bool trimStrings) const +{ + QString r; + switch (field.type()) + { + case QVariant::DateTime: + if (field.value().toDateTime().isValid()) + { + const QDate dt = field.value().toDateTime().date(); + const QTime tm = field.value().toDateTime().time(); + + r = QString::number(dt.year()) + QLatin1Char('-') + + QString::number(dt.month()).rightJustified(2, QLatin1Char('0')) + QLatin1Char('-') + + QString::number(dt.day()).rightJustified(2, QLatin1Char('0')) + QLatin1Char(' ') + + tm.toString(); + + } + else + r = QStringLiteral("NULL"); + break; + case QVariant::Date: + if (field.value().toDate().isValid()) + { + const QDate dt = field.value().toDateTime().date(); + + r = QString::number(dt.year()) + QLatin1Char('-') + + QString::number(dt.month()).rightJustified(2, QLatin1Char('0')) + QLatin1Char('-') + + QString::number(dt.day()).rightJustified(2, QLatin1Char('0')); + + } + else + r = QStringLiteral("NULL"); + break; + case QVariant::String: + return trimStrings ? field.value().toString().trimmed() : field.value().toString(); + default: + return QSqlDriver::formatValue(field, trimStrings); + } + return r; +} + +bool QInformixDriver::beginTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::beginTransaction: Database not open"); + return false; + } + d->addConnection(); + + if (!d->connection->SetTransaction(ITConnection::Begin)) + { + setLastError(qMakeError(tr("Could not begin transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + return true; +} + +bool QInformixDriver::commitTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::commitTransaction: Database not open"); + return false; + } + + if (!d->connection->SetTransaction(ITConnection::Commit)) + { + setLastError(qMakeError(tr("Could not commit transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + d->removeConnection(); + return true; +} + +bool QInformixDriver::rollbackTransaction() +{ + if (!isOpen()) + { + qWarning("QInformixDriver::rollbackTransaction: Database not open"); + return false; + } + + if (!d->connection->SetTransaction(ITConnection::Abort)) + { + setLastError(qMakeError(tr("Could not rollback transaction"), + QSqlError::TransactionError, d)); + d->removeConnection(); + return false; + } + d->removeConnection(); + return true; +} + +void QInformixDriver::timeout() +{ +#ifdef DEBUG_AUTODISCONNECT + fprintf(stderr, "%p %s private: %p\n", this, __PRETTY_FUNCTION__, d); +#endif + d->closeConnection(); +} diff --git a/Z/src/qsql_informix/qsql_informix.h b/Z/src/qsql_informix/qsql_informix.h new file mode 100755 index 000000000..e1561105d --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.h @@ -0,0 +1,88 @@ + + + +#pragma once + +#include +#include + +#ifndef Q_EXPORT_SQLDRIVER_INFORMIX +# ifdef MAKE_QSQL_INFORMIX_LIB +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_EXPORT +# else +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_IMPORT +# endif +#endif + +class QInformixResultPrivate; +class QInformixDriverPrivate; +class QInformixDriver; + +class QInformixResult final : public QSqlResult +{ + friend class QInformixResultPrivate; +public: + QInformixResult(const QInformixDriver *db, QInformixDriverPrivate *p); + ~QInformixResult(); + + QVariant handle() const; + +protected: + void cleanup(); + bool fetch(int i); + bool fetchFirst(); + bool fetchLast(); + QVariant data(int i); + bool isNull(int field); + bool reset(const QString &query); + int size(); + int numRowsAffected(); + QSqlRecord record() const; + QVariant lastInsertId() const; + bool prepare(const QString &query); + bool exec(); + +private: + QInformixResultPrivate *d; +}; + +class Q_EXPORT_SQLDRIVER_INFORMIX QInformixDriver final : public QSqlDriver +{ + Q_OBJECT +public: + + explicit QInformixDriver(QObject *parent = nullptr); + ~QInformixDriver(); + bool hasFeature(DriverFeature f) const; + bool open(const QString &db, + const QString &user, + const QString &password, + const QString &host, + int port, + const QString &connOpts); + bool isOpen() const; + void close(); + + QSqlResult *createResult() const; + QStringList tables(QSql::TableType) const; + QSqlIndex primaryIndex(const QString &tablename) const; + QSqlRecord record(const QString &tablename) const; + + QVariant handle() const; + + QString escapeIdentifier(const QString &identifier, IdentifierType type) const; + QString formatValue(const QSqlField &field, bool trimStrings) const; + +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); + +private: + void init(); + bool openDatabaseInternal(); + QInformixDriverPrivate *d; + friend class QInformixDriverPrivate; +private Q_SLOTS: + void timeout(); +}; diff --git a/Z/src/qsql_informix/qsql_informix.json b/Z/src/qsql_informix/qsql_informix.json new file mode 100755 index 000000000..1079715d6 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "QInformix" ] +} diff --git a/Z/src/qsql_informix/qsql_informix_plugin.cpp b/Z/src/qsql_informix/qsql_informix_plugin.cpp new file mode 100755 index 000000000..28a5dbe69 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_plugin.cpp @@ -0,0 +1,28 @@ + + + +#include +#include "qsql_informix.h" + +class QInformixDriverPlugin final : public QSqlDriverPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "qsql_informix.json") +public: + QInformixDriverPlugin() = default; + + QSqlDriver *create(const QString &); +}; + +QSqlDriver *QInformixDriverPlugin::create(const QString &name) +{ + if (name == QLatin1String("QInformix")) + { + QInformixDriver *driver = new QInformixDriver(); + return driver; + } + return nullptr; +} + +#include "qsql_informix_plugin.moc" + diff --git a/Z/src/qsql_informix/qsql_informix_test.cpp b/Z/src/qsql_informix/qsql_informix_test.cpp new file mode 100755 index 000000000..03cb74d21 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_test.cpp @@ -0,0 +1,277 @@ + + + +#include +#include +#include +#include +#include +#include +#include + +#include "qsql_informix.h" +#include "qsql_informix_utils.h" + +class qsql_informix_test : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void connectDatabase(); + void createTestTable(); + void test_insert(); + void test_select(); + void test_prepare(); + void test_insert_blob(); + void test_select_blob(); + void test_transactions(); + void deleteTestTable(); + void createDB(); + void existsDB(); + void dropDB(); + +}; + +static QString informixServer() +{ + QByteArray srv = qgetenv("INFORMIXSERVER"); + if (srv.isEmpty()) + srv = "guezdbs1_tcp"; + return QString::fromLocal8Bit(srv); +} + +void qsql_informix_test::connectDatabase() +{ + QInformixDriver *drv = new QInformixDriver(); + QSqlDatabase db = QSqlDatabase::addDatabase(drv); + db.setHostName(informixServer()); + QByteArray sys_db = qgetenv("INFORMIXSYSDB"); + if (sys_db.isEmpty()) + sys_db = "int_sys_db"; + db.setDatabaseName(QString::fromLocal8Bit(sys_db)); + db.setUserName(QLatin1String("informix")); + db.setPassword(QLatin1String("informix")); + QByteArray sqlhosts = qgetenv("INFORMIXSQLHOSTS"); + QByteArray informixdir = qgetenv("INFORMIXDIR"); + qDebug() << "Conneting to" << informixServer() + << "database" << sys_db + << "with sqlhosts" << sqlhosts + << "and INFORMIXDIR" << informixdir; + bool bConnect = db.open(); + if (!bConnect) + qDebug() << "Error connecting:" << db.lastError(); + QVERIFY(bConnect); +} + +void qsql_informix_test::createTestTable() +{ + + QSqlQuery q1(QLatin1String("drop table qsql_informix_test")); + q1.exec(); + + QSqlQuery q2; + QString stmt(QLatin1String("create table qsql_informix_test (id int primary key, " + "text nchar(10), vartext varchar(10), text1 char(10), vartext1 varchar(10), blob byte, blobtext text)")); + QVERIFY(q2.exec(stmt)); +} + +void qsql_informix_test::test_insert() +{ + QSqlQuery q1; + QString stmt(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 1, 'text1', 'vartext1', 'text1', 'vartext1' )")); + QCOMPARE(q1.size(), -1); + QVERIFY(q1.exec(stmt)); + + QSqlQuery q2; + QVERIFY(q2.prepare(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( :id, :text, :vartext, :text, :vartext )"))); + q2.bindValue(QLatin1String(":id"), 2); + q2.bindValue(QLatin1String(":text"), QLatin1String("text2")); + q2.bindValue(QLatin1String(":vartext"), QLatin1String("vartext2")); + QVERIFY(q2.exec()); + QCOMPARE(q2.numRowsAffected(), 1); + + + QVERIFY(q2.prepare(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 3, 'text3', 'vartext3', 'text3', 'vartext3' )"))); + QVERIFY(q2.exec()); + + QSqlQuery q3(QLatin1String("insert into qsql_informix_test (id, text, vartext, text1, vartext1) values " + "( 4, 'text4', 'vartext4', 'text4', 'vartext4' )")); + QCOMPARE(q3.exec(), false); +} + +void qsql_informix_test::test_select() +{ + QSqlQuery q1(QLatin1String("select text from qsql_informix_test where id = 1")); + QCOMPARE(q1.size(), 1); + QVERIFY(q1.next()); + QCOMPARE(q1.value(0).toString(), QLatin1String("text1")); + + QSqlQuery q2(QLatin1String("select vartext from qsql_informix_test where id = 1")); + QVERIFY(q2.next()); + + QCOMPARE(q2.value(0).toString(), QLatin1String("vartext1")); + + QSqlQuery q3(QLatin1String("select vartext from qsql_informix_test")); + QVERIFY(q3.next()); + QCOMPARE(q3.size(), 4); + + QVERIFY(q3.prepare(QLatin1String("select vartext, text from qsql_informix_test"))); + QVERIFY(q3.exec()); + QVERIFY(q3.next()); + QCOMPARE(q3.value(0).toString(), QLatin1String("vartext1")); + QCOMPARE(q3.size(), -1); + + + QSqlQuery q4(QLatin1String("select text1 from qsql_informix_test where id = 1")); + QVERIFY(q4.next()); + QCOMPARE(q4.value(0).toString(), QLatin1String("text1")); + + + QSqlQuery q5(QLatin1String("select vartext1 from qsql_informix_test where id = 1")); + QVERIFY(q5.next()); + QCOMPARE(q5.value(0).toString(), QLatin1String("vartext1")); +} + +void qsql_informix_test::test_prepare() +{ + + +#if 0 + QSqlQuery q1; + QVERIFY(q1.prepare(QLatin1String("select * from qsql_informix_test"))); + QVERIFY(q1.exec()); + QCOMPARE(q1.size(), 3); +#endif +} + + +void qsql_informix_test::test_insert_blob() +{ + QSqlQuery q; + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blob) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 14); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'a')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 15); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'A')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 16); + q.bindValue(QLatin1String(":blob"), QByteArray(2, 'B')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("update qsql_informix_test set blobtext = :blob where id = :id"))); + q.bindValue(QLatin1String(":id"), 16); + q.bindValue(QLatin1String(":blob"), QByteArray(200, 'B')); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 17); + QString str = QString::fromUtf8("öäü"); + q.bindValue(QLatin1String(":blob"), str); + QVERIFY(q.exec()); + + QVERIFY(q.prepare(QLatin1String("insert into qsql_informix_test (id, blobtext) values (:id, :blob)"))); + q.bindValue(QLatin1String(":id"), 18); + str = QLatin1String("abcdefghjklimnopqrstuvwxyz"); + q.bindValue(QLatin1String(":blob"), str); + QVERIFY(q.exec()); +} + +void qsql_informix_test::test_select_blob() +{ + QSqlQuery q1(QLatin1String("select blob from qsql_informix_test where id = 14")); + QCOMPARE(q1.size(), 1); + QVERIFY(q1.next()); + QCOMPARE(q1.value(0).toByteArray(), QByteArray(200, 'a')); + + QSqlQuery q2(QLatin1String("select blobtext from qsql_informix_test where id = 15")); + QCOMPARE(q2.size(), 1); + QVERIFY(q2.next()); + QCOMPARE(q2.value(0).toByteArray(), QByteArray(200, 'A')); + + QSqlQuery q3(QLatin1String("select blobtext from qsql_informix_test where id = 16")); + QCOMPARE(q3.size(), 1); + QVERIFY(q3.next()); + QCOMPARE(q3.value(0).toByteArray(), QByteArray(200, 'B')); + + QSqlQuery q4(QLatin1String("select blobtext from qsql_informix_test where id = 17")); + QCOMPARE(q4.size(), 1); + QVERIFY(q4.next()); + QString str = QString::fromUtf8("öäü"); + QCOMPARE(q4.value(0).toString(), str); + + QSqlQuery q5(QLatin1String("select blobtext from qsql_informix_test where id = 18")); + QCOMPARE(q5.size(), 1); + QVERIFY(q5.next()); + str = QLatin1String("abcdefghjklimnopqrstuvwxyz"); + QCOMPARE(q5.value(0).toString(), str); +} + +void qsql_informix_test::test_transactions() +{ + QSqlDatabase db = QSqlDatabase::database(); + QVERIFY(db.transaction()); + QString stmt(QLatin1String("insert into qsql_informix_test (id, text, vartext) values " + "( 100, 'text1', 'vartext1' )")); + QSqlQuery q; + QVERIFY(q.exec(stmt)); + QVERIFY(db.commit()); + + QVERIFY(db.transaction()); + stmt = QLatin1String("insert into qsql_informix_test (id, text, vartext) values " + "( 101, 'text1', 'vartext1' )"); + QVERIFY(q.exec(stmt)); + QVERIFY(db.rollback()); + + stmt = QLatin1String("select * from qsql_informix_test where id = 101"); + QVERIFY(q.exec(stmt)); + QCOMPARE(q.size(), 0); +} + +void qsql_informix_test::deleteTestTable() +{ + QSqlQuery q; + QString stmt(QLatin1String("drop table qsql_informix_test")); + QVERIFY(q.exec(stmt)); +} + +void qsql_informix_test::createDB() +{ + QInformixUtils u; + + QVERIFY(u.createDatabase(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"), + QLatin1String("uebungsdaten_dbs"))); +} + +void qsql_informix_test::existsDB() +{ + QInformixUtils u; + QVERIFY(u.existsDbName(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"))); +} + +void qsql_informix_test::dropDB() +{ + QInformixUtils u; + QVERIFY(u.dropDatabase(informixServer(), + QLatin1String("newdatabase"), + QLatin1String("informix"), + QLatin1String("informix"))); +} + +QTEST_MAIN(qsql_informix_test) + +#include "qsql_informix_test.moc" diff --git a/Z/src/qsql_informix/qsql_informix_utils.cpp b/Z/src/qsql_informix/qsql_informix_utils.cpp new file mode 100755 index 000000000..433d37a83 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_utils.cpp @@ -0,0 +1,98 @@ + + + +#include "qsql_informix_utils.h" + + +#include +#include +#include +#include + +bool QInformixUtils::createDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd, const QString &dbspace) +{ + ITDBInfo info; + + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(newDb.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + bool bOk = info.CreateDatabase(ITDBInfo::Log, ITString(dbspace.toUtf8().constData())); + m_errortext = QString::fromLocal8Bit(info.ErrorText()); + m_sqlstate = QString::fromLocal8Bit(info.SqlState()); + + return bOk; +} + +bool QInformixUtils::dropDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd) +{ + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(newDb.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + bool bOk = info.DropDatabase(); + m_errortext = QString::fromLocal8Bit(info.ErrorText()); + m_sqlstate = QString::fromLocal8Bit(info.SqlState()); + + return bOk; +} + +QStringList QInformixUtils::dbListName(const QString &host, const QString &db, + const QString &user, const QString &passwd) +{ + QStringList sl; + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase(ITString(db.toUtf8().constData())); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + ITConnection connection; + bool bOk = connection.Open(info); + + if (!bOk) return sl; + + ITDBNameList nl; + bOk = nl.Create(); + + if (!bOk) + return sl; + + ITString dbName = nl.NextDBName(); + while (!dbName.IsNull()) + { + sl.append(QString::fromUtf8(dbName.Data())); + dbName = nl.NextDBName(); + } + + return sl; +} + +bool QInformixUtils::existsDbName(const QString &host, const QString &db, + const QString &user, const QString &passwd) +{ + ITDBInfo info; + info.SetSystem(ITString(host.toUtf8().constData())); + info.SetDatabase("sysmaster"); + info.SetUser(ITString(user.toUtf8().constData())); + info.SetPassword(ITString(passwd.toUtf8().constData())); + + ITConnection connection; + bool bOk = connection.Open(info); + + if (!bOk) return false; + + ITDBNameList nl; + if (!nl.Create()) + return false; + + if (nl.IsDBName(ITString(db.toUtf8().constData()))) + return true; + + return false; +} diff --git a/Z/src/qsql_informix/qsql_informix_utils.h b/Z/src/qsql_informix/qsql_informix_utils.h new file mode 100755 index 000000000..135508fc5 --- /dev/null +++ b/Z/src/qsql_informix/qsql_informix_utils.h @@ -0,0 +1,41 @@ + + + +#pragma once + +#include +#include + +#ifndef Q_EXPORT_SQLDRIVER_INFORMIX +# ifdef MAKE_QSQL_INFORMIX_LIB +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_EXPORT +# else +# define Q_EXPORT_SQLDRIVER_INFORMIX Q_DECL_IMPORT +# endif +#endif + +class Q_EXPORT_SQLDRIVER_INFORMIX QInformixUtils +{ + +public: + QInformixUtils() {} + ~QInformixUtils() {} + + bool createDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd, const QString &dbspace); + bool dropDatabase(const QString &host, const QString &newDb, + const QString &user, const QString &passwd); + + bool existsDbName(const QString &host, const QString &db, + const QString &user, const QString &passwd); + + QStringList dbListName(const QString &host, const QString &db, + const QString &user, const QString &passwd); + + QString errorText() const { return m_errortext; } + QString sqlState() const { return m_sqlstate; } + +private: + QString m_errortext; + QString m_sqlstate; +}; diff --git a/Z/src/tcpserver/CMakeLists.txt b/Z/src/tcpserver/CMakeLists.txt new file mode 100755 index 000000000..151a1d8b4 --- /dev/null +++ b/Z/src/tcpserver/CMakeLists.txt @@ -0,0 +1,56 @@ +# tcpserver +SET(tcp_SRCS + commandinterface.cpp + commandinterface.h + cbi_help.cpp + cbi_help.h + cbi_quit.cpp + cbi_quit.h + cbi_shutdown.cpp + cbi_shutdown.h + tcpserver.cpp + tcpserver.h + tcpserver_export.h + tcpserver_logger.h + workerbase.cpp + workerbase.h +) + +SET(tcp_HDRS +) + +NGL_ADD_LIBRARY(tcpserver AAR SV SHARED ${tcp_SRCS}) +NGL_TARGET_LINK_LIBRARIES(tcpserver + PRIVATE + Qt5::Network + ngltools + PUBLIC + Qt5::Core + NGLLogger +) +NGL_TARGET_INCLUDE_DIRECTORIES(tcpserver + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/../ +) +NGL_INSTALL_TARGET(tcpserver) + +IF(BUILD_TESTING AND BUILD_SV AND NOT WIN32) + LIST(APPEND tcp_test_SRCS + cbi_pingpong.cpp + cbi_pingpong.h + cbi_recvfile.cpp + cbi_recvfile.h + cbi_sendfile.cpp + cbi_sendfile.h + tcpserver_test.cpp + ) + + ADD_EXECUTABLE(tcpserver_test ${tcp_test_SRCS}) + TARGET_LINK_LIBRARIES(tcpserver_test + Qt5::Core + Qt5::Network + tcpserver + NGLLogger + ) +ENDIF() + diff --git a/Z/src/tcpserver/cbi_help.cpp b/Z/src/tcpserver/cbi_help.cpp new file mode 100755 index 000000000..209947254 --- /dev/null +++ b/Z/src/tcpserver/cbi_help.cpp @@ -0,0 +1,29 @@ + + + +#include "cbi_help.h" +#include "workerbase.h" + +#include +#include + +CBI_Help::CBI_Help(unsigned short port) + : CommandInterface(port, "HELP") +{} + +void CBI_Help::handleCommandInternal(const QVector &) +{ + const auto commands = workerBase()->getCommands(); + QStringList list; + list.reserve(commands.size()); + for (const CommandInterface *i : commands) + list += i->help(); + + std::sort(list.begin(), list.end()); + writeData(list.join(QLatin1Char('\n'))); +} + +QString CBI_Help::help() const +{ + return QLatin1String("HELP - prints out help informations"); +} diff --git a/Z/src/tcpserver/cbi_help.h b/Z/src/tcpserver/cbi_help.h new file mode 100755 index 000000000..6e49363d2 --- /dev/null +++ b/Z/src/tcpserver/cbi_help.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Help : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Help(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_pingpong.cpp b/Z/src/tcpserver/cbi_pingpong.cpp new file mode 100755 index 000000000..da6748e38 --- /dev/null +++ b/Z/src/tcpserver/cbi_pingpong.cpp @@ -0,0 +1,23 @@ + + + +#include "cbi_pingpong.h" + +CBI_PingPong::CBI_PingPong(unsigned short port) + : CommandInterface(port, "PING") +{} + +void CBI_PingPong::handleCommandInternal(const QVector &args) +{ + writeData("PONG"); + for (const QByteArray &ba : args) + { + writeData(" "); + writeData(quote(ba.constData())); + } +} + +QString CBI_PingPong::help() const +{ + return QString::fromUtf8("PING - mirror the Input and send the data back"); +} diff --git a/Z/src/tcpserver/cbi_pingpong.h b/Z/src/tcpserver/cbi_pingpong.h new file mode 100755 index 000000000..94f94e658 --- /dev/null +++ b/Z/src/tcpserver/cbi_pingpong.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class CBI_PingPong : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_PingPong(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_quit.cpp b/Z/src/tcpserver/cbi_quit.cpp new file mode 100755 index 000000000..891e9598d --- /dev/null +++ b/Z/src/tcpserver/cbi_quit.cpp @@ -0,0 +1,19 @@ + + + +#include "cbi_quit.h" + +CBI_Quit::CBI_Quit(unsigned short port) + : CommandInterface(port, "QUIT") +{} + +void CBI_Quit::handleCommandInternal(const QVector &) +{ + writeOk(QLatin1String("Bye!")); + closeConnection(); +} + +QString CBI_Quit::help() const +{ + return QLatin1String("QUIT - close the current connection"); +} diff --git a/Z/src/tcpserver/cbi_quit.h b/Z/src/tcpserver/cbi_quit.h new file mode 100755 index 000000000..33b15b756 --- /dev/null +++ b/Z/src/tcpserver/cbi_quit.h @@ -0,0 +1,19 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Quit : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Quit(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_recvfile.cpp b/Z/src/tcpserver/cbi_recvfile.cpp new file mode 100755 index 000000000..85425edcf --- /dev/null +++ b/Z/src/tcpserver/cbi_recvfile.cpp @@ -0,0 +1,86 @@ + + + +#include "cbi_recvfile.h" +#include "workerbase.h" + +#include +#include +#include +#include + +CBI_Recvfile::CBI_Recvfile(unsigned short port) + : CommandInterface(port, "RECV_FILE") +{} + +void CBI_Recvfile::handleCommandInternal(const QVector &args) +{ + if (args.count() != 2) + { + writeError(QLatin1String("Invalid arg count: RECV_FILE ")); + return; + } + + QString fn = QString::fromUtf8(args[0]); + int size; + getValue(args[1], size); + + QFile *f = new QFile(fn); + if (!f->open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + writeError(QStringLiteral("Could not open %1 for writing").arg(fn)); + return; + } + m_wbMap.insert(workerBase(), QPair(f, size)); + workerBase()->redirectDataHandling(true, this); +} + +void CBI_Recvfile::newPlainData() +{ + WorkerBase *wb = workerBase(); + QAbstractSocket *in = socket(); + QIODevice *out = m_wbMap[ wb ].first; + if (!out) + { + in->write("ERROR\n"); + + wb->redirectDataHandling(false); + return; + } + int size = m_wbMap[ wb ].second; + + + QByteArray ba(10, 0); + do + { + qint64 bytesRead = in->read(ba.data(), ba.size() < size ? ba.size() : size); + if (bytesRead < 0) + { + in->write("ERROR\n"); + + m_wbMap.remove(wb); + wb->redirectDataHandling(false); + return; + } + size -= bytesRead; + out->write(ba.constData(), bytesRead); + } + while (size > 0 && in->bytesAvailable()); + + + if (size != 0) + { + m_wbMap[ wb ].second = size; + return; + } + out->close(); + delete out; + + m_wbMap.remove(wb); + wb->redirectDataHandling(false); +} + +QString CBI_Recvfile::help() const +{ + return QLatin1String("RECV_FILE "); +} diff --git a/Z/src/tcpserver/cbi_recvfile.h b/Z/src/tcpserver/cbi_recvfile.h new file mode 100755 index 000000000..57a7b013d --- /dev/null +++ b/Z/src/tcpserver/cbi_recvfile.h @@ -0,0 +1,23 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" +#include +#include + +class QIODevice; +class CBI_Recvfile : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Recvfile(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; + void newPlainData() override; +protected: + QMap > m_wbMap; +}; diff --git a/Z/src/tcpserver/cbi_sendfile.cpp b/Z/src/tcpserver/cbi_sendfile.cpp new file mode 100755 index 000000000..8e6d8321e --- /dev/null +++ b/Z/src/tcpserver/cbi_sendfile.cpp @@ -0,0 +1,45 @@ + + + +#include "cbi_sendfile.h" +#include "workerbase.h" + +#include +#include +#include +#include + +CBI_Sendfile::CBI_Sendfile(unsigned short port) + : CommandInterface(port, "SEND_FILE") +{} + +void CBI_Sendfile::handleCommandInternal(const QVector &args) +{ + if (args.count() != 1) + { + writeError(QLatin1String("Invalid arg count: SEND_FILE ")); + return; + } + + QString fn = QString::fromUtf8(args[0]); + QFile f(fn); + if (!f.exists()) + { + writeError(QStringLiteral("File %1 does not exist").arg(fn)); + return; + } + if (!f.open(QIODevice::ReadOnly)) + { + writeError(QStringLiteral("Could not open file %1 for reading").arg(fn)); + return; + } + writeOk(QString::number(f.size())); + writeEOL(); + setAutoWriteEOL(false); + writeData(f.readAll()); +} + +QString CBI_Sendfile::help() const +{ + return QLatin1String("SEND_FILE "); +} diff --git a/Z/src/tcpserver/cbi_sendfile.h b/Z/src/tcpserver/cbi_sendfile.h new file mode 100755 index 000000000..adece8466 --- /dev/null +++ b/Z/src/tcpserver/cbi_sendfile.h @@ -0,0 +1,17 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + +class CBI_Sendfile : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Sendfile(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; +}; diff --git a/Z/src/tcpserver/cbi_shutdown.cpp b/Z/src/tcpserver/cbi_shutdown.cpp new file mode 100755 index 000000000..e923645e8 --- /dev/null +++ b/Z/src/tcpserver/cbi_shutdown.cpp @@ -0,0 +1,25 @@ + + + +#include "cbi_shutdown.h" +#include "tcpserver.h" + +CBI_Shutdown::CBI_Shutdown(unsigned short port) + : CommandInterface(port, "SHUTDOWN") +{ + connect(this, &CBI_Shutdown::shutdownRequest, + TcpServer::instance(port), &TcpServer::shutdownRequest); +} + +void CBI_Shutdown::handleCommandInternal(const QVector &) +{ + writeOk(QLatin1String("Shutting down server - bye!")); + closeConnection(); + emit shutdownRequest(); +} + +QString CBI_Shutdown::help() const +{ + return QLatin1String("SHUTDOWN - shut down the server"); +} + diff --git a/Z/src/tcpserver/cbi_shutdown.h b/Z/src/tcpserver/cbi_shutdown.h new file mode 100755 index 000000000..ed0ed2c93 --- /dev/null +++ b/Z/src/tcpserver/cbi_shutdown.h @@ -0,0 +1,25 @@ + + + +#pragma once + +#include "commandinterface.h" +#include "tcpserver_export.h" + + + +class TCPSERVER_EXPORT CBI_Shutdown : public CommandInterface +{ + Q_OBJECT +public: + explicit CBI_Shutdown(unsigned short port); + + void handleCommandInternal(const QVector &args) override; + QString help() const override; + +Q_SIGNALS: + + + void shutdownRequest(); +private: +}; diff --git a/Z/src/tcpserver/commandinterface.cpp b/Z/src/tcpserver/commandinterface.cpp new file mode 100755 index 000000000..eeedc31b1 --- /dev/null +++ b/Z/src/tcpserver/commandinterface.cpp @@ -0,0 +1,329 @@ + + + +#include "commandinterface.h" +#include "workerbase.h" +#include "tcpserver.h" +#include "tcpserver_logger.h" + +#include +#include +#include + +class CommandInterface::Private +{ +public: + explicit Private(unsigned short port_, const QByteArray &command_) + : command(command_) + , port(port_) + {} + + QByteArray m_connString; + QByteArray command; + QAbstractSocket *dev = nullptr; + WorkerBase *wb = nullptr; + int writeTimeout = 1000; + unsigned short port; + bool autoWriteEOL = true; + bool bWriteError = false; + bool closeConnection = false; + + static QByteArray defaultSuccessMessage; + static QByteArray defaultErrorMessage; +}; +QByteArray CommandInterface::Private::defaultSuccessMessage("OK"); +QByteArray CommandInterface::Private::defaultErrorMessage("ERROR"); + +CommandInterface::CommandInterface(unsigned short port, const QByteArray &command) + : d(new Private(port, command)) +{} + +CommandInterface::~CommandInterface() +{ + delete d; +} + +void CommandInterface::handleCommand(const QVector &args) +{ + Q_ASSERT(d->dev); + d->bWriteError = false; + d->closeConnection = false; + d->m_connString = WorkerBase::formatForDebug(d->dev); + handleCommandInternal(args); + if (d->autoWriteEOL) + writeEOL(); + d->dev->flush(); + if (d->closeConnection) + { + + d->dev->disconnectFromHost(); + + d->dev = nullptr; + } +} + +void CommandInterface::newPlainData() +{ + Q_ASSERT(false); + TCPSERVER_ERROR("CommandInterface::newData called which should never happen!"); +} + +void CommandInterface::writeData(const char *payload) +{ + writeData(QByteArray::fromRawData(payload, strlen(payload))); +} + +void CommandInterface::writeData(const QByteArray &payload) +{ + Q_ASSERT(d->dev); + + if (!d->dev->isOpen()) + return; + + if (!payload.size()) + return; + + TCPSERVER_DEBUG("Sending \'" << WorkerBase::formatForDebug(payload).constData() + << "\' (" << payload.size() << " Bytes) to " + << d->m_connString.constData()) + + qint64 bytesToWrite = payload.size(); + qint64 bytesWritten = 0; + do + { + bytesWritten += d->dev->write(&payload.data()[bytesWritten], bytesToWrite - bytesWritten); + if (!d->dev->waitForBytesWritten(d->writeTimeout)) + { + TCPSERVER_ERROR("waitForBytesWritten returned false for connection " + << d->m_connString.constData() + << " " + << d->dev->error() + << " " + << d->dev->errorString()) + d->bWriteError = true; + return; + } + } + while (bytesToWrite != bytesWritten); +} + +void CommandInterface::writeData(const QString &payload) +{ + writeData(payload.toUtf8()); +} + +void CommandInterface::writeData(const QList &payload) +{ + QByteArray cmd; + for (QByteArray s : payload) + { + s.replace('\"', "\\\""); + if (s.contains(' ')) + s = '"' + s + '"'; + cmd += s + ' '; + } + writeData(cmd); +} + +void CommandInterface::writeData(const QStringList &payload) +{ + QList baList; + baList.reserve(payload.size()); + for (const QString &ba : payload) + baList += ba.toUtf8(); + writeData(baList); +} + +void CommandInterface::writeOk(const QString &additionalMsg) +{ + writeData(Private::defaultSuccessMessage); + if (!additionalMsg.isEmpty()) + { + writeData(" "); + writeData(additionalMsg); + } +} + +void CommandInterface::writeError(const QString &additionalMsg) +{ + writeData(Private::defaultErrorMessage); + if (!additionalMsg.isEmpty()) + { + writeData(" "); + writeData(additionalMsg); + } +} + +void CommandInterface::writeEOL() +{ + writeData("\n"); + + Q_ASSERT(d->dev); + d->dev->flush(); +} + +QByteArray CommandInterface::quote(const QByteArray &payload) +{ + static const QByteArray escapedQuote("\""); + int idx = payload.indexOf(' '); + if (idx < 0) + return payload; + QByteArray ret = payload; + return escapedQuote + ret.replace('\"', "\\\"") + escapedQuote; +} + +QAbstractSocket *CommandInterface::socket() +{ + return d->dev; +} +void CommandInterface::setSocket(QAbstractSocket *socket) +{ + d->dev = socket; +} + +WorkerBase *CommandInterface::workerBase() +{ + return d->wb; +} + +void CommandInterface::setWorkerBase(WorkerBase *wb) +{ + d->wb = wb; +} + +QByteArray CommandInterface::command() const +{ + return d->command; +} + +void CommandInterface::setWriteTimeout(int iMS) +{ + d->writeTimeout = iMS < 0 ? 1000 : iMS; +} + +void CommandInterface::setAutoWriteEOL(bool newAutoWriteEOL) +{ + d->autoWriteEOL = newAutoWriteEOL; +} + +bool CommandInterface::autoWriteEOL() const +{ + return d->autoWriteEOL; +} + +bool CommandInterface::errorOccured() const +{ + return d->bWriteError; +} + +void CommandInterface::setDefaultSuccessMessage(const QString &msg) +{ + Private::defaultSuccessMessage = msg.isEmpty() ? "OK" : msg.toUtf8(); +} + +void CommandInterface::setDefaultErrorMessage(const QString &msg) +{ + Private::defaultErrorMessage = msg.isEmpty() ? "ERROR" : msg.toUtf8(); +} + +unsigned short CommandInterface::port() const +{ + return d->port; +} + +void CommandInterface::closeConnection() +{ + d->closeConnection = true; +} + +bool CommandInterface::socketIsOpen() const +{ + return d->dev && d->dev->isOpen(); +} + +void CommandInterface::conversionError(const QByteArray &arg, const QByteArray &type) +{ + writeError(QLatin1String("Can not convert ") + QString::fromUtf8(arg) + + QLatin1String(" to ") + QString::fromUtf8(type)); +} + +bool CommandInterface::getValue(const QByteArray &arg, bool &value) +{ + bool bOk; + int intValue; + + if (arg.startsWith("0x")) + intValue = arg.mid(2).toInt(&bOk, 16); + else + intValue = arg.toInt(&bOk); + if (!bOk) + conversionError(arg, "bool"); + value = (intValue != 0); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, long &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toLong(&bOk, 16); + else + value = arg.toLong(&bOk); + if (!bOk) + conversionError(arg, "long"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, unsigned long &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toULong(&bOk, 16); + else + value = arg.toUInt(&bOk); + if (!bOk) + conversionError(arg, "unsigned long"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, int &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toInt(&bOk, 16); + else + value = arg.toInt(&bOk); + if (!bOk) + conversionError(arg, "int"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, unsigned int &value) +{ + bool bOk; + if (arg.startsWith("0x")) + value = arg.mid(2).toUInt(&bOk, 16); + else + value = arg.toUInt(&bOk); + if (!bOk) + conversionError(arg, "unsigned int"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, float &value) +{ + bool bOk; + value = arg.toFloat(&bOk); + if (!bOk) + conversionError(arg, "float"); + return bOk; +} + +bool CommandInterface::getValue(const QByteArray &arg, double &value) +{ + bool bOk; + value = arg.toDouble(&bOk); + if (!bOk) + conversionError(arg, "double"); + return bOk; +} diff --git a/Z/src/tcpserver/commandinterface.h b/Z/src/tcpserver/commandinterface.h new file mode 100755 index 000000000..fd1026608 --- /dev/null +++ b/Z/src/tcpserver/commandinterface.h @@ -0,0 +1,158 @@ + + + + +#pragma once + +#include +#include +#include + +#include "tcpserver_export.h" + +class QAbstractSocket; +class QByteArray; +class WorkerBase; + + +class TCPSERVER_EXPORT CommandInterface : public QObject +{ + Q_OBJECT +public: + + + explicit CommandInterface(unsigned short port, const QByteArray &command = QByteArray()); + + + + virtual ~CommandInterface(); + + + void handleCommand(const QVector &args); + + + virtual void newPlainData(); + + + virtual QString help() const = 0; + + + QByteArray command() const; + + + + void setAutoWriteEOL(bool newAutoWriteEOL); + + + + bool autoWriteEOL() const; + + + + bool errorOccured() const; + + + + static void setDefaultSuccessMessage(const QString &msg); + + + + static void setDefaultErrorMessage(const QString &msg); + + template + static CommandInterface *factory(unsigned short port) { return new T(port); } + + + + virtual void aboutToDestroy() {} +protected: + + + virtual void handleCommandInternal(const QVector &args) = 0; + + + void setWriteTimeout(int iMS); + + + void writeData(const QByteArray &payload); + + + void writeData(const char *payload); + + + void writeData(const QString &payload); + + + void writeData(const QStringList &payload); + + + void writeData(const QList &payload); + + + void writeOk(const QString &additionalMsg = QString()); + + + void writeError(const QString &additionalMsg = QString()); + + + void writeEOL(); + + + QByteArray quote(const QByteArray &payload); + + + QAbstractSocket *socket(); + + + void setSocket(QAbstractSocket *socket); + + + WorkerBase *workerBase(); + + + void setWorkerBase(WorkerBase *wb); + + + void conversionError(const QByteArray &arg, const QByteArray &type); + + + bool getValue(const QByteArray &arg, bool &value); + + + bool getValue(const QByteArray &arg, long &value); + + + bool getValue(const QByteArray &arg, unsigned long &value); + + + bool getValue(const QByteArray &arg, int &value); + + + bool getValue(const QByteArray &arg, unsigned int &value); + + + bool getValue(const QByteArray &arg, float &value); + + + bool getValue(const QByteArray &arg, double &value); + + + + unsigned short port() const; + + + + void closeConnection(); + + + + bool socketIsOpen() const; + +private: + friend class WorkerBase; + + class Private; + + + Private *const d; +}; diff --git a/Z/src/tcpserver/tcpserver.cpp b/Z/src/tcpserver/tcpserver.cpp new file mode 100755 index 000000000..ae075b00a --- /dev/null +++ b/Z/src/tcpserver/tcpserver.cpp @@ -0,0 +1,209 @@ + + + +#include "tcpserver.h" +#include "tcpserver_logger.h" +#include "workerbase.h" + +#include +#include +#include +#include + +#include + +NGL::INGLLogger &getTcpServerLogger() +{ + static NGL::INGLLogger *tcpserver_logger_ptr = nullptr; + if (!tcpserver_logger_ptr) + tcpserver_logger_ptr = &NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("tcpserver"); + return *tcpserver_logger_ptr; +} + +typedef QHash< unsigned short, TcpServer::CommandInterfaceList > CommandFactory; +class TcpServer::Private +{ +public: + explicit Private(unsigned short port_) + : mUserData(nullptr) + , port(port_) + , bUseThreads(false) + {} + ~Private() + { + const auto copy(workers); + for (WorkerInstance *worker : copy) + { + + QThread *workerThread = worker->thread(); + if (workerThread != qApp->thread()) + { + QTimer::singleShot(0, worker, &WorkerInstance::deleteLater); + workerThread->wait(); + } + else + delete worker; + } + workers.clear(); + } + + QVector workers; + void *mUserData; + unsigned short port; + bool bUseThreads; + + static QHash s_servers; + static CommandFactory s_cbFactory; +}; +QHash TcpServer::Private::s_servers; +CommandFactory TcpServer::Private::s_cbFactory; + +TcpServer::TcpServer(unsigned short port) + : QTcpServer() + , d(new Private(port)) +{ + TCPSERVER_TRACE2("Port: " << port); +} + +TcpServer::~TcpServer() +{ + TCPSERVER_TRACE + Private::s_servers.remove(d->port); + delete d; +} + +TcpServer *TcpServer::instance(unsigned short port) +{ + if (!Private::s_servers.contains(port)) + Private::s_servers.insert(port, new TcpServer(port)); + + return Private::s_servers[ port ]; +} + +bool TcpServer::listen(const QHostAddress &address) +{ + TCPSERVER_TRACE2("address: " << address); + return QTcpServer::listen(address, d->port); +} + +void TcpServer::setUseWorkerThreads(bool bEnable) +{ + TCPSERVER_TRACE2("bEnable: " << bEnable); + d->bUseThreads = bEnable; +} + +bool TcpServer::useWorkerThreads() const +{ + return d->bUseThreads; +} + +QVector TcpServer::workers() const +{ + return d->workers; +} + +unsigned short TcpServer::getListenPort() const +{ + return d->port; +} + +bool TcpServer::registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)) +{ + CommandInterfaceList &factoryList = Private::s_cbFactory[port]; + if (factoryList.contains(factory)) + { + TCPSERVER_ERROR("Factory " << (void *)factory << " already registered!") + return false; + } + factoryList.append(factory); + TCPSERVER_DEBUG("Added Factory " << (void *)factory << " for port " << port) + return true; +} + +bool TcpServer::unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)) +{ + CommandInterfaceList &factoryList = Private::s_cbFactory[port]; + if (!factoryList.contains(factory)) + { + TCPSERVER_WARN("Trying to unregister factory " << (void *)factory << " for port " << port << " which is not registered!") + return false; + } + TCPSERVER_INFO("Removed Factory " << (void *)factory << " for port " << port) + factoryList.removeAll(factory); + return true; +} + +TcpServer::CommandInterfaceList TcpServer::registeredCommands(unsigned short port) +{ + return Private::s_cbFactory[port]; +} + +void TcpServer::incomingConnection(qintptr socketDescriptor) +{ + + WorkerInstance *worker = new WorkerInstance(socketDescriptor, d->port); + connect(worker, &WorkerInstance::finished, this, &TcpServer::workerFinished); + d->workers += worker; + + if (d->bUseThreads) + { + QThread *workerThread = new QThread(this); + + connect(workerThread, &QThread::started, worker, &WorkerInstance::doWork); + connect(workerThread, &QThread::finished, worker, &WorkerInstance::quit); + worker->moveToThread(workerThread); + + workerThread->start(); + + + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + TCPSERVER_DEBUG("Created new WorkerThread " << worker) + } + else + { + QTimer::singleShot(0, worker, &WorkerInstance::doWork); + TCPSERVER_DEBUG("Created new WorkerInstance " << worker) + } +} + +void TcpServer::workerFinished() +{ + WorkerInstance *wi = qobject_cast(sender()); + if (wi) + { + if (!d->workers.removeAll(wi)) + TCPSERVER_WARN("Got a signal that a worker exited, but could not find it in our list!") + wi->deleteLater(); + } + else + { + TCPSERVER_WARN("Got a signal that a worker exited, but it's neither a WorkerInstance nor WorkerThread!") + } +} + +void TcpServer::shutdownRequest() +{ + emit aboutToQuit(d->port); + for (WorkerBase *worker : qAsConst(d->workers)) + { + WorkerInstance *wi = dynamic_cast(worker); + if (wi) + { + wi->quit(); + while (!wi->isFinished()) + QCoreApplication::processEvents(); + } + } + close(); + deleteLater(); +} + +void TcpServer::setUserData(void *userData) +{ + d->mUserData = userData; +} + +void *TcpServer::userData() const +{ + return d->mUserData; +} diff --git a/Z/src/tcpserver/tcpserver.h b/Z/src/tcpserver/tcpserver.h new file mode 100755 index 000000000..3b3bd1381 --- /dev/null +++ b/Z/src/tcpserver/tcpserver.h @@ -0,0 +1,96 @@ + + + + +#pragma once + +#include + +#include "tcpserver_export.h" + +class WorkerInstance; +class CommandInterface; + + + +class TCPSERVER_EXPORT TcpServer : public QTcpServer +{ + Q_OBJECT +public: + typedef QVector CommandInterfaceList; +public: + + + virtual ~TcpServer(); + + + static TcpServer *instance(unsigned short port); + + + + bool listen(const QHostAddress &address = QHostAddress::Any); + + + + void setUseWorkerThreads(bool bEnable); + + + + bool useWorkerThreads() const; + + + + QVector workers() const; + + + + unsigned short getListenPort() const; + + + + static bool registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)); + + + + static bool unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short)); + + + + static CommandInterfaceList registeredCommands(unsigned short port); + + + + void setUserData(void *userData); + + + + void *userData() const; + +Q_SIGNALS: + + + void aboutToQuit(unsigned short port); + +public Q_SLOTS: + + + void shutdownRequest(); + + + void workerFinished(); + +protected: + void incomingConnection(qintptr socketDescriptor); + +private: + class Private; + + + Private *const d; + + explicit TcpServer(unsigned short port); + + + + bool listen(const QHostAddress &address, quint16 port); +}; diff --git a/Z/src/tcpserver/tcpserver_export.h b/Z/src/tcpserver/tcpserver_export.h new file mode 100755 index 000000000..ae0da04c9 --- /dev/null +++ b/Z/src/tcpserver/tcpserver_export.h @@ -0,0 +1,27 @@ + + +#ifndef TCPSERVER_EXPORT_H +#define TCPSERVER_EXPORT_H + +#include + +#define TCPSERVER_VERSION_MAJ 0 +#define TCPSERVER_VERSION_MIN 0 +#define TCPSERVER_VERSION_REL 3 +#define TCPSERVER_VERSION (((TCPSERVER_VERSION_MAJ) << 16) | ((TCPSERVER_VERSION_MIN) << 8) | (TCPSERVER_VERSION_REL)) + +#ifndef TCPSERVER_STATIC +# ifdef BUILD_STATIC_LIBRARIES +# define TCPSERVER_EXPORT +# else +# ifdef MAKE_TCPSERVER_LIB +# define TCPSERVER_EXPORT Q_DECL_EXPORT +# else +# define TCPSERVER_EXPORT Q_DECL_IMPORT +# endif +# endif +#else +# define TCPSERVER_EXPORT __attribute__((visibility("default"))) +#endif + +#endif diff --git a/Z/src/tcpserver/tcpserver_logger.h b/Z/src/tcpserver/tcpserver_logger.h new file mode 100755 index 000000000..492c8578d --- /dev/null +++ b/Z/src/tcpserver/tcpserver_logger.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#ifdef Q_CC_GNU +#define TCPSERVER_TRACE_FUNCTION __PRETTY_FUNCTION__ +#else +#define TCPSERVER_TRACE_FUNCTION __FUNCTION__ +#endif + +#include + +NGL::INGLLogger &getTcpServerLogger(); + +#ifdef TCPSERVER_ENABLE_TRACE +#define TCPSERVER_TRACE { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION; } +#define TCPSERVER_TRACE2(x) { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION << x; } +#else +#define TCPSERVER_TRACE +#define TCPSERVER_TRACE2(x) +#endif +#define TCPSERVER_DEBUG(y) { DEBUG_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_INFO(y) { INFO_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_WARN(y) { WARNING_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_ERROR(y) { ERROR_LOG (getTcpServerLogger()) << y; } +#define TCPSERVER_FATAL(y) { FATAL_LOG (getTcpServerLogger()) << y; } diff --git a/Z/src/tcpserver/tcpserver_test.cpp b/Z/src/tcpserver/tcpserver_test.cpp new file mode 100755 index 000000000..b3e649e65 --- /dev/null +++ b/Z/src/tcpserver/tcpserver_test.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +#include "tcpserver.h" +#include "cbi_help.h" +#include "cbi_pingpong.h" +#include "cbi_quit.h" +#include "cbi_recvfile.h" +#include "cbi_sendfile.h" +#include "cbi_shutdown.h" +#include "workerbase.h" + +int main(int argc, char **argv) +{ + NGL::NGLLoggerBootstrap::createNGLRootLogger("tcpserver_test.props", false); + + QCoreApplication app(argc, argv); + QSettings settings(QLatin1String("./settings.ini"), QSettings::IniFormat); + unsigned int port = settings.value(QLatin1String("port"), 4711).toInt(); + + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + TcpServer::registerCommand(port, CommandInterface::factory); + + TcpServer *tcpServer = TcpServer::instance(port); + tcpServer->setUseWorkerThreads(true); + + if (!tcpServer->listen(QHostAddress::LocalHost)) + { + qFatal("Error listening on port %d, error: %d", port, tcpServer->serverError()); + delete tcpServer; + return 1; + } + QObject::connect(tcpServer, &TcpServer::destroyed, &app, &QCoreApplication::quit); + + int ret = app.exec(); + return ret; +} diff --git a/Z/src/tcpserver/workerbase.cpp b/Z/src/tcpserver/workerbase.cpp new file mode 100755 index 000000000..83eab0270 --- /dev/null +++ b/Z/src/tcpserver/workerbase.cpp @@ -0,0 +1,304 @@ + + + +#include "workerbase.h" + +#include "commandinterface.h" +#include "tcpserver.h" +#include "tcpserver_logger.h" + +#include +#include +#include + +#include +#include +#include + +#include + +WorkerBase::WorkerBase(qintptr sd, unsigned short port) + : m_socketDescriptor(sd) + , m_connection(nullptr) + , m_port(port) + , m_bRedirectIncomingData(false) + , m_bRedirectDataHandler(nullptr) +{} + +QAbstractSocket *WorkerBase::connection() +{ + return m_connection; +} + +const QAbstractSocket *WorkerBase::connection() const +{ + return m_connection; +} + +void WorkerBase::newDataInternal() +{ + + if (m_bRedirectIncomingData) + { + if (m_bRedirectDataHandler) + m_bRedirectDataHandler->newPlainData(); + return; + } + + if (!m_connection || !m_connection->isOpen()) + return; + + while (m_connection && m_connection->canReadLine()) + { + QByteArray ba(2048, '\0'); + bool bGotEOL = false; + int iOffset = 0; + do + { + qint64 length = m_connection->readLine(ba.data() + iOffset, ba.size()); + if (length < 0) + { + TCPSERVER_ERROR("Error reading data from " << m_connString.constData() + << qPrintable(m_connection->errorString())) + return; + } + bGotEOL = ba.contains('\n'); + if (bGotEOL) + { + + ba.resize(iOffset + length); + } + else + { + + iOffset = ba.size(); + ba.resize(ba.size() * 2); + + memset(ba.data() + iOffset, 0, ba.size() - iOffset); + } + } + while (!bGotEOL); + + + while (ba.endsWith('\r') || ba.endsWith('\n')) + { + ba.data() [ba.size() - 1] = '\0'; + ba.resize(ba.size() - 1); + } + + int idx = ba.indexOf(' '); + if (idx == -1) + idx = ba.size(); + + QByteArray command = ba.left(idx); + if (command.isEmpty()) + { + TCPSERVER_DEBUG("Got empty command from connection " << m_connString.constData()) + continue; + } + + CommandMap::ConstIterator it = m_registeredCommands.constFind(command.toLower()); + if (it == m_registeredCommands.constEnd()) + { + TCPSERVER_WARN("Got unknown command " << formatForDebug(command).constData() + << " from connection " + << m_connString.constData()) + m_connection->write("UNKNOWN COMMAND "); + m_connection->write(command); + m_connection->write("\n"); + if (!m_connection->waitForBytesWritten(1000)) + { + TCPSERVER_WARN("waitForBytesWritten returned false for connection " + << m_connString.constData() + << " " + << m_connection->error() + << " " + << m_connection->errorString()) + } + } + else + { + TCPSERVER_DEBUG("Got command " << formatForDebug(command).constData() + << " from connection " + << m_connString.constData()) + + CommandInterface *interface = *it; + const QVector args = NGL::parseFromTelnet(ba, idx + 1); + interface->handleCommand(args); + if (interface->errorOccured()) + { + TCPSERVER_ERROR("Write error occured on connection " << m_connString.constData()) + } + } + + if (m_bRedirectIncomingData && m_connection && m_connection->bytesAvailable()) + { + if (m_bRedirectDataHandler) + m_bRedirectDataHandler->newPlainData(); + return; + } + } +} + +void WorkerBase::redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler) +{ + m_bRedirectIncomingData = bDoRedirect; + m_bRedirectDataHandler = newDataHandler; + + if (!bDoRedirect) + newDataInternal(); +} + +QByteArray WorkerBase::formatForDebug(const QByteArray &data) +{ + const int size = data.size(); + QByteArray ret; + ret.reserve(size); + for (int i = 0; i < size; ++i) + { + const unsigned char c = data[i]; + if (c < ' ' || c >= 0x7f) + ret += "\\x" + QByteArray::number(c, 16); + else + ret += c; + if (i > 31) + { + ret += "..."; + break; + } + } + return ret; +} + +WorkerBase::CommandMap WorkerBase::getCommands() const +{ + return m_registeredCommands; +} + +QByteArray WorkerBase::formatForDebug(const QAbstractSocket *dev) +{ + const QAbstractSocket *socket = qobject_cast(dev); + if (socket) + return socket->peerAddress().toString().toUtf8() + ":" + QByteArray::number(socket->peerPort()); + try + { + return typeid(*dev).name(); + } + catch (std::bad_typeid &e) + { + TCPSERVER_ERROR("TcpSocket null? - " << e.what()) + } + return ""; +} + +int WorkerBase::initCommands(unsigned short port) +{ + const TcpServer::CommandInterfaceList cbList = TcpServer::registeredCommands(port); + TcpServer::CommandInterfaceList::ConstIterator it = cbList.begin(); + TcpServer::CommandInterfaceList::ConstIterator end = cbList.end(); + for (; it != end; ++it) + { + CommandInterface *(*factory)(unsigned short) = *it; + CommandInterface *cbi = factory(port); + cbi->setWorkerBase(this); + cbi->setSocket(m_connection); + m_registeredCommands.insert(cbi->command().toLower(), cbi); + } + return m_registeredCommands.count(); +} + +void WorkerBase::cleanupCommands() +{ + CommandMap::ConstIterator it = m_registeredCommands.constBegin(); + CommandMap::ConstIterator end = m_registeredCommands.constEnd(); + for (; it != end; ++it) + { + if (*it) + { + (*it)->aboutToDestroy(); + (*it)->deleteLater(); + } + } + m_registeredCommands.clear(); +} + + + +WorkerInstance::WorkerInstance(qintptr sd, unsigned short port, QObject *parent) + : QObject(parent) + , WorkerBase(sd, port) + , m_bFinished(false) +{} + +WorkerInstance::~WorkerInstance() +{ + if (m_connection && m_connection->state() != QAbstractSocket::UnconnectedState) + { + m_connection->disconnectFromHost(); + if (m_connection) + m_connection->waitForDisconnected(); + } + cleanupCommands(); + + delete m_connection; + m_connection = nullptr; +} + +void WorkerInstance::doWork() +{ + m_connection = new QTcpSocket(this); + initCommands(m_port); + if (!m_connection->setSocketDescriptor(m_socketDescriptor)) + { + m_connString = formatForDebug(m_connection); + TCPSERVER_ERROR("Connection to " << m_connString.constData() + << " failed - Aborting (" + << m_connection->error() << ")") + return; + } + m_connString = formatForDebug(m_connection); + TCPSERVER_DEBUG("New incoming connection from " + << m_connString.constData() + << " to " << m_connection->localAddress().toString().toUtf8().constData() + << ":" << m_connection->localPort()); + connect(m_connection.data(), &QTcpSocket::readyRead, this, &WorkerInstance::newData); + connect(m_connection.data(), &QTcpSocket::disconnected, this, &WorkerInstance::connectionDisconnected); +} + +void WorkerInstance::newData() +{ + WorkerBase::newDataInternal(); +} + +void WorkerInstance::connectionDisconnected() +{ + TCPSERVER_DEBUG(m_connString.constData() << " closed - exiting instance " << this); + if (m_connection) + m_connection->deleteLater(); + m_connection = nullptr; + m_bFinished = true; + + QThread *workerThread = QThread::currentThread(); + if (workerThread != qApp->thread()) + { + workerThread->disconnect(this); + workerThread->quit(); + } + emit finished(); +} + +bool WorkerInstance::isRunning() const +{ + return m_connection && m_connection->isOpen(); +} + +bool WorkerInstance::isFinished() const +{ + return m_bFinished; +} + +void WorkerInstance::quit() +{ + if (m_connection) + m_connection->close(); +} diff --git a/Z/src/tcpserver/workerbase.h b/Z/src/tcpserver/workerbase.h new file mode 100755 index 000000000..f42806f2c --- /dev/null +++ b/Z/src/tcpserver/workerbase.h @@ -0,0 +1,127 @@ + + + +#pragma once + +#include +#include +#include + +#include "tcpserver_export.h" + +class QAbstractSocket; +class CommandInterface; + + + +class TCPSERVER_EXPORT WorkerBase +{ +public: + typedef QMap< QByteArray, CommandInterface *> CommandMap; +public: + + + WorkerBase(qintptr sd, unsigned short port); + + + virtual ~WorkerBase() = default; + + + QAbstractSocket *connection(); + + + + const QAbstractSocket *connection() const; + + + + void redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler = nullptr); + + + + static QByteArray formatForDebug(const QByteArray &data); + + + + static QByteArray formatForDebug(const QAbstractSocket *dev); + + + + CommandMap getCommands() const; + +protected: + + + void newDataInternal(); + + + int initCommands(unsigned short port); + + + + void cleanupCommands(); + + + + qintptr m_socketDescriptor; + + + QPointer m_connection; + + + unsigned short m_port; + + + QByteArray m_connString; + + + bool m_bRedirectIncomingData; + + + CommandInterface *m_bRedirectDataHandler; + + + + CommandMap m_registeredCommands; +}; + + + +class WorkerInstance final : public QObject, public WorkerBase +{ + Q_OBJECT +public: + WorkerInstance(qintptr sd, unsigned short port, QObject *parent = nullptr); + virtual ~WorkerInstance(); + + + + bool isRunning() const; + + + bool isFinished() const; + +public Q_SLOTS: + + + void quit(); + + + + void doWork(); + +protected Q_SLOTS: + + + void newData(); + + + void connectionDisconnected(); + +Q_SIGNALS: + void finished(); + +private: + bool m_bFinished; +}; + diff --git a/cmake/DoxygenMacros.cmake b/cmake/DoxygenMacros.cmake new file mode 100755 index 000000000..6fdf455c8 --- /dev/null +++ b/cmake/DoxygenMacros.cmake @@ -0,0 +1,22 @@ + + + + + + + + + + +FIND_PROGRAM(DOXYGEN_EXECUTABLE doxygen) + +MACRO(ADD_DOXYGEN_TARGET target input output infile outdir) + IF(DOXYGEN_EXECUTABLE-NOTFOUND) + MESSAGE(STATUS "Doxygen executable not found - can't create doxygen documentation") + ELSE(DOXYGEN_EXECUTABLE-NOTFOUND) + CONFIGURE_FILE(${input} ${output}) + ADD_CUSTOM_TARGET(doxygen_${target} doxygen ${output} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${infile} ${outdir} + ) + ENDIF(DOXYGEN_EXECUTABLE-NOTFOUND) +ENDMACRO(ADD_DOXYGEN_TARGET target) diff --git a/cmake/FindArcGIS.cmake b/cmake/FindArcGIS.cmake new file mode 100755 index 000000000..5f04b4605 --- /dev/null +++ b/cmake/FindArcGIS.cmake @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + +IF(ARCGIS_INCLUDE_DIR AND ARCGIS_LIBRARY) + SET(ARCGIS_FOUND TRUE) +ELSE() + + INCLUDE(FindLibraryWithDebug) + INCLUDE(FindPackageHandleStandardArgs) + + SET(QT_MIN_VERSION 5.4.0) + FIND_PACKAGE(Qt5 COMPONENTS Core Gui Location Network Sensors REQUIRED) + + SET(_arcgis_include_hint "/usr/include") + SET(_arcgis_library_hint "/usr/lib64") + + SET(_arcgis_lib_dir $ENV{ARCGIS_LIB_DIR}) + SET(_arcgis_inc_dir $ENV{ARCGIS_INC_DIR}) + IF (NOT ${_arcgis_lib_dir} STREQUAL "") + SET(_arcgis_library_hint "${_arcgis_lib_dir}") + ENDIF() + IF (NOT ${_arcgis_inc_dir} STREQUAL "") + SET(_arcgis_include_hint "${_arcgis_inc_dir}") + ENDIF() + IF(WIN32) + GET_FILENAME_COMPONENT(_arcgis_root_path "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\ESRI\\ArcGISRuntimeQt100.0.0;InstallDir]" ABSOLUTE) + IF(_arcgis_root_path) + SET(_arcgis_include_hint "${_arcgis_root_path}/sdk/windows/include/") + SET(_arcgis_library_hint "${_arcgis_root_path}/sdk/windows/x86/lib/") + ELSE() + SET(_root "$ENV{KDEROOT}") + FILE(TO_CMAKE_PATH "${_root}" _root) + IF(NOT EXISTS "${_root}" OR NOT IS_DIRECTORY "${_root}") + SET(_root $ENV{WORKSPACE}) + FILE(TO_CMAKE_PATH "${_root}" _root) + ENDIF() + IF(NOT EXISTS "${_root}" OR NOT IS_DIRECTORY "${_root}") + SET(_root ${EXTERNAL_LIBRARY_DIR}) + FILE(TO_CMAKE_PATH "${_root}" _root) + ENDIF() + SET(_arcgis_include_hint "${_root}/include/") + SET(_arcgis_library_hint "${_root}/lib/") + ENDIF() + ENDIF() + + FIND_PATH(ARCGIS_INCLUDE_DIR arcgis/ArcGISQt_global.h HINTS ${_arcgis_include_hint}) + FIND_LIBRARY_WITH_DEBUG(ARCGIS_LIBRARY WIN32_DEBUG_POSTFIX d NAMES EsriRuntimeQt HINTS ${_arcgis_library_hint}) + + FIND_LIBRARY_WITH_DEBUG(ARCGIS_COMMON_LIBRARY WIN32_DEBUG_POSTFIX d NAMES EsriCommonQt HINTS ${_arcgis_library_hint}) + IF (UNIX) + + FIND_LIBRARY_WITH_DEBUG(ARCGIS_CPP_LIBRARY WIN32_DEBUG_POSTFIX d NAMES runtimecore HINTS ${_arcgis_library_hint}) + ENDIF() + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(ArcGIS DEFAULT_MSG ARCGIS_LIBRARY ARCGIS_INCLUDE_DIR) + + MARK_AS_ADVANCED(ARCGIS_INCLUDE_DIR ARCGIS_LIBRARY) +ENDIF() + +IF(NOT TARGET ArcGIS::ArcGIS) + ADD_LIBRARY(ArcGIS::ArcGIS UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ARCGIS_INCLUDE_DIR}") + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${ARCGIS_INCLUDE_DIR}") + + IF(ARCGIS_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION_RELEASE "${ARCGIS_LIBRARY_RELEASE}") + ENDIF() + IF(ARCGIS_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION_DEBUG "${ARCGIS_LIBRARY_DEBUG}") + ENDIF() + IF(NOT ARCGIS_LIBRARY_RELEASE AND NOT ARCGIS_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY IMPORTED_LOCATION "${ARCGIS_LIBRARY}") + ENDIF() + + SET_PROPERTY(TARGET ArcGIS::ArcGIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ + $ + $ + $ + ) + + IF (UNIX) + IF(ARCGIS_COMMON_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_COMMON_LIBRARY_RELEASE}">) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_CPP_LIBRARY_RELEASE}">) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_COMMON_LIBRARY_DEBUG}">) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:"${ARCGIS_CPP_LIBRARY_DEBUG}">) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY AND NOT ARCGIS_COMMON_LIBRARY_RELEASE AND NOT ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${ARCGIS_COMMON_LIBRARY}" "${ARCGIS_CPP_LIBRARY}") + ENDIF() + ELSE() + IF(ARCGIS_COMMON_LIBRARY_RELEASE) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_RELEASE}>) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_RELEASE}>) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<$:${ARCGIS_COMMON_LIBRARY_DEBUG}>) + ENDIF() + IF(ARCGIS_COMMON_LIBRARY AND NOT ARCGIS_COMMON_LIBRARY_RELEASE AND NOT ARCGIS_COMMON_LIBRARY_DEBUG) + SET_PROPERTY(TARGET ArcGIS::ArcGIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${ARCGIS_COMMON_LIBRARY}") + ENDIF() + ENDIF() +ENDIF() diff --git a/cmake/FindBgViewer.cmake b/cmake/FindBgViewer.cmake new file mode 100755 index 000000000..624930cd9 --- /dev/null +++ b/cmake/FindBgViewer.cmake @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(FindPackageHandleStandardArgs) +INCLUDE(FindLibraryWithDebug) + +FIND_LIBRARY_WITH_DEBUG(BGVIEWER_DTENTITY_LIBRARY WIN32_DEBUG_POSTFIX d dtEntity) +FIND_LIBRARY_WITH_DEBUG(BGVIEWER_DTENTITYOSG_LIBRARY WIN32_DEBUG_POSTFIX d dtEntityOSG) +FIND_PATH(BGVIEWER_INCLUDE_DIR dtEntity/export.h) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(BgViewer DEFAULT_MSG + BGVIEWER_DTENTITY_LIBRARY + BGVIEWER_DTENTITYOSG_LIBRARY + BGVIEWER_INCLUDE_DIR) +SET(BGVIEWER_LIBRARIES ${BGVIEWER_DTENTITYOSG_LIBRARY} + ${BGVIEWER_DTENTITY_LIBRARY}) diff --git a/cmake/FindBotan2.cmake b/cmake/FindBotan2.cmake new file mode 100755 index 000000000..684546bd0 --- /dev/null +++ b/cmake/FindBotan2.cmake @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + +include(FindPkgConfig) + +if(NOT BOTAN_FOUND) + pkg_check_modules(Botan botan-2) +endif() + +if(NOT BOTAN_FOUND) + find_path(BOTAN_INCLUDE_DIRS NAMES botan/botan.h + PATH_SUFFIXES botan-2 + DOC "The botan include directory") + + find_library(BOTAN_LIBRARIES NAMES botan botan-2 + DOC "The botan library") + + + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Botan REQUIRED_VARS BOTAN_LIBRARIES BOTAN_INCLUDE_DIRS) + + if(BOTAN_FOUND) + set(BOTAN_LIBRARY ${BOTAN_LIBRARIES} CACHE INTERNAL "") + set(BOTAN_INCLUDE_DIR ${BOTAN_INCLUDE_DIRS} CACHE INTERNAL "") + set(BOTAN_FOUND ${BOTAN_FOUND} CACHE INTERNAL "") + endif() +endif() + +mark_as_advanced(BOTAN_INCLUDE_DIRS BOTAN_LIBRARIES) diff --git a/cmake/FindKDChart.cmake b/cmake/FindKDChart.cmake new file mode 100755 index 000000000..f4a434bb3 --- /dev/null +++ b/cmake/FindKDChart.cmake @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + +IF(KDCHART_INCLUDE_DIRS AND KDCHART_LIBRARY) + SET(KDCHART_FOUND TRUE) +ELSE() + + FIND_PATH(KDCHART_INCLUDE_DIRS KDChart/kdchart_export.h) + FIND_LIBRARY(KDCHART_LIBRARY NAMES kdchart) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(KDChart DEFAULT_MSG KDCHART_LIBRARY KDCHART_INCLUDE_DIRS) + + MARK_AS_ADVANCED(KDCHART_INCLUDE_DIRS KDCHART_LIBRARY) +ENDIF() + +IF(NOT TARGET KDChart::KDChart) + ADD_LIBRARY(KDChart::KDChart UNKNOWN IMPORTED) + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${KDCHART_INCLUDE_DIRS}") + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${KDCHART_INCLUDE_DIRS}") + SET_PROPERTY(TARGET KDChart::KDChart PROPERTY IMPORTED_LOCATION "${KDCHART_LIBRARY}") +ENDIF() diff --git a/cmake/FindKDReports.cmake b/cmake/FindKDReports.cmake new file mode 100755 index 000000000..42c58a9f3 --- /dev/null +++ b/cmake/FindKDReports.cmake @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + +FIND_PACKAGE(Qt5 COMPONENTS Core Gui PrintSupport Sql Svg Widgets Xml REQUIRED) +IF(KDREPORTS_INCLUDE_DIR AND KDREPORTS_KDREPORTS_INCLUDE_DIR AND KDREPORTS_LIBRARY) + SET(KDREPORTS_FOUND TRUE) +ELSE() + + FIND_PATH(KDREPORTS_INCLUDE_DIR KDReports/KDReports.h) + FIND_PATH(KDREPORTS_KDREPORTS_INCLUDE_DIR KDReports.h PATH_SUFFIXES KDReports) + FIND_LIBRARY(KDREPORTS_LIBRARY NAMES kdreports) + + 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() + +IF(NOT TARGET KDReports::KDReports) + ADD_LIBRARY(KDReports::KDReports UNKNOWN IMPORTED) + 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 IMPORTED_LOCATION "${KDREPORTS_LIBRARY}") + SET_PROPERTY(TARGET KDReports::KDReports APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qt5::Core Qt5::Gui Qt5::PrintSupport Qt5::Widgets) +ENDIF() diff --git a/cmake/FindLibraryWithDebug.cmake b/cmake/FindLibraryWithDebug.cmake new file mode 100755 index 000000000..90101b0a2 --- /dev/null +++ b/cmake/FindLibraryWithDebug.cmake @@ -0,0 +1,113 @@ + + + + + + + + + + + +MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname) + + IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") + + + FIND_LIBRARY(${var_name} + ${win32_dbg_postfix_name} + ${dgb_postfix} + ${libname} + ${ARGN} + ) + + ELSE() + + IF(NOT WIN32) + + + FIND_LIBRARY(${var_name} ${libname} ${ARGN}) + + ELSE() + + + SET(args ${ARGN}) + SET(newargs "") + SET(libnames_release "") + SET(libnames_debug "") + + IF("${libname}" STREQUAL "NAMES") + SET(append_rest 0) + LIST(LENGTH args listCount) + LIST(APPEND args " ") + + FOREACH(i RANGE ${listCount}) + LIST(GET args ${i} val) + + IF(append_rest) + LIST(APPEND newargs ${val}) + ELSE() + IF(${val} STREQUAL "PATHS" OR ${val} STREQUAL "HINTS") + LIST(APPEND newargs ${val}) + SET(append_rest 1) + ELSE() + LIST(APPEND libnames_release "${val}") + LIST(APPEND libnames_debug "${val}${dgb_postfix}") + ENDIF() + ENDIF() + + ENDFOREACH() + + ELSE() + + + LIST(APPEND libnames_release "${libname}") + LIST(APPEND libnames_debug "${libname}${dgb_postfix}") + + SET(newargs ${args}) + + ENDIF() + + + FIND_LIBRARY(${var_name}_RELEASE + NAMES ${libnames_release} + ${newargs} + ) + + + FIND_LIBRARY(${var_name}_DEBUG + NAMES ${libnames_debug} + ${newargs} + ) + + IF(${var_name}_RELEASE AND ${var_name}_DEBUG) + + + SET(${var_name} optimized ${${var_name}_RELEASE} + debug ${${var_name}_DEBUG}) + + ELSE() + + IF(${var_name}_RELEASE) + + + SET(${var_name} ${${var_name}_RELEASE}) + + ELSE() + + + SET(${var_name} ${${var_name}_DEBUG}) + + ENDIF() + + ENDIF() + + MARK_AS_ADVANCED(${var_name}_RELEASE) + MARK_AS_ADVANCED(${var_name}_DEBUG) + + ENDIF() + + ENDIF() + +ENDMACRO() + diff --git a/cmake/FindNGS.cmake b/cmake/FindNGS.cmake new file mode 100755 index 000000000..4838a511e --- /dev/null +++ b/cmake/FindNGS.cmake @@ -0,0 +1,134 @@ + + + + +IF(NGS_INCLUDE_DIRS AND NGS_LIBRARIES) + SET(NGS_FOUND TRUE) +ELSE() + + SET(FOM_NAME "RPRFOM20d17E") + IF("$ENV{NGS_ROOT}" STREQUAL "") + SET(NGS_ROOT "/opt/NGS/NGSPublic") + MESSAGE(STATUS "NGS_ROOT env var not set - using ${NGS_ROOT}") + ELSE() + SET(NGS_ROOT "$ENV{NGS_ROOT}") + ENDIF() + + FIND_PROGRAM(NGS_FOMBUILD fombuild + PATHS ${NGS_ROOT}/exe + ) + FIND_PATH(NGS_INCLUDE_DIR NGSUtils/SimTime.h + PATHS ${NGS_ROOT}/include + ) + FIND_PATH(NGS_SM_INCLUDE_DIR ISystem.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES SimulationManager + ) + FIND_PATH(NGS_FC_INCLUDE_DIR IRTIAmbassador.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES RTIFacadeAPI + ) + FIND_PATH(NGS_GE_INCLUDE_DIR SimulatedWorldAPI.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES SWGeneral + ) + FIND_PATH(NGS_UT_INCLUDE_DIR NGSConfig.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES NGSUtils + ) + FIND_PATH(NGS_PF_INCLUDE_DIR configureBool.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES NGSPlatformConfigure + ) + + FIND_PATH(NGS_FOM_INCLUDE_DIR WorldLocationStruct.h + PATHS ${NGS_INCLUDE_DIR} + PATH_SUFFIXES sw${FOM_NAME}/rpr + PATH_SUFFIXES sw${FOM_NAME}/rpr2 + ) + + FIND_LIBRARY(NGS_LIBRARY NGS + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_SWGENERAL SWGENERAL + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_UTILS NGSUtils + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(FOM_LIBRARY SW${FOM_NAME} + PATHS ${NGS_ROOT}/lib + PATHS ${NGS_ROOT}/lib64 + ) + FIND_LIBRARY(NGS_LIBRARY_CORBA CorbaNotify + PATHS ${NGS_ROOT}/lib/CorbaNotifyCdr + ) + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(NGS DEFAULT_MSG NGS_LIBRARY + NGS_LIBRARY_SWGENERAL + NGS_LIBRARY_UTILS + NGS_LIBRARY_CORBA + FOM_LIBRARY + NGS_SM_INCLUDE_DIR + NGS_FC_INCLUDE_DIR + NGS_GE_INCLUDE_DIR + NGS_UT_INCLUDE_DIR + ) + SET(NGS_INCLUDE_DIRS + ${NGS_INCLUDE_DIR} + ${NGS_SM_INCLUDE_DIR} + ${NGS_FC_INCLUDE_DIR} + ${NGS_GE_INCLUDE_DIR} + ${NGS_UT_INCLUDE_DIR} + ${NGS_PF_INCLUDE_DIR} + ${NGS_FOM_INCLUDE_DIR} + CACHE STRING "All ngs include dirs" FORCE + ) + SET(NGS_LIBRARIES + ${NGS_LIBRARY} + ${NGS_LIBRARY_SWGENERAL} + ${NGS_LIBRARY_UTILS} + ${NGS_LIBRARY_CORBA} + ${FOM_LIBRARY} + CACHE STRING "All ngs libraries" FORCE + ) + MARK_AS_ADVANCED(NGS_INCLUDE_DIR NGS_LIBRARY FOM_LIBRARY) +ENDIF() + +SET(NGS_IS_GUEZ OFF) +SET(NGS_IS_AHTC OFF) +IF (NGS_FOUND) + FIND_PATH(NGS_GUEZ_INCLUDE_DIR TacticalStatusStruct.h + PATHS ${NGS_FOM_INCLUDE_DIR}) + FIND_PATH(NGS_AHTC_INCLUDE_DIR LongBowApacheObjClass.h + PATHS ${NGS_FOM_INCLUDE_DIR}) + IF (NGS_GUEZ_INCLUDE_DIR AND EXISTS "${NGS_GUEZ_INCLUDE_DIR}/TacticalStatusStruct.h") + SET(NGS_IS_GUEZ ON) + MESSAGE(STATUS "NGS - GUEZ version (${NGS_GUEZ_INCLUDE_DIR})") + ELSE() + SET(NGS_IS_GUEZ OFF) + ENDIF() + IF (NGS_AHTC_INCLUDE_DIR AND EXISTS "${NGS_AHTC_INCLUDE_DIR}/LongBowApacheObjClass.h") + SET(NGS_IS_AHTC ON) + MESSAGE(STATUS "NGS - AHTC version (${NGS_AHTC_INCLUDE_DIR})") + ELSE() + SET(NGS_IS_AHTC OFF) + ENDIF() +ENDIF() + +IF(NOT TARGET NGS::NGS) + ADD_LIBRARY(NGS::NGS UNKNOWN IMPORTED) + SET_PROPERTY(TARGET NGS::NGS PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${NGS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET NGS::NGS PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${NGS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET NGS::NGS PROPERTY IMPORTED_LOCATION "${NGS_LIBRARY}") + + SET_PROPERTY(TARGET NGS::NGS APPEND PROPERTY INTERFACE_LINK_LIBRARIES + "${NGS_LIBRARY_SWGENERAL}" + "${NGS_LIBRARY_UTILS}" + "${NGS_LIBRARY_CORBA}" + "${FOM_LIBRARY}" + ) +ENDIF() diff --git a/cmake/FindPopplerQt5.cmake b/cmake/FindPopplerQt5.cmake new file mode 100755 index 000000000..bec65c4df --- /dev/null +++ b/cmake/FindPopplerQt5.cmake @@ -0,0 +1,61 @@ + + + + + + + + + + + + + +if(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) + + + set(POPPLER_QT5_FOUND TRUE) + +else(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) + +set(_poppler_version_bad FALSE) + +if(NOT WIN32) + + + include(FindPkgConfig) + pkg_check_modules(_pc_poppler poppler-qt5) + if(_pc_poppler_FOUND) + if(NOT "${_pc_poppler_VERSION}" VERSION_GREATER 0.24.0) + set(_poppler_version_bad TRUE) + endif(NOT "${_pc_poppler_VERSION}" VERSION_GREATER 0.24.0) + endif(_pc_poppler_FOUND) +endif(NOT WIN32) + +if(NOT _poppler_version_bad) + set(POPPLER_QT5_FOUND FALSE) + + find_library(POPPLER_QT5_LIBRARY poppler-qt5 + HINTS ${_pc_poppler_LIBRARY_DIRS} + ) + + find_path(POPPLER_QT5_INCLUDE_DIR poppler-qt5.h + HINTS ${_pc_poppler_INCLUDE_DIRS} + PATH_SUFFIXES poppler/qt5 + ) + find_path(POPPLER_QT5_INCLUDE_DIR_core qt5/poppler-qt5.h + HINTS ${_pc_poppler_INCLUDE_DIRS} + PATH_SUFFIXES poppler + ) + + if(POPPLER_QT5_LIBRARY AND POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_INCLUDE_DIR_core) + list(APPEND POPPLER_QT5_INCLUDE_DIR "${POPPLER_QT5_INCLUDE_DIR_core}") + set(POPPLER_QT5_FOUND TRUE) + endif(POPPLER_QT5_LIBRARY AND POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_INCLUDE_DIR_core) +endif(NOT _poppler_version_bad) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PopplerQt5 DEFAULT_MSG + POPPLER_QT5_LIBRARY + POPPLER_QT5_INCLUDE_DIR) +endif(POPPLER_QT5_INCLUDE_DIR AND POPPLER_QT5_LIBRARY) diff --git a/cmake/FindRTI.cmake b/cmake/FindRTI.cmake new file mode 100755 index 000000000..3aaf5e82d --- /dev/null +++ b/cmake/FindRTI.cmake @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +SET(_rti_gcc_arch "") +IF(NOT RTI_DIR) + SET(_arch "unknown") + IF(WIN32) + SET(_RTI_DIR $ENV{DDS_PATH}) + IF(NOT _RTI_DIR) + GET_FILENAME_COMPONENT(_rti_root_path "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Real-Time Innovations\\RTI Connext DDS Pro 5.2.3;Location]" ABSOLUTE) + SET(_RTI_DIR "${_rti_root_path}") + ENDIF() + IF(MSVC_VERSION EQUAL 1900) + SET(_rti_msvc_ver "VS2015") + ELSEIF(MSVC_VERSION GREATER_EQUAL 1910) + SET(_rti_msvc_ver "VS2017") + ENDIF() + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(_rti_msvc_ver "x64Win64${_rti_msvc_ver}") + ELSE() + SET(_rti_msvc_ver "i86Win32${_rti_msvc_ver}") + ENDIF() + IF(NOT ${_rti_root_path}) + SET(_RTI_DIR $ENV{KDEROOT}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + SET(_RTI_DIR $ENV{WORKSPACE}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + ENDIF() + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + SET(_RTI_DIR ${EXTERNAL_LIBRARY_DIR}) + FILE(TO_CMAKE_PATH "${_RTI_DIR}" _RTI_DIR) + ENDIF() + ENDIF() + SET(_arch "${_rti_msvc_ver}") + ELSE(WIN32) + SET(_RTI_DIR $ENV{DDS_PATH}) + IF(NOT _RTI_DIR) + SET(_RTI_DIR "/opt/RTI") + ENDIF() + IF(NOT EXISTS "${_RTI_DIR}" OR NOT IS_DIRECTORY "${_RTI_DIR}") + MESSAGE(FATAL_ERROR "Umgebungsvariable DDS_PATH nicht gesetzt!") + ENDIF() + SET(_rti_gcc_arch "x64Linux3gcc4.8.2") + IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0.0) + SET(_rti_gcc_arch "x64Linux3gcc5.4.0") + SET(_tmp "${_RTI_DIR}/lib/${_rti_gcc_arch}") + IF (NOT EXISTS ${_tmp}) + SET(_rti_gcc_arch "x64Linux4gcc7.3.0") + ENDIF() + ENDIF() + ENDIF() + SET(_arch "${_rti_gcc_arch}") + ENDIF() + SET(RTI_DIR "${_RTI_DIR}" CACHE STRING "RTI base path" FORCE) + MESSAGE(STATUS "Trying to use RTI from ${RTI_DIR} with arch ${_arch}") +ENDIF() +IF(WIN32) + SET(_rti_include_hint "${RTI_DIR}/include/") + SET(_rti_library_hint "${RTI_DIR}/lib/${_rti_msvc_ver}/") +ELSE() + SET(_rti_include_hint "${RTI_DIR}/include/") + SET(_rti_library_hint "${RTI_DIR}/lib/") +ENDIF() + + +IF(NOT RTI_INCLUDE_DIR) + FIND_PATH(RTI_INCLUDE_DIR ndds/ndds_cpp.h HINTS ${_rti_include_hint}) + IF(RTI_INCLUDE_DIR) + SET(RTI_INCLUDE_DIRS "${RTI_INCLUDE_DIR}" "${RTI_INCLUDE_DIR}/ndds" "${RTI_INCLUDE_DIR}/ndds/hpp" CACHE STRING "RTI include directories" FORCE) + MARK_AS_ADVANCED(RTI_INCLUDE_DIRS) + ELSE() + MESSAGE(FATAL "Could not find RTI include directory at ${_rti_include_hint}") + ENDIF() +ENDIF() + + +IF(NOT RTI_DDSGEN_EXECUTABLE) + FIND_PROGRAM(RTI_DDSGEN_EXECUTABLE NAMES rtiddsgen rtiddsgen.bat HINTS ${RTI_DIR}/scripts ${RTI_DIR}/bin) +ENDIF() +IF(NOT RTI_VERSION_MAJOR) + EXEC_PROGRAM(${RTI_DDSGEN_EXECUTABLE} ARGS -version OUTPUT_VARIABLE _dds_version_output) + STRING(REGEX REPLACE ".* ([0-9]\\.[0-9]\\.[0-9]).*" "\\1" _dds_version_output ${_dds_version_output}) + SET(_rti_version_major 5) + IF(_dds_version_output VERSION_GREATER 2.9.9) + SET(_rti_version_major 6) + ENDIF() + SET(RTI_VERSION_MAJOR ${_rti_version_major} CACHE STRING "RTI version" FORCE) +ENDIF() + +INCLUDE(FindLibraryWithDebug) +INCLUDE(FindPackageHandleStandardArgs) + + +SET(_RTI_LIBS nddscore nddsc nddscpp2 rtiroutingservice) +SET(_libs "") +SET(_lib_vars "") + +FOREACH(_lib ${_RTI_LIBS}) + SET(_libname "RTI_${_lib}_LIBRARY") + IF (NOT ${_libname}) + FIND_LIBRARY_WITH_DEBUG("${_libname}" + WIN32_DEBUG_POSTFIX d + NAMES ${_lib} + HINTS ${_rti_library_hint} ${RTI_DIR}/lib ${RTI_DIR}/lib/${_rti_gcc_arch}) + ENDIF() + SET(_tgt_name RTI::${_lib}) + + IF(NOT TARGET ${_tgt_name}) + ADD_LIBRARY(${_tgt_name} UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIRS}") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIRS}") + + IF(UNIX) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_UNIX;RTI_LINUX;RTI_64BIT" ) + ENDIF() + IF(WIN32) + IF("${_lib}" STREQUAL "rtiroutingservice") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_WIN32;RTI_routingservice_DLL_VARIABLE" ) + ELSE() + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "RTI_WIN32;NDDS_DLL_VARIABLE" ) + ENDIF() + ENDIF() + + IF(${_libname}_RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_RELEASE "${${_libname}_RELEASE}") + ENDIF() + IF(${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_DEBUG "${${_libname}_DEBUG}") + ENDIF() + IF(NOT ${_libname}_RELEASE AND NOT ${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION "${${_libname}}") + ENDIF() + ENDIF() + + LIST(APPEND _libs "${${_libname}}") + LIST(APPEND _lib_vars "${_libname}") +ENDFOREACH() + +IF(TARGET RTI::nddscore AND UNIX) + SET_PROPERTY(TARGET RTI::nddscore PROPERTY INTERFACE_LINK_LIBRARIES "dl" ) +ENDIF() + +SET(RTI_LIBRARIES ${_libs} CACHE STRING "All rti libraries" FORCE) +MARK_AS_ADVANCED(RTI_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(RTI DEFAULT_MSG RTI_DIR RTI_INCLUDE_DIR RTI_DDSGEN_EXECUTABLE ${_lib_vars}) + diff --git a/cmake/FindSchusstafel.cmake b/cmake/FindSchusstafel.cmake new file mode 100755 index 000000000..87a44356e --- /dev/null +++ b/cmake/FindSchusstafel.cmake @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) + SET(SCHUSSTAFEL_FOUND TRUE) +ELSE(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) + + FIND_PATH(SCHUSSTAFEL_INCLUDE_DIR Schusstafel.h) + FIND_LIBRARY_WITH_DEBUG(SCHUSSTAFEL_LIBRARY WIN32_DEBUG_POSTFIX d NAMES Schusstafel libSchusstafel) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Schusstafel DEFAULT_MSG SCHUSSTAFEL_LIBRARY SCHUSSTAFEL_INCLUDE_DIR) + + MARK_AS_ADVANCED(SCHUSSTAFEL_INCLUDE_DIR SCHUSSTAFEL_LIBRARY) +ENDIF(SCHUSSTAFEL_INCLUDE_DIR AND SCHUSSTAFEL_LIBRARY) diff --git a/cmake/FindTMSIF.cmake b/cmake/FindTMSIF.cmake new file mode 100755 index 000000000..66985c563 --- /dev/null +++ b/cmake/FindTMSIF.cmake @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(NOT TMSIF_DIR) + SET(_arch "unknown") + SET(_TMSIF_DIR $ENV{TMSIF_PATH}) + IF(NOT _TMSIF_DIR) + SET(_TMSIF_DIR "/opt/tmsif") + ENDIF() + IF(NOT EXISTS "${_TMSIF_DIR}" OR NOT IS_DIRECTORY "${_TMSIF_DIR}") + MESSAGE(FATAL_ERROR "Umgebungsvariable TMSIF_PATH nicht gesetzt!") + ENDIF() + SET(TMSIF_DIR "${_TMSIF_DIR}" CACHE STRING "TMSIF base path" FORCE) + MESSAGE(STATUS "Trying to use TMSIF_DIR from ${TMSIF_DIR}") +ENDIF() +SET(_tmsif_include_hint "${TMSIF_DIR}/include/") +SET(_tmsif_library_hint "${TMSIF_DIR}/lib/") + + +IF(NOT TMSIF_INCLUDE_DIR) + FIND_PATH(TMSIF_INCLUDE_DIR Common.h HINTS ${_tmsif_include_hint}) + IF(TMSIF_INCLUDE_DIR) + SET(TMSIF_INCLUDE_DIRS "${TMSIF_INCLUDE_DIR}" "${TMSIF_INCLUDE_DIR}/ddscxx" CACHE STRING "TMSIF include directories" FORCE) + MARK_AS_ADVANCED(TMSIF_INCLUDE_DIRS) + ELSE() + MESSAGE(FATAL "Could not find TMSIF include directory at ${_tmsif_include_hint}") + ENDIF() +ENDIF() + + + +SET(_TMSIF_LIBS tmsif-cyclone ddscxx ddkit-cyclone ) +SET(_libs "") +SET(_lib_vars "") + +FOREACH(_lib ${_TMSIF_LIBS}) + SET(_libname "TMSIF_${_lib}_LIBRARY") + IF (NOT ${_libname}) + FIND_LIBRARY_WITH_DEBUG("${_libname}" + WIN32_DEBUG_POSTFIX d + NAMES ${_lib} + HINTS ${_tmsif_library_hint} ${TMSIF_DIR}/lib ) + ENDIF() + SET(_tgt_name TMSIF::${_lib}) + + IF(NOT TARGET ${_tgt_name}) + ADD_LIBRARY(${_tgt_name} UNKNOWN IMPORTED) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${TMSIF_INCLUDE_DIRS}") + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${TMSIF_INCLUDE_DIRS}") + + IF(UNIX) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY INTERFACE_COMPILE_DEFINITIONS "TMSIF_UNIX;TMSIF_LINUX;TMSIF_64BIT" ) + ENDIF() + IF(${_libname}_RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_RELEASE "${${_libname}_RELEASE}") + ENDIF() + IF(${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION_DEBUG "${${_libname}_DEBUG}") + ENDIF() + IF(NOT ${_libname}_RELEASE AND NOT ${_libname}_DEBUG) + SET_PROPERTY(TARGET ${_tgt_name} PROPERTY IMPORTED_LOCATION "${${_libname}}") + ENDIF() + ENDIF() + + LIST(APPEND _libs "${${_libname}}") + LIST(APPEND _lib_vars "${_libname}") +ENDFOREACH() + + +SET(TMSIF_LIBRARIES ${_libs} CACHE STRING "All TMSIF libraries" FORCE) +MARK_AS_ADVANCED(TMSIF_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TMSIF DEFAULT_MSG TMSIF_DIR TMSIF_INCLUDE_DIR ${_lib_vars}) + diff --git a/cmake/FindVLC.cmake b/cmake/FindVLC.cmake new file mode 100755 index 000000000..d6ab65cd4 --- /dev/null +++ b/cmake/FindVLC.cmake @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +IF(VLC_INCLUDE_DIR AND VLC_LIBRARIES) + + + SET(VLC_FOUND TRUE) + +ELSE() + + INCLUDE(FindPackageHandleStandardArgs) + INCLUDE(FindLibraryWithDebug) + + FIND_LIBRARY_WITH_DEBUG(VLC_LIBRARIES WIN32_DEBUG_POSTFIX d NAMES vlc libvlc) + FIND_PATH(VLC_INCLUDE_DIR vlc/vlc.h) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(VLC DEFAULT_MSG VLC_LIBRARIES VLC_INCLUDE_DIR) + + FIND_PATH(VLC_IS_2_0_ABOVE vlc/libvlc_version.h + PATHS ${VLC_INCLUDE_DIR} + NO_DEFAULT_PATH) + + IF(NOT VLC_IS_2_0_ABOVE) + MESSAGE(FATAL_ERROR "Need at least VLC 2.x") + ENDIF() + MARK_AS_ADVANCED(VLC_DEFINES) + +ENDIF() diff --git a/cmake/FindXSD.cmake b/cmake/FindXSD.cmake new file mode 100755 index 000000000..ccf432e07 --- /dev/null +++ b/cmake/FindXSD.cmake @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +IF(XSD_INCLUDE_DIR AND XSD_COMPILER) + SET(XSD_FOUND TRUE) +ELSE(XSD_INCLUDE_DIR AND XSD_COMPILER) + + FIND_PROGRAM(XSD_COMPILER NAMES xsdcxx xsd) + FIND_PATH(XSD_INCLUDE_DIR xsd/cxx/config.hxx) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XSD DEFAULT_MSG + XSD_COMPILER + XSD_INCLUDE_DIR + ) + + MARK_AS_ADVANCED(XSD_COMPILER + XSD_INCLUDE_DIR) +ENDIF(XSD_INCLUDE_DIR AND XSD_COMPILER) + +MACRO(XSD_GENERATE_TREE srcList infile) + GET_FILENAME_COMPONENT(output ${infile} NAME) + GET_FILENAME_COMPONENT(input ${infile} ABSOLUTE) + GET_FILENAME_COMPONENT(dir ${infile} DIRECTORY) + + EXEC_PROGRAM(${XSD_COMPILER} ARGS version OUTPUT_VARIABLE _xsd_version_output) + STRING(REGEX REPLACE ".* ([0-9]\\.[0-9]\\.[0-9]).*" "\\1" _xsd_version_output ${_xsd_version_output}) + + SET(_xsd_in ${input}) + SET(_cpp_out ${dir}/${output}.cxx) + SET(_hpp_out ${dir}/${output}.hxx) + + STRING(REPLACE ".xsd" "" _cpp_out "${_cpp_out}") + STRING(REPLACE ".xsd" "" _hpp_out "${_hpp_out}") + SET(additional_xsd_args "") + IF(_xsd_version_output VERSION_GREATER 3.9.0) + IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7.0) + SET(additional_xsd_args --std c++11) + ELSE() + IF(WIN32 OR NOT CMAKE_COMPILER_IS_GNUCC) + SET(additional_xsd_args --std c++11) + ENDIF(WIN32 OR NOT CMAKE_COMPILER_IS_GNUCC) + ENDIF() + ENDIF() + + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${dir} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${dir} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + ADD_CUSTOM_COMMAND(OUTPUT ${_cpp_out} ${_hpp_out} + COMMAND ${XSD_COMPILER} + ARGS cxx-tree ${additional_xsd_args} --generate-serialization ${_xsd_in} + DEPENDS ${_xsd_in} ${CMAKE_CURRENT_BINARY_DIR}/${dir} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir} + ) + LIST(APPEND ${srcList} ${_cpp_out} ${_hpp_out} ${infile}) +ENDMACRO(XSD_GENERATE_TREE srcList infile) diff --git a/cmake/MacroCodeGenIdl.cmake b/cmake/MacroCodeGenIdl.cmake new file mode 100755 index 000000000..ba39f7d39 --- /dev/null +++ b/cmake/MacroCodeGenIdl.cmake @@ -0,0 +1,511 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(CMakeParseArguments) + +MACRO(_ADD_SERVICE_RESTART_FLAG svcName) + + STRING(TOUPPER ${svcName} _svcNameUpper) + STRING(TOLOWER ${svcName} _svcNameLower) + SET(_optionName DONTRESTARTSVC_${_svcNameUpper}) + OPTION(${_optionName} "Do not automatically restart Service ${_svcNameUpper} (build dir only)" OFF) + SET(_fn "${CMAKE_BINARY_DIR}/share/Lts/xml/${_svcNameLower}.dontRestart") + IF (${_optionName}) + FILE(WRITE ${_fn} "blub") + ELSE() + FILE(REMOVE ${_fn}) + ENDIF() + +ENDMACRO() + + +MACRO(_GET_SERVICENAME xmlFile_in svcNameOut) + GET_FILENAME_COMPONENT(xmlFile ${xmlFile_in} NAME_WE) + SET(_idx -1) + STRING(FIND "${xmlFile}" "_" _idx) + STRING(SUBSTRING "${xmlFile}" 0 ${_idx} ${svcNameOut}) +ENDMACRO() + +MACRO(_CODEGEN_ACTION action srcList xmlIn in_files out_files) + LIST(APPEND dependFiles ${ARGN} ${xmlIn} ${${in_files}}) + + + + + SET(_cg codegen) + ADD_CUSTOM_COMMAND(OUTPUT ${${out_files}} + COMMAND ${_cg} + ARGS -s ${xmlIn} + -a ${action} + -o ${CMAKE_CURRENT_BINARY_DIR} + -i ${CMAKE_BINARY_DIR}/service_idl_files.txt + ${${in_files}} + DEPENDS ${_cg} ${dependFiles} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + LIST(APPEND ${srcList} ${${out_files}}) + GET_FILENAME_COMPONENT(_xml "${CMAKE_CURRENT_SOURCE_DIR}/${xmlIn}" ABSOLUTE) + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_IDL_FILES "${_xml}") +ENDMACRO() + +MACRO(CODEGEN_DATABASE_STRUCTS srcList_h xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.h" + ) + _CODEGEN_ACTION("DATABASE" ${srcList_h} ${xmlFile_in} in_files out_files ${ARGN}) +ENDMACRO() + +MACRO(CODEGEN_DATABASE_SQL srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h" + ) + _CODEGEN_ACTION("DATABASE" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h") + ENDIF() +ENDMACRO() + +MACRO(CODEGEN_DAO srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dao.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dao.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.h" + ) + _CODEGEN_ACTION("dao" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dao.h") + ENDIF() +ENDMACRO() + +MACRO(CODEGEN_DATABASE srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_structs.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_db.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_structs.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + ) + _CODEGEN_ACTION("DATABASE_SERVER" ${srcList} ${xmlFile_in} in_files out_files ${ARGN}) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_db_impl.h") + ENDIF() +ENDMACRO() + + +MACRO(INSTALL_SHARED_FILES srcList) + SET(options) + SET(oneValueArgs DESTINATION) + SET(multiValueArgs FILES) + CMAKE_PARSE_ARGUMENTS(_ISF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + SET(build_out_dir ${CMAKE_BINARY_DIR}/share/Lts/${_ISF_DESTINATION}) + SET(inst_out_dir share/Lts/${_ISF_DESTINATION}) + + FOREACH(filename ${_ISF_FILES}) + GET_FILENAME_COMPONENT(fn ${filename} NAME) + SET(build_out_file ${build_out_dir}/${fn}) + SET(in_file ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) + ADD_CUSTOM_COMMAND(OUTPUT ${build_out_file} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${build_out_dir} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy_if_different ${in_file} ${build_out_file} + DEPENDS ${in_file} + ) + LIST(APPEND ${srcList} ${in_file} ${build_out_file}) + ENDFOREACH() + NGL_INSTALL(${_ISF_UNPARSED_ARGUMENTS} FILES ${_ISF_FILES} DESTINATION ${inst_out_dir}) +ENDMACRO() + +MACRO(CODEGEN_SQL srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(out_dir_sql "${CMAKE_BINARY_DIR}/share/Lts/sql/") + SET(out_file_sql "${out_dir_sql}/${svcNameOut}.sql") + SET(action "SQL") + ADD_CUSTOM_COMMAND(OUTPUT ${out_file_sql} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${out_dir_sql} + COMMAND codegen + ARGS -s ${xmlFile_in} + -a ${action} + -o ${out_dir_sql} + -i ${CMAKE_BINARY_DIR}/service_idl_files.txt + DEPENDS ${_cg} ${xmlFile_in} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + LIST(APPEND ${srcList} ${out_file_sql}) + + + NGL_INSTALL(SV AAR FILES ${out_file_sql} DESTINATION share/Lts/sql) +ENDMACRO() + +MACRO(CODEGEN_HANDLE_SVC_XML srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + + SET(out_dir_xml "${CMAKE_BINARY_DIR}/share/Lts/xml/") + SET(out_file_xml "${out_dir_xml}/${svcNameOut}.xml") + ADD_CUSTOM_COMMAND(OUTPUT ${out_file_xml} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${out_dir_xml} + COMMAND ${CMAKE_COMMAND} + ARGS -E copy_if_different ${xmlFile_in} ${out_file_xml} + DEPENDS ${xmlFile_in} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + LIST(APPEND ${srcList} ${xmlFile_in} ${out_file_xml}) + + _ADD_SERVICE_RESTART_FLAG(${svcNameOut}) + + + NGL_INSTALL(SV AAR FILES ${out_file_xml} DESTINATION share/Lts/xml) +ENDMACRO() + +MACRO(CODEGEN_IDL_SVC srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc.idl.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_enums.idl.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_json.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_json.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_translation.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_translation.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}.idl" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_enums.idl") + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_IDL_FILES "${out_files}") + SET_SOURCE_FILES_PROPERTIES(${out_files} PROPERTIES HEADER_FILE_ONLY TRUE) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_json.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_json.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_translation.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_translation.h") + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files ${ARGN}) + + CODEGEN_HANDLE_SVC_XML(${srcList} ${xmlFile_in}) +ENDMACRO() + +FIND_PACKAGE(PythonInterp 2.7 REQUIRED) +MACRO(CODEGEN_TOPIC_TYPEDEFS srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(inFile ${xmlFile_in}) + IF(NOT IS_ABSOLUTE ${inFile}) + SET(inFile ${CMAKE_CURRENT_SOURCE_DIR}/${inFile}) + IF(NOT EXISTS ${inFile}) + SET(inFile ${CMAKE_CURRENT_BINARY_DIR}/${inFile}) + ENDIF() + ENDIF() + SET(prog ${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/codegen_simple.py) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_types.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_operator_rights.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_operator_rights.cpp" + "${CMAKE_BINARY_DIR}/share/Lts/sql/${svcNameOut}_operator_rights.sql" + ) + + ADD_CUSTOM_COMMAND( OUTPUT ${out_files} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} + ARGS -E make_directory ${CMAKE_BINARY_DIR}/share/Lts/sql/ + COMMAND ${PYTHON_EXECUTABLE} + ARGS ${prog} ALL + ${inFile} + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PYTHON_EXECUTABLE} + ARGS ${prog} SQL + ${inFile} + ${CMAKE_BINARY_DIR}/share/Lts/sql + DEPENDS ${inFile} + ${prog} + ) + LIST(APPEND ${srcList} ${out_files}) + SET_PROPERTY(GLOBAL APPEND PROPERTY CODEGEN_XML_FILES "${inFile}") +ENDMACRO() + +MACRO(CODEGEN_CLIENT_TOPICS_IFC srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTC" "FTC") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc.h.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc.h" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc.h") + ENDIF() + ELSEIF(part STREQUAL "FTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc.h.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc.h" + ) + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + +MACRO(CODEGEN_CLIENT_TOPICS_IMPL srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTC" "FTC") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dtc_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dtc_impl.h") + ENDIF() + ELSEIF(part STREQUAL "FTC") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_ftc_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_ftc_impl.h") + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + +MACRO(CODEGEN_SERVER_TOPICS srcList xmlFile_in) + SET(options) + SET(oneValueArgs) + SET(multiValueArgs PARTS) + CMAKE_PARSE_ARGUMENTS(_CST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + IF(NOT _CST_PARTS) + SET(_CST_PARTS "DTS" "FTS") + ENDIF() + SET(in_files "") + SET(out_files "") + FOREACH(part ${_CST_PARTS}) + IF(part STREQUAL "DTS") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_dts_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_dts_impl.cpp" + ) + ELSEIF(part STREQUAL "FTS") + LIST(APPEND in_files + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts_impl.h.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_fts_impl.cpp.grantlee" + ) + LIST(APPEND out_files + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.h" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.cpp" + ) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_fts_impl.h) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Unkown part argument for CODEGEN_SERVER_TOPICS (${part})") + ENDIF() + ENDFOREACH() + + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) +ENDMACRO() + + + + +MACRO(CODEGEN_TOPIC_TYPE_PLUGIN srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_topic_type_plugin.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_topic_type_plugin.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.h" + ) + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_topic_type_plugin.h) + ENDIF() +ENDMACRO() + +MACRO(CREATE_TOPIC_TYPE_PLUGIN xmlFile_in) + SET(_my_srcs "") + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + CODEGEN_TOPIC_TYPE_PLUGIN(_my_srcs ${xml_FILE}) + + STRING(SUBSTRING ${svcNameOut} 0 1 _ss1) + STRING(SUBSTRING ${svcNameOut} 1 -1 _ss2) + STRING(TOUPPER ${_ss1} _ss1) + SET(_commonLib "svc${_ss1}${_ss2}Common") + + IF(svcNameOut STREQUAL "core") + SET(_commonLib ddscore) + ENDIF() + + NGL_ADD_LIBRARY(WS AAR SV NO_TRANSLATION ${svcNameOut}TopicTypePlugin MODULE + ${_my_srcs} + ) + NGL_TARGET_LINK_LIBRARIES(${svcNameOut}TopicTypePlugin + topic_type_plugin + routing_plugin + ddscore + ${_commonLib} + ) + NGL_INSTALL_TARGET(${svcNameOut}TopicTypePlugin) +ENDMACRO() + + + + +MACRO(CODEGEN_RECORD_REPLAY_PLUGIN srcList xmlFile_in) + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + SET(in_files "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_record_replay_plugin.cpp.grantlee" + "${CMAKE_SOURCE_DIR}/Lts/Common/CodeGen/svc_record_replay_plugin.h.grantlee" + ) + SET(out_files "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.h" + ) + _CODEGEN_ACTION("DDS_TOPICS" ${srcList} "${xmlFile_in}" in_files out_files) + IF(NOT POLICY CMP0071) + QT5_WRAP_CPP(${srcList} ${CMAKE_CURRENT_BINARY_DIR}/${svcNameOut}_record_replay_plugin.h) + ENDIF() +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN_INTERN xmlFile_in svcSourceList libtype) + SET(_my_srcs "") + _GET_SERVICENAME( "${xmlFile_in}" svcNameOut ) + CODEGEN_RECORD_REPLAY_PLUGIN(_my_srcs ${xml_FILE}) + + STRING(SUBSTRING ${svcNameOut} 0 1 _ss1) + STRING(SUBSTRING ${svcNameOut} 1 -1 _ss2) + STRING(TOUPPER ${_ss1} _ss1) + SET(_commonLib "svc${_ss1}${_ss2}Common") + + IF(svcNameOut STREQUAL "core") + SET(_commonLib ddscore) + ENDIF() + + LIST(APPEND ${svcSourceList} ${_my_srcs}) + + NGL_ADD_LIBRARY(SV AAR WS ${svcNameOut}RecordReplayPlugin ${libtype} + ${_my_srcs} + ) + NGL_TARGET_LINK_LIBRARIES(${svcNameOut}RecordReplayPlugin + RecordReplayPlugin + ddscore + ddsconnector + ddsdtc + ngldb + LtsUtilsCore + ${_commonLib} + ) + NGL_INSTALL_TARGET(${svcNameOut}RecordReplayPlugin) + NGL_TARGET_INCLUDE_DIRECTORIES(${svcNameOut}RecordReplayPlugin + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_BINARY_DIR}/../ + ) +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN xmlFile_in svcSourceList) + CREATE_RECORD_REPLAY_PLUGIN_INTERN(${xmlFile_in} ${svcSourceList} MODULE) +ENDMACRO() + +MACRO(CREATE_RECORD_REPLAY_PLUGIN_SHARED xmlFile_in) + CREATE_RECORD_REPLAY_PLUGIN_INTERN(${xmlFile_in} _unused SHARED) +ENDMACRO() + +MACRO(CODEGEN_WRITE_SERVICEFILE_INFO) + GET_PROPERTY(idl_files GLOBAL PROPERTY CODEGEN_IDL_FILES) + LIST(REMOVE_DUPLICATES idl_files) + FILE(WRITE ${CMAKE_BINARY_DIR}/service_idl_files.txt "-- all available service idl files\n") + FOREACH(idl_file ${idl_files}) + FILE(APPEND ${CMAKE_BINARY_DIR}/service_idl_files.txt "${idl_file}\n") + ENDFOREACH() +ENDMACRO() diff --git a/cmake/MacroEnsureOutOfSourceBuild.cmake b/cmake/MacroEnsureOutOfSourceBuild.cmake new file mode 100755 index 000000000..3b3655519 --- /dev/null +++ b/cmake/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,21 @@ + + + + + + + + + + + + +MACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) + + STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource) + IF(insource) + MESSAGE(FATAL_ERROR "${_errorMessage}") + ENDIF(insource) + +ENDMACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) + diff --git a/cmake/MacroRTIDDSGen.cmake b/cmake/MacroRTIDDSGen.cmake new file mode 100755 index 000000000..b8daeb8b1 --- /dev/null +++ b/cmake/MacroRTIDDSGen.cmake @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + +MACRO(RTIDDSGEN srcList infile) + FIND_PACKAGE(RTI REQUIRED) + + SET(input ${infile}) + IF(NOT IS_ABSOLUTE ${input}) + SET(input "${CMAKE_CURRENT_BINARY_DIR}/${input}") + ENDIF() + GET_FILENAME_COMPONENT(output ${infile} NAME_WE) + GET_FILENAME_COMPONENT(input ${input} ABSOLUTE) + + + + + SET(_ddsgen_args "") + SET(output_cxx + ${CMAKE_CURRENT_BINARY_DIR}/${output}.cxx + ${CMAKE_CURRENT_BINARY_DIR}/${output}Plugin.cxx + ) + + SET(output_hpp + ${CMAKE_CURRENT_BINARY_DIR}/${output}.hpp + ${CMAKE_CURRENT_BINARY_DIR}/${output}Plugin.hpp + ) + + + + + ADD_CUSTOM_COMMAND(OUTPUT ${output_cxx} ${output_hpp} + COMMAND ${CMAKE_COMMAND} + ARGS -E remove ${output_cxx} + COMMAND ${RTI_DDSGEN_EXECUTABLE} + ARGS -language "C++11" + ARGS -unboundedSupport + ARGS -verbosity 2 + ARGS -update typefiles + ARGS -stl + ARGS -d ${CMAKE_CURRENT_BINARY_DIR} + ARGS -inputIdl ${input} + ARGS -I ${CMAKE_CURRENT_BINARY_DIR} + ARGS -I ${CMAKE_CURRENT_BINARY_DIR}/../ + ARGS -I ${CMAKE_CURRENT_BINARY_DIR}/../../ + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR} + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR}/../ + ARGS -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${input} ${ARGN} + ) + + IF(WIN32) + SET_SOURCE_FILES_PROPERTIES(${output_cxx} PROPERTIES COMPILE_FLAGS "-DNDDS_USER_DLL_EXPORT") + ELSE() + SET_SOURCE_FILES_PROPERTIES(${output_cxx} PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) + ENDIF() + LIST(APPEND ${srcList} ${output_cxx} ${output_hpp}) + + +ENDMACRO() diff --git a/cmake/NGLMacros.cmake b/cmake/NGLMacros.cmake new file mode 100755 index 000000000..cf06076ac --- /dev/null +++ b/cmake/NGLMacros.cmake @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +INCLUDE(GenerateExportHeader) +SET(_default_build OFF) +IF(BUILD_ALL) + SET(_default_build ON) +ENDIF() + +OPTION(BUILD_SV "Build and install Server software parts" ${_default_build}) +OPTION(BUILD_AAR "Build and install AAR software parts" ${_default_build}) +OPTION(BUILD_LTSCC "Build and install LTS CC Conf" OFF) +OPTION(BUILD_HLA "Build and install HLA Server software parts" OFF) +OPTION(BUILD_WS "Build and install Workstation software parts" ${_default_build}) +OPTION(BUILD_TOOLSWS "Build and install TOOLS for WS" OFF) +OPTION(BUILD_TOOLSSV "Build and install TOOLS for SV" OFF) + +OPTION(BUILD_DEP_TEST_EXECUTABLES "Build executables for created libs to check library dependencies" OFF) +OPTION(BUILD_TS_FILES "Regenerate ts-files for translations" OFF) +OPTION(BUILD_STATIC_LIBRARIES "Build all libraries as static libraries" OFF) + +IF(BUILD_STATIC_LIBRARIES) + ADD_DEFINITIONS(-DBUILD_STATIC_LIBRARIES) +ENDIF() + + +SET(AAR_INSTALL_PATH "AAR") +SET(SV_INSTALL_PATH "SV") +SET(HLA_INSTALL_PATH "SV") +SET(DDS_INSTALL_PATH "SV") +SET(WS_INSTALL_PATH "WS") +SET(TOOLSWS_INSTALL_PATH "WS") +SET(TOOLSSV_INSTALL_PATH "SV") +IF(WIN32) + SET(INSTALL_DEFAULT_ARGS RUNTIME DESTINATION bin + LIBRARY DESTINATION bin + ARCHIVE DESTINATION lib COMPONENT Devel) +ELSE() + SET(INSTALL_DEFAULT_ARGS RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib COMPONENT Devel) +ENDIF() +SET(INSTALL_DEFAULT_ARGS_DEVEL RUNTIME DESTINATION bin COMPONENT Devel + LIBRARY DESTINATION lib COMPONENT Devel + ARCHIVE DESTINATION lib COMPONENT Devel) +SET(_components SV WS AAR TOOLSWS TOOLSSV HLA) + + + + +MACRO (NGL_GET_BUILDPARTS _args _buildopts) + + SET(${_buildopts} "") + SET(_at_least_one_keyword_found OFF) + + LIST(FIND ${_args} "ALL" _all) + IF (_all GREATER -1) + LIST(REMOVE_AT ${_args} ${_all}) + SET(_at_least_one_keyword_found ON) + FOREACH(_component ${_components}) + IF(BUILD_${_component}) + LIST(APPEND ${_buildopts} ${_component}) + ENDIF() + ENDFOREACH() + ELSE() + FOREACH(_component ${_components}) + LIST(FIND ${_args} "${_component}" _idx) + IF(_idx GREATER -1) + LIST(REMOVE_AT ${_args} ${_idx}) + SET(_at_least_one_keyword_found ON) + IF(BUILD_${_component}) + LIST(APPEND ${_buildopts} ${_component}) + ENDIF() + ENDIF() + ENDFOREACH() + ENDIF() + + IF(NOT _at_least_one_keyword_found) + MESSAGE(FATAL_ERROR "No software component keyword (ALL/SV/WS) given!") + ENDIF() +ENDMACRO() + +MACRO (NGL_PARSE_BUILDCOMPONENT_INTERNAL _args _properties _build_target) + + NGL_GET_BUILDPARTS(${_args} _buildopts) + SET(${_build_target} OFF) + + FOREACH(_component ${_components}) + LIST(FIND _buildopts ${_component} _idx) + IF(_idx GREATER -1) + LIST(APPEND ${_properties} NGL_INSTALL_${_component} ON) + SET(${_build_target} ON) + ENDIF() + ENDFOREACH() + LIST(FIND ${_args} "NO_TRANSLATION" _no_i18n) + IF (_no_i18n GREATER -1) + LIST(REMOVE_AT ${_args} ${_no_i18n}) + LIST(APPEND ${_properties} NO_TRANSLATION ON) + ENDIF () + +ENDMACRO() + +MACRO(NGL_ADD_TRANSLATION output_location _qm_file_name _ts_file _qm_files) + GET_FILENAME_COMPONENT(_abs_FILE ${_ts_file} ABSOLUTE) + FILE(MAKE_DIRECTORY "${output_location}") + SET(qm "${output_location}/${_qm_file_name}.qm") + + ADD_CUSTOM_COMMAND(OUTPUT ${qm} + COMMAND Qt5::lrelease + ARGS ${_abs_FILE} -qm ${qm} + DEPENDS ${_abs_FILE} + ) + SET(${_qm_files} ${${_qm_files}} ${qm}) +ENDMACRO() + + + + +MACRO (NGL_ADD_LIBRARY) + + SET(_args ${ARGN}) + + + IF(BUILD_STATIC_LIBRARIES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + ENDIF() + ENDIF() + + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + + ADD_LIBRARY(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + + IF(NOT MSVC AND NOT USE_ASAN AND NOT USE_UBSAN) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--no-undefined") + ENDIF() + + + STRING(TOUPPER ${_target_NAME} _symbol) + STRING(REGEX REPLACE "[^_A-Za-z0-9]" "_" _symbol ${_symbol}) + IF(BUILD_STATIC_LIBRARIES) + SET(_symbol "${_symbol}_EXPORT=") + TARGET_COMPILE_DEFINITIONS(${_target_NAME} PUBLIC ${_symbol}) + ELSE() + GET_TARGET_PROPERTY(target_type ${_target_NAME} TYPE) + IF(target_type STREQUAL "SHARED_LIBRARY" OR + target_type STREQUAL "MODULE_LIBRARY") + SET(_symbol "MAKE_${_symbol}_LIB") + TARGET_COMPILE_DEFINITIONS(${_target_NAME} PRIVATE ${_symbol}) + ENDIF() + ENDIF() + + IF(BUILD_DEP_TEST_EXECUTABLES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + LIST(REMOVE_ITEM _args "${_target_NAME}") + ADD_EXECUTABLE(${_target_NAME}_dep_test ${NGL_MODULE_DIR}/ngl_dep_test_main.cpp ${_args}) + ENDIF() + ENDIF() + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + +MACRO (NGL_ADD_LIBRARY2) + + SET(_args ${ARGN}) + + + IF(BUILD_STATIC_LIBRARIES) + LIST(FIND _args "SHARED" _is_shared) + IF(_is_shared GREATER -1) + LIST(REMOVE_AT _args ${_is_shared}) + ENDIF() + ENDIF() + + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + + ADD_LIBRARY(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + + IF(NOT MSVC AND NOT USE_ASAN AND NOT USE_UBSAN) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--no-undefined") + ENDIF() + TARGET_INCLUDE_DIRECTORIES(${_target_NAME} + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/../ + ) + GET_PROPERTY(type TARGET ${_target_NAME} PROPERTY TYPE) + IF(NOT ${type} STREQUAL "STATIC_LIBRARY") + NGL_INSTALL_TARGET(${_target_NAME}) + ENDIF() + IF(${type} STREQUAL "SHARED_LIBRARY" OR ${type} STREQUAL "MODULE_LIBRARY") + GENERATE_EXPORT_HEADER(${_target_NAME}) + ENDIF() + IF(BUILD_DEP_TEST_EXECUTABLES) + IF(${type} STREQUAL "SHARED_LIBRARY") + LIST(REMOVE_ITEM _args "SHARED") + LIST(REMOVE_ITEM _args "${_target_NAME}") + ADD_EXECUTABLE(${_target_NAME}_dep_test ${NGL_MODULE_DIR}/ngl_dep_test_main.cpp ${_args}) + ENDIF() + ENDIF() + + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + + + + +MACRO (NGL_ADD_EXECUTABLE) + + SET(_args ${ARGN}) + SET(_properties "") + SET(_build_target OFF) + NGL_PARSE_BUILDCOMPONENT_INTERNAL(_args _properties _build_target) + LIST(GET _args 0 _target_NAME) + + IF(_build_target) + ADD_EXECUTABLE(${_args}) + SET_TARGET_PROPERTIES(${_target_NAME} PROPERTIES ${_properties}) + SET_PROPERTY(GLOBAL APPEND PROPERTY NGL_TS_TARGETS ${_target_NAME}) + ENDIF() + + + +ENDMACRO() + + + + +MACRO(NGL_TARGET_INCLUDE_DIRECTORIES _target_NAME) + + IF(TARGET ${_target_NAME}) + TARGET_INCLUDE_DIRECTORIES(${_target_NAME} ${ARGN}) + ENDIF() + +ENDMACRO() + + + + +MACRO(NGL_TARGET_LINK_LIBRARIES _target_NAME) + + IF(TARGET ${_target_NAME}) + TARGET_LINK_LIBRARIES(${_target_NAME} ${ARGN}) + IF(BUILD_DEP_TEST_EXECUTABLES) + GET_TARGET_PROPERTY(_type ${_target_NAME} TYPE) + IF("${_type}" STREQUAL "SHARED_LIBRARY") + TARGET_LINK_LIBRARIES(${_target_NAME}_dep_test ${ARGN} ${_target_NAME}) + ENDIF() + ENDIF() + ENDIF() + +ENDMACRO() +MACRO(NGL_ADD_INSTALL_PREFIX_INTERNAL _args prefix) + LIST(LENGTH ${_args} len) + + SET(_ret_args "") + SET(_replace_next OFF) + FOREACH( _arg ${${_args}}) + IF(${_arg} STREQUAL "DESTINATION") + SET(_replace_next ON) + LIST(APPEND _ret_args ${_arg}) + ELSE() + IF(_replace_next) + LIST(APPEND _ret_args "${prefix}/${_arg}") + SET(_replace_next OFF) + ELSE() + LIST(APPEND _ret_args ${_arg}) + ENDIF() + ENDIF() + ENDFOREACH() + + SET(${_args} ${_ret_args}) +ENDMACRO() + + + + + +MACRO(_NGL_INSTALL_TARGET_internal _target_NAME) + + SET(_args ${ARGN}) + IF(TARGET ${_target_NAME}) + FOREACH(_component ${_components}) + GET_TARGET_PROPERTY(_install_component ${_target_NAME} NGL_INSTALL_${_component}) + IF(_install_component) + SET(_my_args ${_args}) + NGL_ADD_INSTALL_PREFIX_INTERNAL(_my_args ${${_component}_INSTALL_PATH}) + INSTALL(TARGETS ${_target_NAME} ${_my_args}) + ENDIF() + ENDFOREACH() + ENDIF() +ENDMACRO() + +MACRO(NGL_INSTALL_TARGET _target_NAME) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + IF(${len} EQUAL 0) + SET(_args ${INSTALL_DEFAULT_ARGS}) + ENDIF() + _NGL_INSTALL_TARGET_internal(${_target_NAME} ${_args}) +ENDMACRO() + +MACRO(NGL_INSTALL_TARGET_DEVEL _target_NAME) + IF (NOT BUILD_RPM) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + IF(${len} EQUAL 0) + SET(_args ${INSTALL_DEFAULT_ARGS_DEVEL}) + ENDIF() + _NGL_INSTALL_TARGET_internal(${_target_NAME} ${_args}) + ENDIF() +ENDMACRO() + +MACRO(NGL_INSTALL) + SET(_args ${ARGN}) + + NGL_GET_BUILDPARTS(_args _buildopts) + + FOREACH(_component ${_components}) + LIST(FIND _buildopts ${_component} _idx) + IF(_idx GREATER -1) + SET(_my_args ${_args}) + NGL_ADD_INSTALL_PREFIX_INTERNAL(_my_args ${${_component}_INSTALL_PATH}) + INSTALL(${_my_args}) + ENDIF() + ENDFOREACH() + +ENDMACRO() + +MACRO(NGL_SET_TARGET_PROPERTIES _target_NAME) + IF(TARGET ${_target_NAME}) + SET_TARGET_PROPERTIES(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_TARGET_COMPILE_DEFINITIONS _target_NAME) + IF(TARGET ${_target_NAME}) + TARGET_COMPILE_DEFINITIONS(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_COMPILE_FLAGS _target_NAME _property_value) + IF(TARGET ${_target_NAME}) + + SET_PROPERTY(TARGET ${_target_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_property_value}") + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_TEST) + IF(TARGET ${_target_NAME}) + ADD_TEST(${_target_NAME} ${ARGN}) + ENDIF() +ENDMACRO() + +MACRO(NGL_CREATE_ASSISTANT_HELP type target_name language) + + SET(_QHP_FILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${language}.qhp") + SET(_QHP_FILE_BLD "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhp") + SET(_QCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qch") + SET(_QHCP_FILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${language}.qhcp") + SET(_QHCP_FILE_BLD "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhcp") + SET(_QHC_FILE "${CMAKE_CURRENT_BINARY_DIR}/${language}/${language}.qhc") + + SET(_file_list ${ARGN}) + + SET(_command_qhg qhelpgenerator-qt5) + SET(_command_qcg qcollectiongenerator-qt5) + + ADD_CUSTOM_COMMAND(DEPENDS ${_file_list} ${_QHP_FILE_SRC} ${_QHCP_FILE_SRC} + COMMAND ${NGL_MODULE_DIR}/make_qt_help.py + ARGS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${language} ${language} ${_file_list} + COMMAND ${_command_qhg} + ARGS ${_QHP_FILE_BLD} -o ${_QCH_FILE} + COMMAND ${_command_qcg} + ARGS "${_QHCP_FILE_BLD}" -o "${_QHC_FILE}" + COMMAND ${CMAKE_COMMAND} + ARGS -E touch ${CMAKE_CURRENT_BINARY_DIR}/${language}_qch_dummy.c + OUTPUT "${_QHC_FILE}" + "${_QHCP_FILE_BLD}" + "${_QHP_FILE_BLD}" + "${_QCH_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/${language}_qch_dummy.c" + WORKING_DIRECTORY ${CMAKE_CURRENT_BUILD_DIR} + COMMENT "Generating Qt assistant help for language ${language}" + ) + + NGL_ADD_LIBRARY(${type} "${type}_${target_name}_${language}_qch_dummy" "${language}_qch_dummy") + NGL_INSTALL(${type} FILES "${_QCH_FILE}" "${_QHC_FILE}" DESTINATION help/${target_name}/) + +ENDMACRO() + +MACRO(NGL_ADD_TARGET_LINK targetName targetAbbr) + +IF(TARGET ${targetName}) + IF(NOT WIN32) + SET(cmake_operation create_symlink) + IF(WIN32) + SET(cmake_operation copy) + ENDIF(WIN32) + ADD_CUSTOM_COMMAND(TARGET ${targetName} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove -f ${targetAbbr} + COMMAND ${CMAKE_COMMAND} -E ${cmake_operation} ${targetName} ${targetAbbr} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin + ) + ENDIF() +ENDIF() +ENDMACRO() + + +MACRO(ADD_INTERFACE_LIBRARY name_ header_ inc_path_) + SET(link_libs_ ${ARGN}) + ADD_LIBRARY(${name_} INTERFACE) + TARGET_INCLUDE_DIRECTORIES(${name_} + INTERFACE + ${inc_path_} + ) + FOREACH(link_lib_ ${link_libs_}) + TARGET_LINK_LIBRARIES(${name_} + INTERFACE + ${link_lib_} + ) + ENDFOREACH() + TARGET_SOURCES(${name_} INTERFACE ${header_}) +ENDMACRO() + + +macro(NGL_COMPILE_RESOURCES output_qrc_objects) + + + get_property(ipo_active VARIABLE PROPERTY CMAKE_INTERPROCEDURAL_OPTIMIZATION) + if(CMAKE_VERSION VERSION_GREATER 3.8.99 AND Qt5Core_VERSION VERSION_GREATER 5.12.99 AND NOT WIN32 AND NOT ipo_active) + set(_QT5_INTERNAL_SCOPE ON) + + set(options) + set(oneValueArgs) + set(multiValueArgs OPTIONS) + cmake_parse_arguments(_NGL_COMPILE_RESOURCES "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(qrc_files ${_NGL_COMPILE_RESOURCES_UNPARSED_ARGUMENTS}) + set(rcc_options ${_NGL_COMPILE_RESOURCES_OPTIONS}) + + foreach(qrc_file ${qrc_files}) + get_filename_component(qrc_object_file ${qrc_file} NAME_WE) + get_filename_component(qrc_filename ${qrc_file} ABSOLUTE) + set(qrc_header_file ${CMAKE_CURRENT_BINARY_DIR}/qrc_${qrc_object_file}_header.cpp) + set(qrc_object ${CMAKE_CURRENT_BINARY_DIR}/qrc_${qrc_object_file}.o) + + _qt5_parse_qrc_file(${qrc_filename} _out_depends _rc_depends) + set_source_files_properties(${qrc_filename} PROPERTIES SKIP_AUTORCC ON) + add_custom_command(OUTPUT ${qrc_header_file} + COMMAND echo ">>> 1: Regenerating ${qrc_header_file}" + COMMAND ${Qt5Core_RCC_EXECUTABLE} ${rcc_options} --name ${qrc_object_file} --pass 1 --output ${qrc_header_file} ${qrc_filename} + DEPENDS ${qrc_filename} ${_rc_depends} "${_out_depends}" + VERBATIM) + + add_custom_target(resources_${qrc_object_file} ALL DEPENDS ${qrc_header_file}) + add_library(qrc_object_${qrc_object_file} OBJECT ${qrc_header_file}) + add_dependencies(qrc_object_${qrc_object_file} resources_${qrc_object_file}) + + set_target_properties(qrc_object_${qrc_object_file} PROPERTIES AUTOMOC OFF) + set_target_properties(qrc_object_${qrc_object_file} PROPERTIES AUTOUIC OFF) + + add_custom_command(OUTPUT ${qrc_object} + COMMAND echo ">>> 2: Regenerating ${qrc_object} with $" + COMMAND ${Qt5Core_RCC_EXECUTABLE} + ARGS ${rcc_options} --name ${qrc_object_file} --pass 2 --temp $ --output ${qrc_object} ${qrc_filename} + DEPENDS qrc_object_${qrc_object_file} ${qrc_filename} ${qrc_header_file} + VERBATIM) + + list(APPEND ${output_qrc_objects} ${qrc_object}) + endforeach() + else() + + QT5_ADD_RESOURCES(${output_qrc_objects} ${ARGN}) + endif() +endmacro() + + +MACRO(NGL_ADD_BIG_RESOURCES) + + + GET_PROPERTY(ipo_active VARIABLE PROPERTY CMAKE_INTERPROCEDURAL_OPTIMIZATION) + IF(CMAKE_VERSION VERSION_GREATER 3.8.99 AND Qt5Core_VERSION VERSION_GREATER 5.12.99 AND NOT WIN32 AND NOT ipo_active) + QT5_ADD_BIG_RESOURCES(${ARGN}) + ELSE() + QT5_ADD_RESOURCES(${ARGN}) + ENDIF() +ENDMACRO() + + + + +MACRO(NGL_WRAP_UI) + QT5_WRAP_UI(${ARGN}) +ENDMACRO() + +MACRO(NGL_ADD_APP_ICON_INTERNAL _srcs icon) + IF(WIN32) + SET(_rc_file ${CMAKE_CURRENT_BINARY_DIR}/${target}_icon.rc) + FILE(WRITE ${_rc_file} "IDI_ICON1 ICON DISCARDABLE \"${icon}\"\n") + LIST(APPEND ${target} ${_rc_file}) + SET_SOURCE_FILES_PROPERTIES(${_rc_file} PROPERTIES OBJECT_DEPENDS ${icon}) + LIST(APPEND ${_srcs} ${_rc_file}) + ENDIF() +ENDMACRO() + +MACRO(NGL_ADD_APP_ICON target) + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/rde_icon_256.ico") +ENDMACRO() + +MACRO(NGL_ADD_SVC_ICON target) + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/rde_icon_256.ico") +ENDMACRO() + +MACRO(NGL_ADD_TOOL_ICON target) + SET(_args ${ARGN}) + LIST(LENGTH _args len) + SET(_ico "rde_logo.ico") + IF (len EQUAL 1) + LIST(GET _args 0 _tool) + SET(_ico "rde_internal_${_tool}_logo_256x256.ico") + ENDIF() + NGL_ADD_APP_ICON_INTERNAL(${target} "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/${_ico}") +ENDMACRO() + + +macro(NGL_TEST_APPS_JSON target) + if(NOT BUILD_RPM AND TARGET ${target}) + add_custom_command( + TARGET ${target} + PRE_BUILD + COMMAND $ + ARGS ${CMAKE_CURRENT_SOURCE_DIR} resources/apps.json + VERBATIM) + + if(jsonschema) + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND jsonschema + ARGS -i ${CMAKE_CURRENT_SOURCE_DIR}/resources/apps.json ${CMAKE_CURRENT_SOURCE_DIR}/../apps.schema.json + VERBATIM) + endif() + endif() +endmacro() diff --git a/cmake/make_qt_help.py b/cmake/make_qt_help.py new file mode 100755 index 000000000..4c93fb9fc --- /dev/null +++ b/cmake/make_qt_help.py @@ -0,0 +1,186 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + + + + +import os +import shutil +import sys +import sgmllib + + + +class MyParser(sgmllib.SGMLParser): + "A simple parser class." + + def __init__(self, verbose=0): + "Initialise an object, passing 'verbose' to the superclass." + + sgmllib.SGMLParser.__init__(self, verbose) + self.hyperlinks = [] + self.descriptions = [] + self.depths = [] + self.inside_a_element = 0 + self.inside_li_element = 0 + self.current_description = "" + self.current_hyperlink = "" + self.current_ul_depth = 0 + self.current_li_data = "" + + def parse(self, string): + "Parse the given string 'string'." + self.feed(string) + self.close() + + def start_a(self, attributes): + "Process a hyperlink and its 'attributes'." + + self.current_hyperlink = "" + self.current_description = "" + self.inside_a_element = 1 + for name, value in attributes: + if name == "href": + self.current_hyperlink = value + + def end_a(self): + "Record the end of a hyperlink" + + self.inside_a_element = 0 + + def start_ul(self, attributes): + "
    " + self.current_ul_depth += 1 + + def end_ul(self): + "
" + self.current_ul_depth -= 1 + + def start_li(self, attributes): + "
  • " + self.inside_li_element = 1 + self.current_description = "" + self.current_hyperlink = "" + + def end_li(self): + "
  • " + self.inside_li_element = 0 + if len(self.current_description) == 0: + self.descriptions.append(self.current_li_data) + self.hyperlinks.append(self.current_hyperlink) + self.depths.append(self.current_ul_depth) + + def handle_data(self, data): + "Handle the textual 'data'" + + if self.inside_a_element: + self.descriptions.append(data) + self.hyperlinks.append(self.current_hyperlink) + self.depths.append(self.current_ul_depth) + + self.current_description = data + + if self.inside_li_element: + self.current_li_data = data + + def get_xml(self, spacecount, prefix): + "return the structure as xml" + ret = "" + basespaces = ' ' * spacecount + for i, val in enumerate( self.descriptions ): + depth = self.depths[i] + + nextdepth = self.depths[0] + if i != len(self.descriptions) - 1: + nextdepth = self.depths[i+1] + end = '/>' + if depth < nextdepth: + end = '>' + ref = "" + if len(self.hyperlinks[i]) > 0: + ref += ' ref="%s/%s"' % ( prefix, self.hyperlinks[i] ) + spaces = basespaces + ' ' * depth + ret += '%s
    nextdepth: + spaces = basespaces + ' ' * (depth - 1) + ret += '%s
    \n' % spaces + depth -= 1 + return ret + +def removeDir(dirname): + "remove dir 'dirname' and all it's subdirectories" + for name in os.listdir(dirname): + filename = os.path.join(dirname, name) + if not os.path.islink(filename) and os.path.isdir(filename): + removeDir(filename) + else: + os.remove(filename) + os.rmdir(dirname) + return + +def main(): + if len(sys.argv) < 4: + print >> sys.stderr, "To few arguments: %s []" % sys.argv[0] + sys.exit(1) + srcdir = sys.argv[1] + blddir = sys.argv[2] + lang = sys.argv[3] + files = sys.argv[4:] + files.sort() + + if os.path.exists( blddir ): + removeDir( blddir ) + os.makedirs( blddir ) + + menu_toc = '' + files_string = '' + for filename in files: + files_string += '%s\n' % filename + if filename.endswith( 'menu.html' ): + try: + f = open( os.path.join( srcdir, filename ), 'r' ) + except IOError: + continue + parser = MyParser() + parser.parse( f.read() ) + menu_toc = parser.get_xml(13, lang) + + + qhp_file_src = os.path.join( srcdir, lang + '.qhp' ) + qhp_file_bld = os.path.join( blddir, lang + '.qhp' ) + infile = open( qhp_file_src, "r" ) + outfile = open( qhp_file_bld, "w" ) + for line in infile: + line = line.replace( "@FILES@", files_string ).replace( "@MENU_TOC@", menu_toc ) + outfile.write(line) + infile.close() + outfile.close() + + + qhcp_file_src = os.path.join( srcdir, lang + '.qhcp' ) + qhcp_file_bld = os.path.join( blddir, lang + '.qhcp' ) + shutil.copy( qhcp_file_src, qhcp_file_bld ) + + + for filename in files: + src = os.path.join( srcdir, filename ) + dst = os.path.join( blddir, filename ) + if not os.path.exists( src ): + print >> sys.stderr, "Source file %s does not exist - skipping" % src + continue + + if ( os.path.exists( dst ) and os.path.isfile( dst ) ) and\ + ( os.path.getsize( src ) == os.path.getsize( dst ) ) and\ + ( os.stat( src ).st_mtime <= os.stat( dst ).st_mtime ): + continue + + dstdir = os.path.dirname( dst ) + if not os.path.isdir( dstdir ): + + if os.path.exists( dstdir ): + os.remove( dstdir ) + os.makedirs( dstdir ) + shutil.copy( src, dst ) + +if __name__ == "__main__": + main() diff --git a/cmake/ngl_dep_test_main.cpp b/cmake/ngl_dep_test_main.cpp new file mode 100755 index 000000000..474486e44 --- /dev/null +++ b/cmake/ngl_dep_test_main.cpp @@ -0,0 +1,5 @@ +int main(int, char**) +{ + return 0; +} +