Qt6 Migration: Complete migration with DDS/RTI support and build validation
Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list
Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF
Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
- Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
- Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)
Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified
Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
18662 files changed
+4115092
-5435
No files matched your search
@@ -0,0 +1,34 @@
|
||||
AccessModifierOffset: -4
|
||||
AlignTrailingComments: true
|
||||
AlignAfterOpenBracket: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
InsertNewlineAtEOF: true
|
||||
BreakBeforeBinaryOperators: true
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
ColumnLimit: 170
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
IncludeCategories:
|
||||
- Regex: '^\"((?!\/).)*\"$'
|
||||
Priority: 1
|
||||
- Regex: '^(\<.*\/.*\>)$'
|
||||
Priority: 2
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
PenaltyBreakBeforeFirstCallParameter: 1000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Right
|
||||
PointerBindsToType: false
|
||||
SortIncludes: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpacesInAngles: false
|
||||
SpacesInParentheses: false
|
||||
Standard: Cpp11
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,4 @@
|
||||
/CMakeLists.txt.user*
|
||||
/build
|
||||
.vscode
|
||||
.cache
|
||||
@@ -0,0 +1,172 @@
|
||||
##########################
|
||||
# BASE Pipeline
|
||||
# Adjust
|
||||
# ARTIFACTORY_PATH -> Path where we upload the final RPM zips on the asset repository
|
||||
# PROJECT_BASE_DIR -> this is how the git exports the file its the same as the projects-domain-live/guez/<fork_name>/legatus/ name
|
||||
# cmake_build_flags -> add specific BUILD Params per Project like uas proxy or HLA etc
|
||||
# NON GUEZ
|
||||
# BUILD_IMAGE -> the build images to use there is guez, federates and lynxhu
|
||||
# When used they are tagged: <PROJECT>:<OSVERSION>
|
||||
# Not every <OSVERSION> is available for each Project
|
||||
# guez: 15.4 15.1 42.3
|
||||
# federates: 15.4
|
||||
# lynxhu: 15.5
|
||||
#########################
|
||||
|
||||
default:
|
||||
interruptible: true
|
||||
|
||||
variables:
|
||||
PROJECT_NAME: 'guez'
|
||||
TDS_MAJOR_VERSION: '1.3'
|
||||
BUILD_IMAGE: 'asset-repository.sf.defence-elec.de/docker-rme/livesim/guez'
|
||||
CHECKOUT_IMAGE: 'asset-repository.sf.defence-elec.de/docker-local/docker/docker:git'
|
||||
ARTIFACTORY: 'http://asset-repository.sf.defence-elec.de:80/artifactory'
|
||||
ARTIFACTORY_PATH: 'generic-rme/livesim/guez/dlbo'
|
||||
RUNNER_TAG: ''
|
||||
|
||||
stages:
|
||||
- checkout
|
||||
- workflow
|
||||
- build
|
||||
- test-release
|
||||
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == "master"
|
||||
variables:
|
||||
RUNNER_TAG: "ram_20g"
|
||||
- if: $CI_COMMIT_REF_NAME != "master"
|
||||
variables:
|
||||
RUNNER_TAG: "docker"
|
||||
- when: always
|
||||
|
||||
checkout:
|
||||
tags:
|
||||
- docker
|
||||
stage: checkout
|
||||
interruptible: true
|
||||
image: $CHECKOUT_IMAGE
|
||||
script:
|
||||
- git clone http://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab-sg1.defence-elec.de/projects-domain-live/rpmbuild.git
|
||||
artifacts:
|
||||
paths:
|
||||
- rpmbuild/
|
||||
|
||||
build:
|
||||
parallel:
|
||||
matrix:
|
||||
- VERSION: "15.1"
|
||||
- VERSION: "15.4"
|
||||
- VERSION: "42.3"
|
||||
# - VERSION: "15.6"
|
||||
tags: [$RUNNER_TAG]
|
||||
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
#- ram_20g
|
||||
timeout: 5h
|
||||
stage: build
|
||||
image: ${BUILD_IMAGE}:${VERSION}
|
||||
dependencies:
|
||||
- checkout
|
||||
#interruptible: true
|
||||
#resource_group: team7
|
||||
variables:
|
||||
BUILD_VERSION: $VERSION
|
||||
VERSION_DATE: $CI_COMMIT_TIMESTAMP
|
||||
PROJECT_BASE_DIR: /builds/projects-domain-live/guez/dlbo/legatus
|
||||
EMERGE_VERBOSE: 1 # Verbosity level 0:warning 1:info 2:debug
|
||||
script:
|
||||
- export BUILD_NUMBER=$(date +%Y%m%d%H)
|
||||
- echo '%_smp_mflags -j 4' > ~/.rpmmacros # Limit the number of cores used by the build to 4. https://rpm-packaging-guide.github.io/
|
||||
- cp -a rpmbuild /shd/CTC/TOOLS/rpmbuild
|
||||
- mkdir /shd/CTC/TOOLS/rpms
|
||||
- cd /shd/CTC/TOOLS/rpmbuild
|
||||
- |
|
||||
echo "TAG: $RUNNER_TAG"
|
||||
echo "Current Branch: $CI_COMMIT_REF_NAME"
|
||||
if [ $CI_COMMIT_REF_NAME == master ];
|
||||
then
|
||||
echo '%_smp_mflags -j 4' > ~/.rpmmacros # Limit the number of cores used by the build to 4. https://rpm-packaging-guide.github.io/
|
||||
|
||||
if [ $VERSION == 42.3 ];
|
||||
then
|
||||
echo "build 42.3"
|
||||
python ./make_rpmModule.py -c LTS \
|
||||
--project_name $PROJECT_NAME \
|
||||
--version $TDS_MAJOR_VERSION \
|
||||
--output_dir /shd/CTC/TOOLS/rpms/ \
|
||||
-h true \
|
||||
-t false \
|
||||
-w false \
|
||||
--cmake_build_flags='-DUSE_IPO=ON -DBUILD_ALL=OFF -DUSE_UNITY_BUILD=ON -DGUEZ_MODE=ON -DBUILD_SV=OFF -DBUILD_AAR=OFF -DBUILD_HLA=ON -DBUILD_WLS=OFF -DBUILD_SVC_HLA=ON -DBUILD_TOOLSWS=OFF -DBUILD_TOOLSSV=OFF -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/pgsql/'
|
||||
else
|
||||
echo "$VERSION"
|
||||
python ./make_rpm.py -c LTS \
|
||||
--project_name $PROJECT_NAME \
|
||||
--version $TDS_MAJOR_VERSION \
|
||||
--output_dir /shd/CTC/TOOLS/rpms/ \
|
||||
--cmake_build_flags='-DUSE_IPO=ON -DUSE_UNITY_BUILD=ON -DGUEZ_MODE=ON -DBUILD_WLS=OFF -DBUILD_SVC_HLA=OFF -DBUILD_TOOLSWS=ON -DBUILD_TOOLSSV=ON -DBUILD_UAS_PROXY=ON -DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/pgsql/'
|
||||
fi
|
||||
else
|
||||
echo "$VERSION !!!! NO conti Build"
|
||||
fi
|
||||
- |
|
||||
echo "Current Branch: $CI_COMMIT_REF_NAME"
|
||||
if [ $CI_COMMIT_REF_NAME == master ];
|
||||
then
|
||||
echo "BUILD ZIP and UPLOAD"
|
||||
zip -qr $PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip /shd/CTC/TOOLS/rpms/$PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER
|
||||
curl -sS \
|
||||
-u $RME_CI_GENERIC_WRITER_USER:$RME_CI_GENERIC_WRITER_TOKEN \
|
||||
-H "X-Checksum-Sha256: $(sha256sum $PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip | awk '{print $1}')" \
|
||||
-H "X-Checksum-Sha1: $(sha1sum $PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip | awk '{print $1}')" \
|
||||
-H "X-Checksum-Md5: $(md5sum $PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip | awk '{print $1}')" \
|
||||
-X PUT "$ARTIFACTORY/$ARTIFACTORY_PATH/$VERSION/$PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip" \
|
||||
-T $PROJECT_NAME-TDS-$TDS_MAJOR_VERSION-$BUILD_NUMBER-$VERSION.zip
|
||||
else
|
||||
echo "NO BUILD ZIP and UPLOAD"
|
||||
fi
|
||||
|
||||
weekly_release:
|
||||
stage: build
|
||||
image: ${BUILD_IMAGE}:15.1
|
||||
tags:
|
||||
- docker
|
||||
rules:
|
||||
- if: '$WEEKLY_RELEASE == "true"'
|
||||
variables:
|
||||
PROJECT_BASE_DIR: /builds/projects-domain-live/guez/legatus
|
||||
artifacts:
|
||||
paths:
|
||||
- changelog.md
|
||||
before_script:
|
||||
- git config --global --add safe.directory $PROJECT_BASE_DIR
|
||||
- git fetch --tags
|
||||
script:
|
||||
- LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
|
||||
- VER="v$(date +%Y).$(date +%V)"
|
||||
- |
|
||||
if [ "$LAST_TAG" = "none" ]; then
|
||||
RANGE="HEAD"
|
||||
else
|
||||
RANGE="$LAST_TAG..HEAD"
|
||||
fi
|
||||
- echo "Range= $RANGE LastTag= $LAST_TAG Version= $VER"
|
||||
- git log $RANGE --pretty=format:"%s" > jira_tickets.txt
|
||||
|
||||
- echo "Weekly Release $VER" > changelog.md
|
||||
- echo "" >> changelog.md
|
||||
- echo "Commits" >> changelog.md
|
||||
- git log $RANGE --pretty=format:"- %s" >> changelog.md
|
||||
- echo "" >> changelog.md
|
||||
- while read t; do echo "- $t"; done < jira_tickets.txt >> changelog.md
|
||||
- git config --global user.name "schmidt_n"
|
||||
- git config --global user.email "niklas.schmidt@rheinmetall.com"
|
||||
- git tag "$VER"
|
||||
- git push --tags http://root:EYQJTVoFUEdgbb23KSuJ@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:master
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Configfile für CDash unter http://guezrs/CDash
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
# do not limit the number of warnings
|
||||
set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS 10000)
|
||||
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Hanna Rathje, SLSE, 2017-12-14
|
||||
#
|
||||
|
||||
SET(SRCS
|
||||
aar_application.cpp
|
||||
aar_application.h
|
||||
databases_model.cpp
|
||||
databases_model.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(SRCS aarApp.ui)
|
||||
|
||||
NGL_ADD_EXECUTABLE(AAR aarApp ${SRCS})
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(aarApp
|
||||
Qt5::Widgets
|
||||
Qt5::Core
|
||||
nglapplication
|
||||
ngldb
|
||||
nglcoreapplication
|
||||
ngltools
|
||||
ngltranslator
|
||||
nglwidgets
|
||||
NGLLogger
|
||||
LtsCommandLineParser
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(aarApp)
|
||||
NGL_INSTALL(AAR FILES log4cxx_aarApp.props DESTINATION bin)
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AarApplication</class>
|
||||
<widget class="QMainWindow" name="AarApplication">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::WindowModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>846</width>
|
||||
<height>382</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Database administration</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblStatus">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>No active database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblDatabases">
|
||||
<property name="text">
|
||||
<string>Databases:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableViewDatabases">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbActivateNetwork">
|
||||
<property name="text">
|
||||
<string>Activate network database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbActivate">
|
||||
<property name="text">
|
||||
<string>Activate local database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbRemove">
|
||||
<property name="text">
|
||||
<string>Remove database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbClose">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<action name="actionShow">
|
||||
<property name="text">
|
||||
<string>&Show</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStart">
|
||||
<property name="text">
|
||||
<string>&Start</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStop">
|
||||
<property name="text">
|
||||
<string>St&op</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>oeffnenClicked()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#include "aar_application.h"
|
||||
#include "ui_aarApp.h"
|
||||
#include "databases_model.h"
|
||||
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QMenu>
|
||||
#include <QSettings>
|
||||
#include <QDir>
|
||||
#include <QThread>
|
||||
#include <QScreen>
|
||||
#include <QSqlError>
|
||||
|
||||
#define DEFAULT_DB "lts_ets_pro"
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
|
||||
AarApplication::AarApplication(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_ui(new Ui::AarApplication)
|
||||
, m_stopping(false)
|
||||
, m_proc(nullptr)
|
||||
, m_progressDialog(nullptr)
|
||||
, m_logger(getLogger("AarApplication"))
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
|
||||
const QList<QScreen*> &screenList = QGuiApplication::screens();
|
||||
m_widgets.reserve(screenList.size());
|
||||
for (QScreen *s : qAsConst(screenList))
|
||||
{
|
||||
QWidget *w = new QWidget(); // no parent
|
||||
w->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
|
||||
w->setGeometry(s->geometry());
|
||||
w->activateWindow();
|
||||
w->show();
|
||||
m_widgets.append(w);
|
||||
}
|
||||
|
||||
m_databasesModel = new DatabasesModel(this);
|
||||
m_proxyModel = new DatabasesProxyModel(this);
|
||||
m_proxyModel->setSourceModel(m_databasesModel);
|
||||
m_ui->tableViewDatabases->setModel(m_proxyModel);
|
||||
|
||||
connect(m_ui->pbClose, &QPushButton::clicked, this, &AarApplication::onClosedClicked);
|
||||
connect(m_ui->pbRemove, &QPushButton::clicked, this, &AarApplication::onRemoveClicked);
|
||||
connect(m_ui->pbActivate, &QPushButton::clicked, this, &AarApplication::onActivateClicked);
|
||||
connect(m_ui->pbActivateNetwork, &QPushButton::clicked, this, &AarApplication::onActivateNetworkClicked);
|
||||
|
||||
connect(m_ui->tableViewDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AarApplication::enaDisa);
|
||||
|
||||
setWindowTitle(QLatin1String("AarApplication"));
|
||||
|
||||
enaDisa();
|
||||
|
||||
m_progressDialog = new QProgressDialog(this);
|
||||
|
||||
m_progressDialog->setLabelText(tr("Stopping server software ..."));
|
||||
m_progressDialog->setMinimum(0);
|
||||
m_progressDialog->setMaximum(0);
|
||||
m_progressDialog->show();
|
||||
onStopApp();
|
||||
|
||||
}
|
||||
|
||||
AarApplication::~AarApplication()
|
||||
{
|
||||
delete m_ui;
|
||||
delete m_databasesModel;
|
||||
delete m_progressDialog;
|
||||
|
||||
for (QSqlDatabase db : qAsConst(m_dbMap))
|
||||
db.close();
|
||||
|
||||
m_dbPostgres.close();
|
||||
|
||||
if (m_proc)
|
||||
m_proc->deleteLater();
|
||||
|
||||
qDeleteAll(m_widgets);
|
||||
}
|
||||
|
||||
bool AarApplication::init()
|
||||
{
|
||||
m_ui->lblStatus->setText(tr("No active database"));
|
||||
|
||||
m_dbPostgres = DBConnection::open(m_logger,
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("QPSQL"),
|
||||
QStringLiteral("localhost"),
|
||||
QStringLiteral("postgres"),
|
||||
QString(),
|
||||
QStringLiteral("localhost_postgres"));
|
||||
|
||||
if (!m_dbPostgres.open())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening postgres database" << m_dbPostgres.lastError().databaseText();
|
||||
return false;
|
||||
}
|
||||
|
||||
NSqlQuery q(m_dbPostgres);
|
||||
|
||||
QString stmt = QStringLiteral("SELECT datname FROM pg_database WHERE datname = '") + QStringLiteral(DEFAULT_DB) + QStringLiteral("'");
|
||||
|
||||
if (!q.execAndFetch(stmt))
|
||||
{
|
||||
NOTICE_LOG(m_logger) << "Database does not exist: " << DEFAULT_DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
QSqlDatabase db_lts = DBConnection::open(m_logger,
|
||||
QStringLiteral("ctc_sv"),
|
||||
QStringLiteral("ctc11de"),
|
||||
QStringLiteral("QPSQL"),
|
||||
QStringLiteral("localhost"),
|
||||
QStringLiteral(DEFAULT_DB),
|
||||
QString(),
|
||||
QStringLiteral("localhost_")+QStringLiteral(DEFAULT_DB));
|
||||
|
||||
if (!db_lts.open())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening database " << DEFAULT_DB << " : "<< db_lts.lastError().databaseText();
|
||||
m_dbPostgres.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
NSqlQuery ql(db_lts);
|
||||
|
||||
stmt = QStringLiteral("SELECT id FROM exm.exercise");
|
||||
|
||||
if (!ql.execAndFetch(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No entry for exercise found in database " << DEFAULT_DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dbId = ql.value(0).toInt();
|
||||
db_lts.close();
|
||||
|
||||
QString dbName = QStringLiteral("lts_db_") + QString::number(dbId);
|
||||
INFO_LOG(m_logger) << "New dbName for " << DEFAULT_DB << ": " << dbName;
|
||||
|
||||
stmt = QStringLiteral("ALTER DATABASE ") + QStringLiteral(DEFAULT_DB) + QStringLiteral(" RENAME TO ") + dbName;
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error renaming database " << DEFAULT_DB << " : " << db_lts.lastError().databaseText();
|
||||
m_dbPostgres.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stmt = QStringLiteral("SELECT datname FROM pg_database WHERE datname ilike 'lts_db_%';");
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while reading dbnames from database";
|
||||
return false;
|
||||
}
|
||||
|
||||
while (q.next())
|
||||
{
|
||||
QString dbName = q.value(0).toString();
|
||||
QSqlDatabase db = DBConnection::open(m_logger,
|
||||
QStringLiteral("ctc_sv"),
|
||||
QStringLiteral("ctc11de"),
|
||||
QStringLiteral("QPSQL"),
|
||||
QStringLiteral("localhost"),
|
||||
dbName,
|
||||
QString(),
|
||||
QStringLiteral("localhost_") + dbName);
|
||||
|
||||
if (!db.open())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while opening database " << dbName << ", error: " << db.lastError().databaseText();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_databasesModel->initModel(db);
|
||||
m_dbMap.insert(dbName, db);
|
||||
}
|
||||
|
||||
m_ui->tableViewDatabases->resizeColumnsToContents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AarApplication::onClosedClicked()
|
||||
{
|
||||
handleProcInit(QStringLiteral("/usr/bin/openbox"), {QStringLiteral("--exit")});
|
||||
m_proc->start();
|
||||
m_proc->waitForFinished();
|
||||
QThread::sleep(2);
|
||||
close();
|
||||
}
|
||||
|
||||
void AarApplication::onRemoveClicked()
|
||||
{
|
||||
disableButtons();
|
||||
|
||||
m_databaseToRemove = m_databasesModel->getRowData(m_ui->tableViewDatabases->currentIndex().row());
|
||||
|
||||
QString strMsg = QStringLiteral("Do you really want to remove the database '%1'?").arg (m_databaseToRemove.dbName);
|
||||
int result = QMessageBox::question(this, tr("Remove Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (result == QMessageBox::No)
|
||||
{
|
||||
enableButtons();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "onRemoveClicked: dbName = " << m_databaseToRemove.dbName;
|
||||
QSqlDatabase db = m_dbMap.value(m_databaseToRemove.dbName);
|
||||
db.close();
|
||||
|
||||
const QStringList args({QStringLiteral("-U"),
|
||||
QStringLiteral("postgres"),
|
||||
QStringLiteral("-h"),
|
||||
QStringLiteral("localhost"),
|
||||
m_databaseToRemove.dbName
|
||||
});
|
||||
|
||||
QString errStr;
|
||||
const QString exePath = NGL::postgresExecutablePath(QStringLiteral("dropdb"), errStr);
|
||||
if (!errStr.isEmpty())
|
||||
WARNING_LOG(m_logger) << errStr;
|
||||
|
||||
handleProcInit(exePath, args);
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &AarApplication::onDropDbFinished);
|
||||
|
||||
// start process
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
void AarApplication::onActivateClicked()
|
||||
{
|
||||
const QString fileName = QStringLiteral("/shd/CTC/WS/lts-cc.conf.org");
|
||||
|
||||
WARNING_LOG(m_logger) << "FileName: " << fileName;
|
||||
QFile ltsConfig(fileName);
|
||||
|
||||
if (ltsConfig.exists())
|
||||
ltsConfig.rename(QStringLiteral("/shd/CTC/WS/lts-cc.conf.org"), QStringLiteral("/shd/CTC/WS/lts-cc.conf"));
|
||||
|
||||
Exercise ex = m_databasesModel->getRowData(m_ui->tableViewDatabases->currentIndex().row());
|
||||
|
||||
QString strMsg = tr("Do you really want to activate database '%1'?").arg(ex.name);
|
||||
int result = QMessageBox::question(this, tr("Activate local database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (result == QMessageBox::No)
|
||||
return;
|
||||
|
||||
INFO_LOG(m_logger) << "onActivateClicked: dbName = " << ex.dbName;
|
||||
|
||||
QSqlDatabase db = m_dbMap.value(ex.dbName);
|
||||
db.close();
|
||||
|
||||
NSqlQuery q(m_dbPostgres);
|
||||
|
||||
QString stmt = QStringLiteral("ALTER DATABASE ") + ex.dbName + QStringLiteral(" RENAME TO ") + QStringLiteral(DEFAULT_DB);
|
||||
|
||||
if (!q.exec(stmt))
|
||||
ERROR_LOG(m_logger) << "Error renaming " << ex.dbName << " to " << DEFAULT_DB << " "<< m_dbPostgres.lastError().databaseText();
|
||||
else
|
||||
INFO_LOG(m_logger) << "Database " << ex.dbName << " renamed to " << DEFAULT_DB;
|
||||
|
||||
QString status = ex.name + QStringLiteral(" (") + ex.dbName + QStringLiteral(") ") + tr("active");
|
||||
m_ui->lblStatus->setText(status);
|
||||
onStartApp();
|
||||
}
|
||||
|
||||
void AarApplication::onActivateNetworkClicked()
|
||||
{
|
||||
onStopApp();
|
||||
//const QString fileName = QDir::homePath()+ QStringLiteral("/lts-cc.conf");
|
||||
|
||||
const QString fileName = QStringLiteral("/shd/CTC/WS") + QStringLiteral("/lts-cc.conf");
|
||||
|
||||
WARNING_LOG(m_logger) << "FileName: " << fileName;
|
||||
QFile ltsConfig(fileName);
|
||||
|
||||
if (!ltsConfig.exists())
|
||||
{
|
||||
QMessageBox::critical(this, tr ("Activate network database"), tr("Network database active"), QMessageBox::Ok);
|
||||
m_ui->lblStatus->setText(tr("Network database active"));
|
||||
return;
|
||||
}
|
||||
|
||||
ltsConfig.rename(QStringLiteral("/shd/CTC/WS/lts-cc.conf"), QStringLiteral("/shd/CTC/WS/lts-cc.conf.org"));
|
||||
m_ui->lblStatus->setText(tr("Network database active"));
|
||||
}
|
||||
|
||||
void AarApplication::enaDisa()
|
||||
{
|
||||
if (!m_ui)
|
||||
return;
|
||||
int selected = m_ui->tableViewDatabases->selectionModel()->selectedRows().size();
|
||||
|
||||
m_ui->pbRemove->setEnabled(selected > 0);
|
||||
m_ui->pbActivate->setEnabled(selected > 0);
|
||||
}
|
||||
|
||||
void AarApplication::onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onDropDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
|
||||
|
||||
static const QString s_title = tr("Remove Database");
|
||||
static const QString s_msgFailure = tr("Removing database failed.");
|
||||
static const QString s_msgSuccess = tr("Removing database successful.");
|
||||
|
||||
if (exitCode > 0)
|
||||
{
|
||||
const QString str = QString::fromLocal8Bit(m_proc->readAllStandardError()) + QLatin1Char('\n') +
|
||||
QString::fromLocal8Bit(m_proc->readAllStandardOutput());
|
||||
ERROR_LOG(m_logger) << "Cannot drop database: " << str;
|
||||
QString msg = s_msgFailure;
|
||||
QString db0 = QLatin1String("ERROR: database \"") + m_databaseToRemove.dbName + QLatin1String("\" does not exist");
|
||||
if (!str.contains(db0))
|
||||
msg += tr(" Database cannot be removed:\n%1.").arg(str);
|
||||
QMessageBox::critical(this, s_title, msg, QMessageBox::Ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_databasesModel->onDataChanged(m_databaseToRemove, DataModification::eRemoved);
|
||||
QMessageBox::information(this, s_title, s_msgSuccess);
|
||||
}
|
||||
|
||||
enableButtons();
|
||||
}
|
||||
|
||||
void AarApplication::onErrorOccured(QProcess::ProcessError error)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "error: " << error;
|
||||
}
|
||||
|
||||
void AarApplication::onStartApp()
|
||||
{
|
||||
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &AarApplication::onPsauxFinished);
|
||||
m_proc->start();
|
||||
}
|
||||
|
||||
|
||||
void AarApplication::onPsauxFinished()
|
||||
{
|
||||
enableButtons();
|
||||
QByteArray output = m_proc->readAllStandardOutput();
|
||||
|
||||
if (output.contains("svcServiceManagement"))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ServiceManagement already started";
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Start svcServiceManagement";
|
||||
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-z")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &AarApplication::onStartAppFinished);
|
||||
m_proc->start();
|
||||
m_proc->waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void AarApplication::onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
handleProcFinished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void AarApplication::onStopApp()
|
||||
{
|
||||
disableButtons();
|
||||
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
|
||||
m_proc->start();
|
||||
if (m_proc->waitForFinished())
|
||||
onPsauxStopFinished();
|
||||
}
|
||||
|
||||
void AarApplication::onPsauxStopFinished()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "IN onPsauxStopFinished";
|
||||
enableButtons();
|
||||
QByteArray output = m_proc->readAllStandardOutput();
|
||||
|
||||
if (output.contains("svcServiceManagement"))
|
||||
{
|
||||
if (m_stopping)
|
||||
{
|
||||
QThread::sleep(3);
|
||||
onStopApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ERROR_LOG(m_logger) << "ServiceManagement started - stopping";
|
||||
|
||||
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-s")});
|
||||
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &AarApplication::onStopAppFinished);
|
||||
m_proc->start();
|
||||
m_stopping = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(m_logger) << "ServiceManagement already stopped";
|
||||
m_stopping = false;
|
||||
m_progressDialog->hide();
|
||||
}
|
||||
|
||||
m_proc->waitForFinished();
|
||||
}
|
||||
|
||||
void AarApplication::onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (m_stopping)
|
||||
onPsauxStopFinished();
|
||||
|
||||
handleProcFinished(exitCode, exitStatus);
|
||||
}
|
||||
|
||||
void AarApplication::handleProcInit(const QString &program, const QStringList &args)
|
||||
{
|
||||
if (m_proc)
|
||||
{
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
}
|
||||
m_proc = new QProcess(this);
|
||||
NOTICE_LOG(m_logger) << "Starting process '" << program << "' with args '"
|
||||
<< args.join(QLatin1Char(' ')) << "'";
|
||||
|
||||
m_proc->setProgram(program);
|
||||
m_proc->setArguments(args);
|
||||
connect(m_proc, &QProcess::errorOccurred, this, &AarApplication::onErrorOccured);
|
||||
disableButtons();
|
||||
}
|
||||
|
||||
void AarApplication::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
enableButtons();
|
||||
|
||||
if (!m_proc)
|
||||
return;
|
||||
if (exitCode != 0 || exitStatus != 0)
|
||||
{
|
||||
QByteArray out = m_proc->readAllStandardError();
|
||||
if (!out.isEmpty())
|
||||
out += '\n';
|
||||
out += m_proc->readAllStandardOutput();
|
||||
ERROR_LOG(m_logger) << "Process finished - exitCode: " << exitCode << ", exitStatus = " << exitStatus << ", " << out;
|
||||
|
||||
QMessageBox::critical(this,
|
||||
tr ("Execute process"), tr("Error executing process, exitCode: %1, exitStatus: %2, output: %3")
|
||||
.arg(exitCode).arg(exitStatus).arg(QString::fromLocal8Bit(out)),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
m_proc->disconnect(this);
|
||||
m_proc->deleteLater();
|
||||
m_proc = nullptr;
|
||||
|
||||
if (m_progressDialog)
|
||||
m_progressDialog->hide();
|
||||
}
|
||||
|
||||
|
||||
void AarApplication::enaDisaButtons(bool bEnable)
|
||||
{
|
||||
{
|
||||
const QList<QPushButton*> l = findChildren<QPushButton*>();
|
||||
for (QPushButton *pb : l)
|
||||
pb->setEnabled(bEnable);
|
||||
}
|
||||
{
|
||||
const QList<QAction*> l = findChildren<QAction*>();
|
||||
for (QAction *a : l)
|
||||
a->setEnabled(bEnable);
|
||||
}
|
||||
if (bEnable)
|
||||
enaDisa();
|
||||
}
|
||||
|
||||
} // namespace AarApplication
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <QStandardItemModel>
|
||||
#include <QVector>
|
||||
#include <QCloseEvent>
|
||||
#include <QProcess>
|
||||
#include <QProgressDialog>
|
||||
#include <QMenuBar>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "logger.h"
|
||||
#include "databases_model.h"
|
||||
|
||||
namespace Ui {
|
||||
class AarApplication;
|
||||
}
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
class AarApplication : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AarApplication(QWidget *parent = nullptr);
|
||||
~AarApplication();
|
||||
|
||||
bool init();
|
||||
|
||||
private slots:
|
||||
void onClosedClicked();
|
||||
void onRemoveClicked();
|
||||
void onActivateClicked();
|
||||
void onActivateNetworkClicked();
|
||||
void onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPsauxFinished();
|
||||
void onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onPsauxStopFinished();
|
||||
void onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void onErrorOccured(QProcess::ProcessError error);
|
||||
void onStartApp();
|
||||
void onStopApp();
|
||||
|
||||
private:
|
||||
void enaDisa();
|
||||
void handleProcInit(const QString &program, const QStringList &args);
|
||||
void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void disableButtons() { enaDisaButtons(false); }
|
||||
void enableButtons() { enaDisaButtons(true); }
|
||||
void enaDisaButtons(bool bEnable);
|
||||
|
||||
|
||||
private:
|
||||
Ui::AarApplication *m_ui;
|
||||
DatabasesModel *m_databasesModel;
|
||||
DatabasesProxyModel *m_proxyModel;
|
||||
QMap<QString, QSqlDatabase> m_dbMap;
|
||||
bool m_stopping;
|
||||
Exercise m_databaseToRemove;
|
||||
QProcess *m_proc;
|
||||
QSqlDatabase m_dbPostgres;
|
||||
QProgressDialog *m_progressDialog;
|
||||
QVector<QWidget*> m_widgets;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
} // namespace AARApplication
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#include "databases_model.h"
|
||||
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QPalette>
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
|
||||
DatabasesModel::DatabasesModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_logger(getLogger("DatabasesModel"))
|
||||
{
|
||||
beginResetModel();
|
||||
m_vecData.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool DatabasesModel::initModel(const QSqlDatabase &db)
|
||||
{
|
||||
NSqlQuery q(db);
|
||||
|
||||
QString stmt = QStringLiteral("SELECT id, name, begin_time, end_time, exercise_state_id FROM exm.exercise");
|
||||
|
||||
if (!q.prepare(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Preparing statement '" << stmt << "' failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!q.exec(stmt))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Executing statement '" << stmt << "' failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
while (q.next())
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "More than one exercise detected. There should be only one exercise per database.";
|
||||
break;
|
||||
}
|
||||
|
||||
Exercise exercise;
|
||||
exercise.id = q.value(0).toInt();
|
||||
exercise.name = q.value(1).toString();
|
||||
exercise.startTime = q.value(2).toLongLong();
|
||||
exercise.endTime = q.value(3).toLongLong();
|
||||
exercise.dbName = QStringLiteral("lts_db_") + QString::number(exercise.id);
|
||||
exercise.stateId = q.value(4).toInt();
|
||||
TRACE_LOG(m_logger) << "Found exercise with id=" << exercise.id << ", name=" << exercise.name << ", startTime="
|
||||
<< exercise.startTime << ", endTime=" << exercise.endTime << ", dbName=" << exercise.dbName
|
||||
<< ", stateId=" << exercise.stateId;
|
||||
if (exercise.stateId != 6)
|
||||
onDataChanged(exercise, DataModification::eAdded);
|
||||
++count;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "initModel - #exercises: " << m_vecData.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVariant DatabasesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || !index.isValid() || index.row() >= m_vecData.size())
|
||||
return QVariant();
|
||||
|
||||
const Exercise &e = m_vecData.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case Id:
|
||||
return e.id;
|
||||
case Name:
|
||||
return QString(e.name);
|
||||
case StartTime:
|
||||
return DTG::toStringMSec(e.startTime);
|
||||
case EndTime:
|
||||
return DTG::toStringMSec(e.endTime);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int DatabasesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_vecData.size();
|
||||
}
|
||||
|
||||
int DatabasesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : EndTime + 1;
|
||||
}
|
||||
|
||||
QVariant DatabasesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal
|
||||
&& role == Qt::DisplayRole)
|
||||
{
|
||||
Columns col = static_cast<Columns>(section);
|
||||
switch (col)
|
||||
{
|
||||
case Id:
|
||||
return tr("Id");
|
||||
case Name:
|
||||
return tr("Name");
|
||||
case StartTime:
|
||||
return tr("Start Time");
|
||||
case EndTime:
|
||||
return tr("End Time");
|
||||
}
|
||||
}
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
Exercise DatabasesModel::getRowData(int row) const
|
||||
{
|
||||
if (row < 0 || row >= m_vecData.size())
|
||||
return Exercise();
|
||||
return m_vecData.at(row);
|
||||
}
|
||||
|
||||
bool DatabasesModel::insertRow(const Exercise &item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
|
||||
m_vecData.append(item);
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabasesModel::removeRow(const int &row)
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_vecData.remove(row);
|
||||
endRemoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DatabasesModel::onDataChanged(const Exercise &data, DataModification modType)
|
||||
{
|
||||
int row = -1;
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
row = m_vecData.size();
|
||||
if (insertRow(data))
|
||||
emit dataChanged(index(row, Columns::Id), index(row, Columns::EndTime));
|
||||
return;
|
||||
|
||||
case DataModification::eModified:
|
||||
row = m_vecData.indexOf(data);
|
||||
if (row != -1)
|
||||
{
|
||||
m_vecData[row] = data;
|
||||
emit dataChanged(index(row, Columns::Id), index(row, Columns::EndTime));
|
||||
}
|
||||
return;
|
||||
|
||||
case DataModification::eRemoved:
|
||||
row = m_vecData.indexOf(data);
|
||||
if (row != -1)
|
||||
if (removeRow(row))
|
||||
emit dataChanged(index(std::min(row, m_vecData.size()-1), Columns::Id), index(m_vecData.size()-1, Columns::EndTime));
|
||||
return;
|
||||
} // switch
|
||||
}
|
||||
|
||||
|
||||
void DatabasesProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
m_sourceModel = qobject_cast<DatabasesModel*>(sourceModel);
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool DatabasesProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (!m_sourceModel ||
|
||||
source_left.column() != source_right.column() ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid())
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
|
||||
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
|
||||
switch (source_left.column())
|
||||
{
|
||||
case DatabasesModel::StartTime:
|
||||
return dataLeft.startTime < dataRight.startTime;
|
||||
case DatabasesModel::EndTime:
|
||||
return dataLeft.endTime < dataRight.endTime;
|
||||
case DatabasesModel::Id:
|
||||
case DatabasesModel::Name:
|
||||
break;
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
|
||||
} // namespace AARApplication
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* PresentationManangement - Script Overview Dialog Model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-03-15
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <LtsUtils/LtsUtilsCore/data_modification_enum.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
|
||||
class QSqlDatabase;
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
|
||||
struct Exercise
|
||||
{
|
||||
qint32 id = 0;
|
||||
QString name;
|
||||
QString dbName;
|
||||
qint64 startTime = 0;
|
||||
qint64 endTime = 0;
|
||||
qint32 stateId = 0;
|
||||
|
||||
bool operator == (const Exercise &other) { return id == other.id; }
|
||||
bool operator != (const Exercise &other) { return id != other.id; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DatabasesModel
|
||||
//
|
||||
class DatabasesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
Id = 0,
|
||||
Name,
|
||||
StartTime,
|
||||
EndTime
|
||||
};
|
||||
|
||||
explicit DatabasesModel(QObject *parent = nullptr);
|
||||
~DatabasesModel() = default;
|
||||
|
||||
bool initModel(const QSqlDatabase &db);
|
||||
|
||||
QVariant data(const QModelIndex &, int) const override final;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override final;
|
||||
int columnCount(const QModelIndex &parent) const override final;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
|
||||
Exercise getRowData(int row) const;
|
||||
bool insertRow(const Exercise &item);
|
||||
bool removeRow(const int &row);
|
||||
|
||||
friend class DatabasesProxyModel;
|
||||
|
||||
protected:
|
||||
|
||||
public slots:
|
||||
void onDataChanged(const Exercise &data, DataModification modType);
|
||||
|
||||
private:
|
||||
QVector<Exercise> m_vecData;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DatabasesProxyModel
|
||||
//
|
||||
class DatabasesProxyModel final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using QSortFilterProxyModel::QSortFilterProxyModel;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
|
||||
private:
|
||||
DatabasesModel *m_sourceModel = nullptr;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# DbAdministration
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.DbAdministration=DEBUG
|
||||
|
||||
# File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "DBA.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AARApplication
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for Evaluations
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
|
||||
namespace AARApplication
|
||||
{
|
||||
typedef NGL::INGLLogger &LOGGER_T;
|
||||
|
||||
LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace AARApplication
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* @RDE_HEADER@
|
||||
* <short description>
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Malte Schröder, SLSE, 2016-06-08
|
||||
*/
|
||||
|
||||
#include "aar_application.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <nglapplication/nglapplication.h>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions::None)
|
||||
{
|
||||
addOption({{QStringLiteral("l"), QStringLiteral("lang")},
|
||||
QStringLiteral("Language iso code to use (de_DE, en_GB, en_US)"),
|
||||
QStringLiteral("<locale iso code>")
|
||||
});
|
||||
}
|
||||
QString langIsoCode() const { return value(QStringLiteral("l")); }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = -1;
|
||||
bool bHeadless = false;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "-e") == 0)
|
||||
{
|
||||
bHeadless = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QScopedPointer<QCoreApplication> app;
|
||||
app.reset(bHeadless ? dynamic_cast<QCoreApplication*>(new NGLCoreApplication(argc, argv))
|
||||
: dynamic_cast<QCoreApplication*>(new NGLApplication(argc, argv)));
|
||||
QCoreApplication::setApplicationName(QLatin1String("AarApplication"));
|
||||
QCoreApplication::setOrganizationName(QLatin1String("RME"));
|
||||
|
||||
if (!bHeadless)
|
||||
app->setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
|
||||
NGL::LoggerHandler *lh = dynamic_cast<NGL::LoggerHandler*>(app.data());
|
||||
lh->createLogger("AarApp", "log4cxx_aarApp.props");
|
||||
NGL::INGLLogger &logger = lh->baseLogger();
|
||||
|
||||
// Parse Options
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return retval;
|
||||
|
||||
// Set Translation
|
||||
QString langIsoCode = options.langIsoCode();
|
||||
if (langIsoCode.isEmpty())
|
||||
langIsoCode = QLocale::system().name();
|
||||
NGL::setTranslationLocale(langIsoCode.toLatin1());
|
||||
|
||||
AARApplication::AarApplication * w = new AARApplication::AarApplication;
|
||||
if (!w->init())
|
||||
return -2;
|
||||
|
||||
STARTUP_LOG(logger);
|
||||
w->show();
|
||||
QGuiApplication::setQuitOnLastWindowClosed(true);
|
||||
retval = QCoreApplication::exec();
|
||||
|
||||
SHUTDOWN_LOG(logger);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(AarApp)
|
||||
ADD_SUBDIRECTORY(OpApp)
|
||||
ADD_SUBDIRECTORY(THP)
|
||||
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(LOG4CXX_PROPS_FILE log4cxx_opapp.props)
|
||||
|
||||
SET(mwt_SRCS
|
||||
main.cpp
|
||||
${LOG4CXX_PROPS_FILE}
|
||||
)
|
||||
|
||||
IF(WIN32)
|
||||
SET(JBN ${JENKINS_BUILD_NUMBER})
|
||||
IF (NOT JENKINS_BUILD_NUMBER)
|
||||
SET(JBN "0")
|
||||
ENDIF()
|
||||
SET(OPAPP_VERSION_INFO "${LTS_VERSION_MAJOR}, ${LTS_VERSION_MINOR}, ${JBN}, ${LTS_VERSION_PATCH}")
|
||||
CONFIGURE_FILE(opapp.rc.cmake ${CMAKE_CURRENT_BINARY_DIR}/opapp.rc)
|
||||
LIST(APPEND mwt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/opapp.rc)
|
||||
ENDIF()
|
||||
NGL_ADD_APP_ICON(mwt_SRCS)
|
||||
|
||||
IF(BUILD_RPM)
|
||||
NGL_ADD_EXECUTABLE(WS OperatorApplication WIN32 ${mwt_SRCS})
|
||||
ELSE()
|
||||
NGL_ADD_EXECUTABLE(WS OperatorApplication ${mwt_SRCS})
|
||||
ENDIF()
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(OperatorApplication
|
||||
ArcGISQt5Hack # make sure it's loaded *before* libEsriCommonQt.so
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
nglapplication
|
||||
LtsCommandLineParser
|
||||
NGLLogger
|
||||
LtsSession
|
||||
LtsPluginLoader
|
||||
LtsAppDescriptor
|
||||
LtsAppManager
|
||||
LtsSessionData
|
||||
LtsUtilsSettings
|
||||
ngltranslator
|
||||
nglsettings
|
||||
LtsProjectionWorkstation
|
||||
LtsMultiMonitor # TODO: rm if -m is out
|
||||
LtsUtilsGuiConnectDialog # to set timeout if -v is set
|
||||
LtsUtilsGuiStyleManager
|
||||
)
|
||||
NGL_INSTALL_TARGET(OperatorApplication)
|
||||
|
||||
NGL_INSTALL(FILES WS ${LOG4CXX_PROPS_FILE} DESTINATION "bin")
|
||||
@@ -0,0 +1,537 @@
|
||||
# Created by Mike Wille, SLSE, 2016-08-08
|
||||
log4j.reset=true
|
||||
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# LtsSession
|
||||
###########################################################
|
||||
#log4j.logger.LtsSession.TopicLockHandler=INFO
|
||||
#log4j.logger.LtsWidget.LtsDialog=INFO
|
||||
|
||||
|
||||
# SituationReplayManagement SRM
|
||||
###########################################################
|
||||
#log4j.logger.SRM=DEBUG
|
||||
|
||||
# Schnittstelle Adpter Adler SAA
|
||||
###########################################################
|
||||
#log4j.logger.SAA.SAAInterfaceGuiPlugin=DEBUG
|
||||
#log4j.logger.SAA.SaaDialogModel=DEBUG
|
||||
#log4j.logger.SAA.CustomViewSaa=DEBUG
|
||||
#log4j.logger.SAA.SaaChooser=DEBUG
|
||||
|
||||
# FileManagement FLM
|
||||
###########################################################
|
||||
#log4j.logger.AVM=DEBUG
|
||||
#log4j.logger.FLM.Plugins.Data=INFO
|
||||
#log4j.logger.FLM.Plugins.Gui.Explorer=INFO
|
||||
#log4j.logger.FLM.Plugins.Gui.FlmCombobox=INFO
|
||||
#log4j.logger.FLM.FileManagementDialog=DEBUG
|
||||
#log4j.logger.FLM.DialogModelFolder=INFO
|
||||
#log4j.logger.FLM.DialogEditFolder=INFO
|
||||
#log4j.logger.FLM.DialogModelFile=INFO
|
||||
#log4j.logger.FLM.FileContentEditDialog=DEBUG
|
||||
#log4j.logger.FLM.FileContentPreviewDialog=DEBUG
|
||||
#log4j.logger.FLM.SetAttributesDialog=INFO
|
||||
#log4j.logger.FLM.HQReportModel=DEBUG
|
||||
|
||||
|
||||
# FilterManagement FLT
|
||||
###########################################################
|
||||
#log4j.logger.FLT.AesDisplayFilterImpl=DEBUG
|
||||
#log4j.logger.FLT.BuildingComponentSettingsImpl=TRACE
|
||||
#log4j.logger.FLT.BuildingComponentFilterDialog=TRACE
|
||||
#log4j.logger.FLT.BuildingComponentSettingsWidget=TRACE
|
||||
#log4j.logger.FLT.SymbolAppearanceSettings=DEBUG
|
||||
#log4j.logger.FLT.SymbolAppearanceDialog=INFO
|
||||
#log4j.logger.FLT.SymbolAppearanceWidget=DEBUG
|
||||
|
||||
#log4j.logger.FLT.FilterChangeDialog=INFO
|
||||
|
||||
# CodificationManagement COD
|
||||
###########################################################
|
||||
#log4j.logger.COD.Plugins.Gui.CodificationDataImpl=DEBUG
|
||||
#log4j.logger.COD.CodificationDataOverviewDialog=DEBUG
|
||||
#log4j.logger.COD.CodificationDataOverviewModel=DEBUG
|
||||
#log4j.logger.COD.CodificationDataTableView=DEBUG
|
||||
#log4j.logger.COD.CodificationDataTableEditView=DEBUG
|
||||
#log4j.logger.COD.CodificationDataTableView=DEBUG
|
||||
#log4j.logger.COD.CodificationCSVExport=DEBUG
|
||||
#log4j.logger.COD.CodificationCSVImport=DEBUG
|
||||
#log4j.logger.COD.NumeralCodeTableModel=DEBUG
|
||||
#log4j.logger.COD.AuthenticationCodeTableModel=DEBUG
|
||||
#log4j.logger.COD.LogisticalTermsModel=DEBUG
|
||||
#log4j.logger.COD.PhraseTableModel= DEBUG
|
||||
#log4j.logger.COD.CodeTableEditDelegate=DEBUG
|
||||
#log4j.logger.COD.AssignCodificationDataTable=DEBUG
|
||||
|
||||
# AlarmManagement Info
|
||||
###########################################################
|
||||
#log4j.logger.ALM.Config=DEBUG
|
||||
#log4j.logger.ALM.Model=DEBUG
|
||||
#log4j.logger.ALM.Dialog=DEBUG
|
||||
|
||||
# InfrastructureManagement ISM
|
||||
###########################################################
|
||||
#log4j.logger.ISM.ApproachingPointsDialog=DEBUG
|
||||
#log4j.logger.ISM.ApproachingPointsDialogModel=DEBUG
|
||||
#log4j.logger.ISM.AssetFilterDialog=DEBUG
|
||||
#log4j.logger.ISM.AssetListDialog=DEBUG
|
||||
#log4j.logger.ISM.AssetListDialogModel=DEBUG
|
||||
#log4j.logger.ISM.AudioVideoConfigPlugin=DEBUG
|
||||
#log4j.logger.ISM.BuildingMountPointDialog=DEBUG
|
||||
#log4j.logger.ISM.BuildingMountPointModel=DEBUG
|
||||
#log4j.logger.ISM.CustomViewSchedule=DEBUG
|
||||
#log4j.logger.ISM.DdsSelector=DEBUG
|
||||
#log4j.logger.ISM.EditApproachingPointDialog=DEBUG
|
||||
#log4j.logger.ISM.EditAssetDialog=DEBUG
|
||||
#log4j.logger.ISM.ExerciseAssignmentDialog=DEBUG
|
||||
#log4j.logger.ISM.ExerciseAssignmentDialogModel=DEBUG
|
||||
#log4j.logger.ISM.ForeignDataInterface=DEBUG
|
||||
#log4j.logger.ISM.InfrastructureManagement=DEBUG
|
||||
#log4j.logger.ISM.MountingPointInfoDialog=DEBUG
|
||||
#log4j.logger.ISM.MountingPointListDialog=DEBUG
|
||||
#log4j.logger.ISM.MountingPointListDialogModel=DEBUG
|
||||
#log4j.logger.ISM.NewPlanDialog=DEBUG
|
||||
#log4j.logger.ISM.OverviewDialog=DEBUG
|
||||
#log4j.logger.ISM.OverviewDialogModel=DEBUG
|
||||
|
||||
#log4j.logger.ISM.OverviewMountingPointListDialog=DEBUG
|
||||
#log4j.logger.ISM.ViewMountingPointListModel=DEBUG
|
||||
|
||||
#log4j.logger.ISM.PlanChooser=DEBUG
|
||||
#log4j.logger.ISM.PlanDialog=DEBUG
|
||||
#log4j.logger.ISM.PlanDialogModel=DEBUG
|
||||
#log4j.logger.ISM.PlanEditDialog=DEBUG
|
||||
#log4j.logger.ISM.PlanTimeLineDialog=DEBUG
|
||||
#log4j.logger.ISM.PlanTimeLineModel=DEBUG
|
||||
#log4j.logger.ISM.Plugins.Gui.IsmCombobox=DEBUG
|
||||
#log4j.logger.ISM.ResourceManagement=DEBUG
|
||||
#log4j.logger.ISM.SetPropertiesDialog=DEBUG
|
||||
#log4j.logger.ISM.SetRecordingDialog=DEBUG
|
||||
|
||||
# AreaEffectSimulation Info
|
||||
###########################################################
|
||||
#log4j.logger.AES.AESInfo=DEBUG
|
||||
#log4j.logger.AES.AESInfoDialog=DEBUG
|
||||
|
||||
# generated using ctc_find_getlogger.sh
|
||||
#log4j.logger.AES.AesGuiBase=DEBUG
|
||||
#log4j.logger.AES.AESInfo=DEBUG
|
||||
#log4j.logger.AES.AESInfoDialog=DEBUG
|
||||
#log4j.logger.AES.AesItemList=DEBUG
|
||||
#log4j.logger.AES.ChargeAdministration=DEBUG
|
||||
#log4j.logger.AES.ChargeAdministrationList=DEBUG
|
||||
#log4j.logger.AES.DangerArea.AesItemInfo=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.Aes.Borderline=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.AirSupport=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.BcContamination=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.BorderlineImpl=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.ChargeAdministration=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.DangerArea=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.Explosion=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.FunctionalArea=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.GasPipe=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.MineArea=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.MineCorridor=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.MineSingleVirtual=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.NContamination=DEBUG
|
||||
#log4j.logger.AES.Plugins.Gui.TechnicalArea=DEBUG
|
||||
|
||||
#log4j.logger.AES.BCContaminationEdit=DEBUG
|
||||
#log4j.logger.AES.BoobyTrapEdit=DEBUG
|
||||
#log4j.logger.AES.BorderlineEdit=DEBUG
|
||||
#log4j.logger.AES.DangerAreaEdit=DEBUG
|
||||
#log4j.logger.AES.ExplosionEdit=DEBUG
|
||||
### setExplosionsEdit to ERROR (WARN "zValue is very small, set to 100")
|
||||
log4j.logger.AES.ExplosionsEdit=ERROR
|
||||
#log4j.logger.AES.FunctionalAreaEdit=DEBUG
|
||||
#log4j.logger.AES.GasPipeEdit=DEBUG
|
||||
#log4j.logger.AES.MineAreaEdit=DEBUG
|
||||
#log4j.logger.AES.MineCorridorEdit=DEBUG
|
||||
#log4j.logger.AES.NContaminationEdit=DEBUG
|
||||
#log4j.logger.AES.OffRouteMineEdit=DEBUG
|
||||
#log4j.logger.AES.TechnicalAreaEdit=DEBUG
|
||||
|
||||
# in context ExplosionCluster / Artillery suppress warnings of TrajectoryGenerator, TrajectoryGeneratorVulcano
|
||||
log4j.logger.AES.TrajectoryGenerator=ERROR
|
||||
log4j.logger.AES.TrajectoryGeneratorVulcano=ERROR
|
||||
|
||||
|
||||
|
||||
# AdvancedSymbolgy
|
||||
###########################################################
|
||||
#log4j.logger.AdvSymbology=INFO
|
||||
#log4j.logger.AdvSymbology.FlmSubscriber=DEBUG
|
||||
# FlmSubscriber.ReFetch should be on INFO to be able check the occurance of ReFetching
|
||||
#log4j.logger.AdvSymbology.FlmSubscriber.ReFetch=INFO
|
||||
#log4j.logger.AdvSymbology.FlmSymbolProxy=DEBUG
|
||||
#log4j.logger.AdvSymbology.EsriDictionaryProcessor=INFO
|
||||
#log4j.logger.AdvSymbology.SidcBuilder=INFO
|
||||
#log4j.logger.AdvSymbology.PropertyResult=INFO
|
||||
#log4j.logger.AdvSymbology.PropertyResultWatcher=INFO
|
||||
#log4j.logger.AdvSymbology.SymbolResult=INFO
|
||||
#log4j.logger.AdvSymbology.SymbolResultWatcher=INFO
|
||||
#log4j.logger.AdvSymbology.SymbolDictionary=INFO
|
||||
#log4j.logger.AdvSymbology.SymbolDictionaryImpl=INFO
|
||||
|
||||
# AdvancedSymbolgy - Plugin
|
||||
#log4j.logger.AdvSymbology.FlmSubscriber=INFO
|
||||
#log4j.logger.AdvSymbology.FlmSymbolProxy=INFO
|
||||
|
||||
|
||||
# Building-Viewer
|
||||
###########################################################
|
||||
#log4j.logger.BDV=DEBUG
|
||||
#Common
|
||||
#log4j.logger.BDV.BuildingManager=DEBUG
|
||||
#log4j.logger.BDV.BuildingViewerDdsController=DEBUG
|
||||
#log4j.logger.BDV.BgViewerControllerSingleton=DEBUG
|
||||
#log4j.logger.BDV.BuildingViewerDdsController=DEBUG
|
||||
#log4j.logger.BDV.CommunicationInterface=DEBUG
|
||||
#GUI
|
||||
#log4j.logger.BDV.BuildingViewer::BuildingEdit=DEBUG
|
||||
#log4j.logger.BDV.BgViewerDataView=DEBUG
|
||||
#log4j.logger.BDV.ThreadVideoExporter=DEBUG
|
||||
#log4j.logger.BDV.ReplayHandler=DEBUG
|
||||
#log4j.logger.BDV.BdvPluginProvider=DEBUG
|
||||
#log4j.logger.BDV.BgViewerDataViewDialog=DEBUG
|
||||
#log4j.logger.BDV.TopicReplayInterface=DEBUG
|
||||
#Plugin
|
||||
#log4j.logger.BDV.InterfaceImpl=DEBUG
|
||||
|
||||
|
||||
# Building
|
||||
###########################################################
|
||||
#log4j.logger.BLD.BldInfo=DEBUG
|
||||
#log4j.logger.BLD.BldInfoDialog=DEBUG
|
||||
#log4j.logger.BLD.BuildingConfigDialog=DEBUG
|
||||
|
||||
# TakeHomePackageManager
|
||||
###########################################################
|
||||
#log4j.logger.TPM.ExportedScriptsModel=DEBUG
|
||||
|
||||
# Script Editor
|
||||
###########################################################
|
||||
#log4j.logger.ScriptTimelineDialog.JournalDialog=DEBUG
|
||||
#log4j.logger.ScriptTimelineDialog.ScriptTimelineDialog=DEBUG
|
||||
#log4j.logger.ScriptTimelineDialog.ScriptModel=DEBUG
|
||||
#log4j.logger.ScriptTimelineDialog.Plugins.Gui.Pre.ScriptTimeline=DEBUG
|
||||
#log4j.logger.ScriptTimelineDialog.StoryboardDialog=DEBUG
|
||||
#log4j.logger.PRE.ScreenRecorder=DEBUG
|
||||
#log4j.logger.PRE.TopicRecorder=DEBUG
|
||||
|
||||
# SituationMap
|
||||
###########################################################
|
||||
#log4j.logger.SituationMap=INFO
|
||||
|
||||
### rethink SituationMap.Plugins.Gui.SitMap
|
||||
#log4j.logger.SituationMap.Plugins.Gui.SitMap=INFO
|
||||
#log4j.logger.SituationMap.SituationMapInit=INFO
|
||||
#log4j.logger.SituationMap.MapInitializer=INFO
|
||||
#log4j.logger.SituationMap.ThatPartyIdToColorFunctor=INFO
|
||||
#log4j.logger.SituationMap.RegisterAppHandler=INFO
|
||||
|
||||
# SituationMap-AdapterDds:
|
||||
#log4j.logger.SituationMap.AdapterDds=INFO
|
||||
#log4j.logger.SituationMap.EmergencyCallToMap=INFO
|
||||
#log4j.logger.SituationMap.MovementTrack=INFO
|
||||
#log4j.logger.SituationMap.MovementTrackManager=INFO
|
||||
#log4j.logger.SituationMap.Building2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.BuildingOwnership=INFO
|
||||
#log4j.logger.SituationMap.BCContamination2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.ExplosionSingle2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.ExplosionArea2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.ExplosionCluster2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.ExplosionCluster2SituationMap.update=INFO
|
||||
#log4j.logger.SituationMap.GuezIed2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.Participant2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.HitlineInfo2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.MineArea2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.MsePointToMap=INFO
|
||||
#log4j.logger.SituationMap.MseBridgeToMap=INFO
|
||||
#log4j.logger.SituationMap.MountingPointToMap=INFO
|
||||
#log4j.logger.SituationMap.SoundAreaToMap=INFO
|
||||
#log4j.logger.SituationMap.AerialOrdnance2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.BoobyTrap2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.OffRoute2SituationMap=INFO
|
||||
#log4j.logger.SituationMap.ChargeEffectToMap=INFO
|
||||
|
||||
# SituationMap-Core
|
||||
#log4j.logger.SituationMap=INFO
|
||||
#log4j.logger.SituationMap.MapImpl=INFO
|
||||
#log4j.logger.SituationMap.MapSettings=INFO
|
||||
#log4j.logger.SituationMap.MapInitializer=INFO
|
||||
#log4j.logger.SituationMap.JumpPoints=INFO
|
||||
#log4j.logger.SituationMap.JumpPointWidget=TRACE
|
||||
#log4j.logger.SituationMap.LayerFactoryImpl=INFO
|
||||
#log4j.logger.SituationMap.LayerControl=INFO
|
||||
#log4j.logger.SituationMap.LogicalLayer=INFO
|
||||
#log4j.logger.SituationMap.CoordTranslationFunctorImpl=INFO
|
||||
#log4j.logger.SituationMap.CoordTranslationThread=INFO
|
||||
#log4j.logger.SituationMap.PositionsTranslated=INFO
|
||||
#log4j.logger.SituationMap.GridImpl=INFO
|
||||
#log4j.logger.SituationMap.ObjectFactory=INFO
|
||||
#log4j.logger.SituationMap.IdGenerator=INFO
|
||||
#log4j.logger.SituationMap.ObjectContainer=INFO
|
||||
#log4j.logger.SituationMap.ObjectContainerCTC=INFO
|
||||
#log4j.logger.SituationMap.OverlayHandlerImpl=INFO
|
||||
#log4j.logger.SituationMap.OverviewMapHandlerImpl=INFO
|
||||
#log4j.logger.SituationMap.OverviewMap=INFO
|
||||
#log4j.logger.SituationMap.PixelBasedTextBoxHandlerImpl=INFO
|
||||
#log4j.logger.SituationMap.ViewshedImpl=INFO
|
||||
#log4j.logger.SituationMap.ViewshedBase=INFO
|
||||
|
||||
# SituationMap-AbstractMapObject's
|
||||
#log4j.logger.SituationMap.AbstractMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.AbstractEffectSimulationImpl=INFO
|
||||
#log4j.logger.SituationMap.OriginTranslated=INFO
|
||||
#log4j.logger.SituationMap.PositionsTranslated=INFO
|
||||
#log4j.logger.SituationMap.AbstractMultiPointMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.AbstractSinglePointMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.BasicPathObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.PathContainer=INFO
|
||||
#log4j.logger.SituationMap.IndicationContainer=INFO
|
||||
|
||||
#log4j.logger.SituationMap.PolygonImpl=INFO
|
||||
#log4j.logger.SituationMap.PolylineImpl=INFO
|
||||
#log4j.logger.SituationMap.TextImpl=INFO
|
||||
|
||||
#log4j.logger.SituationMap.AreaFireImpl=INFO
|
||||
#log4j.logger.SituationMap.BiologicalAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.BuildingOutlineImpl=INFO
|
||||
#log4j.logger.SituationMap.ChemicalAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.DangerAreaImpl=INFO
|
||||
#log4j.logger.SituationMap.FunctionalAreaImpl=INFO
|
||||
#log4j.logger.SituationMap.GeoImageImpl=INFO
|
||||
#log4j.logger.SituationMap.HitLineImpl=INFO
|
||||
#log4j.logger.SituationMap.ObjectIndicatorImpl=INFO
|
||||
#log4j.logger.SituationMap.MineImpl=INFO
|
||||
#log4j.logger.SituationMap.MineFieldImpl=INFO
|
||||
#log4j.logger.SituationMap.NineLinerImpl=TRACE
|
||||
#log4j.logger.SituationMap.NuclearAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.ParticipantImpl=INFO
|
||||
#log4j.logger.SituationMap.SingleFireImpl=INFO
|
||||
#log4j.logger.SituationMap.CubeImpl=INFO
|
||||
#log4j.logger.SituationMap.VirtualMineImpl=INFO
|
||||
|
||||
#log4j.logger.SituationMap.AbstractGraphicalObject=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectAttributes=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectEllipse=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectPath=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectMultiPath=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectPictureMarker=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectRange=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectRendererAttributes=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectSceneMarker=INFO
|
||||
#log4j.logger.SituationMap.GraphicalObjectText=INFO
|
||||
#log4j.logger.SituationMap.TacticalAppearance=INFO
|
||||
|
||||
|
||||
#log4j.logger.SituationMap.ElevationMapManager=DEBUG
|
||||
#log4j.logger.SituationMap.ElevationMap=DEBUG
|
||||
|
||||
|
||||
|
||||
# SituationMap-Widgets
|
||||
#log4j.logger.SituationMap.MapWidgetControl=INFO
|
||||
#log4j.logger.SituationMap.LayerControlDialog=INFO
|
||||
#log4j.logger.SituationMap.ConfigureMapUrls=INFO
|
||||
|
||||
# TargetManagement TGT
|
||||
###########################################################
|
||||
# SVC
|
||||
#log4j.logger.TGT.DdsHandler=INFO
|
||||
#log4j.logger.TGT.HandlerTargetConfig=INFO
|
||||
# SVC-L400
|
||||
#log4j.logger.TGT.HandlerShootbackArea=INFO
|
||||
#log4j.logger.TGT.HandlerShootbackTarget=INFO
|
||||
#log4j.logger.TGT.HandlerTargetAreaAssignment=INFO
|
||||
#log4j.logger.TGT.ObjectShootbackArea=INFO
|
||||
#log4j.logger.TGT.ObjectShootbackTarget=INFO
|
||||
#log4j.logger.TGT.ObjectTargetAreaAssignment=INFO
|
||||
#log4j.logger.TGT.ShootbackController=INFO
|
||||
# PLUGIN-L400
|
||||
#log4j.logger.Plugins.Gui.Tgt.Target=INFO
|
||||
#log4j.logger.TGT.ParticipantHandler=INFO
|
||||
#log4j.logger.TGT.AreaDialog=INFO
|
||||
#log4j.logger.TGT.AreaEdit=INFO
|
||||
#log4j.logger.TGT.AreaModel=INFO
|
||||
#log4j.logger.TGT.AssignmentParticipantModel=INFO
|
||||
#log4j.logger.TGT.AssignmentDialog=INFO
|
||||
#log4j.logger.TGT.AssignmentEditDialog=INFO
|
||||
#log4j.logger.TGT.ShootbackTargetEdit=INFO
|
||||
#log4j.logger.TGT.TargetPartDialog=INFO
|
||||
#log4j.logger.TGT.TargetParticipantModel=INFO
|
||||
|
||||
|
||||
# MeteoDataManagement MDM
|
||||
###########################################################
|
||||
#log4j.logger.MDM.MeteoDataManagementDialog=INFO
|
||||
#log4j.logger.MDM.MeteoDataManagementEdit=INFO
|
||||
#log4j.logger.MDM.MeteoDataModel=INFO
|
||||
#log4j.logger.MDM.InterfaceImpl.MeteoData=INFO
|
||||
|
||||
# Messaging MSG
|
||||
###########################################################
|
||||
#log4j.logger.MSG.MessagingDialog=INFO
|
||||
#log4j.logger.MSG.MessagingModel=INFO
|
||||
|
||||
# AudioVideoManagement AVM
|
||||
###########################################################
|
||||
# AVM AudioSettings
|
||||
#log4j.logger.AVM.AudioSettingsDialog=DEBUG
|
||||
#log4j.logger.AVM.AudioSettingsAvailStreamsModel=DEBUG
|
||||
#log4j.logger.AVM.AudioSettingsUsedStreamsModel=DEBUG
|
||||
|
||||
# AVM TopicEditor
|
||||
#log4j.logger.AVM.AvmSequenceModel=DEBUG
|
||||
|
||||
# AVM AVMenuEdit
|
||||
#log4j.logger.AVM.Plugins.Gui.Avm.MenuEdit=DEBUG
|
||||
#log4j.logger.AVM.AvailableStreamsModel=DEBUG
|
||||
#log4j.logger.AVM.UsedStreamsModel=DEBUG
|
||||
#log4j.logger.AVM.ChooseMenu=DEBUG
|
||||
#log4j.logger.AVM.AudioVideoManagementEdit=DEBUG
|
||||
#log4j.logger.AVM.AudioVideoManagementDialog=DEBUG
|
||||
#log4j.logger.AVM.MenuViewModel=DEBUG
|
||||
#log4j.logger.AVM.NewMenu=DEBUG
|
||||
|
||||
# AVM CNR
|
||||
#log4j.logger.AVM.Plugins.Gui.Avm.CombatNetRadio=DEBUG
|
||||
#log4j.logger.AVM.CombatNetRadioDialog=DEBUG
|
||||
#log4j.logger.AVM.CombatNetRadioDialogModel=DEBUG
|
||||
#log4j.logger.AVM.EditCombatNetRadioDialog=DEBUG
|
||||
|
||||
# AVM CNR FrequencyPlanning
|
||||
#log4j.logger.AVM.Plugins.Gui.Avm.CombatNetRadio=DEBUG
|
||||
#log4j.logger.AVM.FrequencyPlanningDialog=DEBUG
|
||||
#log4j.logger.AVM.FrequencyPlanningDialogModel=DEBUG
|
||||
#log4j.logger.AVM.InitFrequencyPlanningDialog=DEBUG
|
||||
#log4j.logger.AVM.EditFrequencyPlanningDialog=DEBUG
|
||||
#log4j.logger.AVM.EditFrequencyPlanningDataModel=DEBUG
|
||||
#log4j.logger.AVM.EditFrequencyPlanningResourceDialog=DEBUG
|
||||
#log4j.logger.AVM.EditFrequencyPlanningResourceDataModel=DEBUG
|
||||
|
||||
|
||||
# AVM Eloka
|
||||
#log4j.logger.AVM.Plugins.Gui.avm.Eloka=DEBUG
|
||||
#log4j.logger.AVM.ElokaDialog=DEBUG
|
||||
#log4j.logger.AVM.ElokaEditDialog=DEBUG
|
||||
#log4j.logger.AVM.ElokaModel=DEBUG
|
||||
|
||||
# AVM MobileVideoSystem
|
||||
#log4j.logger.AVM.Plugins.Gui.Avm.MobileVideoSystem=DEBUG
|
||||
#log4j.logger.AVM.MvsDialog=DEBUG
|
||||
#log4j.logger.AVM.EditVideoTeamDialog=DEBUG
|
||||
#log4j.logger.AVM.MvsModel=DEBUG
|
||||
#log4j.logger.AVM.MvsVideoTeamDialog=DEBUG
|
||||
|
||||
# AVM TVC
|
||||
#log4j.logger.AVM.Plugins.Gui.Avm.CombatNetRadio=DEBUG
|
||||
#log4j.logger.AVM.TrainingVoiceCommunicationDialog=DEBUG
|
||||
#log4j.logger.AVM.EditTrainingVoiceCommunicationDialog=DEBUG
|
||||
#log4j.logger.AVM.TrainingVoiceCommunicationDialogModel=DEBUG
|
||||
|
||||
|
||||
|
||||
# OPM
|
||||
###########################################################
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm=INFO
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm.Edit=INFO
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm.Overview=INFO
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm.OpmCombobox=INFO
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm.Settings=INFO
|
||||
#log4j.logger.OPM.Plugins.Gui.Opm.SettingsDialog=INFO
|
||||
#log4j.logger.OPM.LoginDialog=INFO
|
||||
#log4j.logger.OPM.SettingsGroup=DEBUG
|
||||
|
||||
|
||||
# PWS
|
||||
###########################################################
|
||||
#log4j.logger.PWS.LtsProjetionWorkstation=INFO
|
||||
#log4j.logger.PWS.ControlDialog=INFO
|
||||
|
||||
# Online Help
|
||||
#log4j.logger.OLH.onlineHelp=INFO
|
||||
|
||||
# ServiceMonitor
|
||||
###########################################################
|
||||
#log4j.logger.ServiceMonitorDialog=INFO
|
||||
#log4j.logger.ServiceMonitorBiteModel=INFO
|
||||
#log4j.logger.ServiceMonitorManipulationModel=INFO
|
||||
#log4j.logger.BasePlayerModel=DEBUG
|
||||
#log4j.logger.PartyEquipmentCheckDialog=DEBUG
|
||||
#log4j.logger.SingleServiceEquipmentCheckDialog=DEBUG
|
||||
|
||||
# Appnd_File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=100MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
#log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_OpApp.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=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
@@ -0,0 +1,523 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for OperatorApplication
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <LtsAppManager/lts_app_manager.h>
|
||||
#include <LtsPluginManager/lts_plugin_loader.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <LtsMultiMonitor/lts_multi_monitor.h>
|
||||
#include <StyleManager/style_manager.h>
|
||||
#include <LtsWidgets/lts_global_wait_dialog.h>
|
||||
#include <LtsWidgets/lts_splash.h>
|
||||
#include <LtsWidgets/lts_combo_box.h>
|
||||
#include <LtsProjectionWorkstation/lts_projection_workstation.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <nglapplication/nglapplication.h>
|
||||
#include <nglapplication/nglloggerhandler.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <rti/config/Logger.hpp>
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QScrollerProperties>
|
||||
#include <QInputDialog>
|
||||
#include <QNetworkProxy>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions(CreateDomainIdFromIp | DomainId | ExerciseId | TcpConnectionUrl))
|
||||
{
|
||||
addOption({{QStringLiteral("a"), QStringLiteral("application")},
|
||||
QStringLiteral("Specify the initial application to start (Default: Situation [Demo / Dev - otherwise NOT SPECIFIED => starts AppChooser]"), QStringLiteral("Application"),
|
||||
QStringLiteral("Situation")
|
||||
}); // TODO: remove default on release
|
||||
|
||||
addOption({{QStringLiteral("b"), QStringLiteral("basePlugin")},
|
||||
QStringLiteral("Base Project Plugin Iid to start the application with (Default: <not specified>)"), QStringLiteral("Base Project Plugin Iid"),
|
||||
QString()
|
||||
}); // TODO: remove default on release
|
||||
|
||||
addOption({{QStringLiteral("s"), QStringLiteral("stylePlugin")},
|
||||
QStringLiteral("Style Plugin to start the application with (Default: rme.light)"), QStringLiteral("Style Plugin Iid"),
|
||||
QStringLiteral("rme.light")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("u"), QStringLiteral("username")},
|
||||
QStringLiteral("Preset Username to skip login (also specify -p !)"),
|
||||
QStringLiteral("username")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("x"), QStringLiteral("tabletmode")},
|
||||
QStringLiteral("Enforce Tablet Mode"),
|
||||
QStringLiteral("false")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("w"), QStringLiteral("workstationmode")},
|
||||
QStringLiteral("Enforce Workstation Mode"),
|
||||
QStringLiteral("false")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("q"), QStringLiteral("qos_file")},
|
||||
QStringLiteral("Define QoS Profile "),
|
||||
QStringLiteral("qos_file")
|
||||
});
|
||||
|
||||
|
||||
addOption({{QStringLiteral("p"), QStringLiteral("password")},
|
||||
QStringLiteral("Preset Password to skip login (also specify -u !)"),
|
||||
QStringLiteral("password")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("k"), QStringLiteral("skipScreen")},
|
||||
QStringLiteral("Tell the Multi Monitor mode to not put anything on the screen with id n (example: 1 (skips entire screen 1)) - or on sub screen 0 or 1 (left or right) for ultra wide screens (example: 1.1 (skips the right side of screen 1)) (Default: (none))"),
|
||||
QStringLiteral("screen id"),
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("m"), QStringLiteral("multi-monitor-mode")},
|
||||
QStringLiteral("Use the Multi Monitor mode to place Base Layouts on Screens in Fullscreen")
|
||||
});
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
addOption({QStringLiteral("dbgmmm"),
|
||||
QStringLiteral("Start the multi-monitor-mode with reduced size for use on development maschines")
|
||||
});
|
||||
#endif
|
||||
|
||||
addOption({{QStringLiteral("r"), QStringLiteral("replayId")},
|
||||
QStringLiteral("Default: -1"),
|
||||
QStringLiteral("Replay ID"),
|
||||
QStringLiteral("-1")
|
||||
});
|
||||
|
||||
addOption({{QStringLiteral("l"), QStringLiteral("lang")},
|
||||
QStringLiteral("Language iso code to use (de_DE, en_GB, en_US)"),
|
||||
QStringLiteral("<locale iso code>")
|
||||
});
|
||||
|
||||
addOption({QStringLiteral("ignore-plugins"),
|
||||
QStringLiteral("Ignore these plugins, which otherwise would be loaded, "
|
||||
"specified by apps.json of the selected Base Plugin. "
|
||||
"Example: \"--ignore-plugins data:avm,data:bdv,gui:avm\""),
|
||||
QStringLiteral("ignore-plugins") // <= value
|
||||
});
|
||||
|
||||
addOption({QStringLiteral("projection"),
|
||||
QStringLiteral("Application is started on an Projection Workstation."),
|
||||
});
|
||||
|
||||
addOption({QStringLiteral("check-requirements"),
|
||||
QStringLiteral("Lets the Plugin Loader check if every App's requirements are met before starting"),
|
||||
});
|
||||
addOption({QStringLiteral("enable-experimental-web-platform-features"),
|
||||
QString(),
|
||||
});
|
||||
|
||||
addOption({QStringLiteral("script"),
|
||||
QStringLiteral("Id of a script. The script has to exist in the given exercise."),
|
||||
QStringLiteral("ScriptId"),
|
||||
QStringLiteral("0")
|
||||
});
|
||||
|
||||
addOption({QStringLiteral("place-script-screens"),
|
||||
QStringLiteral("Let the screen 1 and screen 2 of the script-editor be placed automatically on startup.")
|
||||
});
|
||||
|
||||
m_additionalHelpStr =
|
||||
QStringLiteral("\n\n\e[33m example OWS : %1 -m -a0 -d1 -b legatus -t EXCTDS01:7400 -l de_DE \n\n\e[0m").arg(QCoreApplication::arguments().at(0));
|
||||
|
||||
// fprintf(stdout, "\n\n\e[33m example OWS : %s -m -a0 -d1 -b legatus -t EXCTDS01:7400 -l de_DE \n\n\e[0m", QCoreApplication::arguments().at(0).toLatin1().data());
|
||||
|
||||
}
|
||||
|
||||
QString operatorName() const { return value(QStringLiteral("u")); }
|
||||
QString password() const { return value(QStringLiteral("p")); }
|
||||
int replayId() const { return value(QStringLiteral("r")).toInt(); }
|
||||
QString projectPluginIid() const { return value(QStringLiteral("b")); }
|
||||
QString stylePluginIid() const { return value(QStringLiteral("s")); }
|
||||
int applicationId() const { bool idk = false; int id = value(QStringLiteral("a")).toInt(&idk); if (!idk) { return -1; } return id; }
|
||||
bool multiMonitorMode() const { return isSet(QStringLiteral("m")); }
|
||||
bool isProjectionWorkstation() const { return isSet(QStringLiteral("projection")); }
|
||||
bool isForcedTabletMode() const { return isSet(QStringLiteral("x")); }
|
||||
bool isForcedWSMode() const { return isSet(QStringLiteral("w")); }
|
||||
QString langIsoCode() const { return value(QStringLiteral("l")); }
|
||||
QStringList ignoredPlugins() const { return value(QStringLiteral("ignore-plugins")).split(QLatin1Char(','), QString::SkipEmptyParts); }
|
||||
bool checkRequirements() const { return isSet(QStringLiteral("check-requirements")); }
|
||||
QString skipScreen() const { return value(QStringLiteral("k")); }
|
||||
QString qosFile() const { return value(QStringLiteral("q")).size() > 0 ? value(QStringLiteral("q")) : QString(); }
|
||||
int scriptId() const { return value(QStringLiteral("script")).toInt(); }
|
||||
bool placeScriptScreens() const { return isSet(QStringLiteral("place-script-screens")); }
|
||||
#ifdef LTS_DEBUG
|
||||
bool debugMultiMonitorMode() const { return isSet(QStringLiteral("dbgmmm")); }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv) // TODO: json strings to lower
|
||||
{
|
||||
qsrand(time(nullptr));
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
|
||||
QScrollerProperties props;
|
||||
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
|
||||
QScrollerProperties::setDefaultScrollerProperties(props);
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
//LtsApp app(argc, argv);
|
||||
NGLApplication app(argc, argv);
|
||||
app.createLogger("opApp");
|
||||
QApplication::setQuitOnLastWindowClosed(false); // we are cool enough to handle it ourselves 8)
|
||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy()); // do NOT use proxies anywhere!
|
||||
|
||||
NGL::LoggerHandler *lh = NGL::LoggerHandler::getLoggerHandler();
|
||||
if (lh)
|
||||
{
|
||||
const QByteArray postfix = lh->loggerNamePostfix().toLocal8Bit() + "_dds_";
|
||||
const QByteArray prefix = lh->loggerNamePrefix().toLocal8Bit();
|
||||
|
||||
rti::config::Logger &ddsLogger = rti::config::Logger::instance();
|
||||
//ddsLogger.output_file(fdopen(STDOUT_FILENO, "w"));
|
||||
ddsLogger.output_file_set(postfix.data(), prefix.data(), 10 * 1024 * 1024, 10);
|
||||
ddsLogger.verbosity(rti::config::Verbosity_def::WARNING);
|
||||
//ddsLogger.verbosity_by_category(rti::config::LogCategory_def::COMMUNICATION, rti::config::Verbosity_def::STATUS_ALL);
|
||||
}
|
||||
|
||||
|
||||
// TODO: replace all exit(x) with qApp.quit() and an error msg
|
||||
|
||||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(false); // avoid wait screen, we have the splash for this reason!
|
||||
|
||||
#ifdef __linux__
|
||||
// svcSituationRep - pgrep/pkill length limitation
|
||||
QProcess::startDetached(QLatin1String("pkill -9 svcSituationRep")); // kill it!
|
||||
QProcess::startDetached(QLatin1String("pkill -9 ffmpeg")); // otherwise a stray ffmpeg may record until the the disk is full
|
||||
#elif _WIN32
|
||||
QProcess::startDetached(QLatin1String("taskkill /im svcSituationReplay /f"));
|
||||
#endif
|
||||
|
||||
// Parse Options
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
// Set Translation
|
||||
|
||||
QString langIsoCode = options.langIsoCode();
|
||||
if (langIsoCode.isEmpty())
|
||||
langIsoCode = QLocale::system().name();
|
||||
NGL::setTranslationLocale(langIsoCode.toLatin1());
|
||||
|
||||
|
||||
// Set Style
|
||||
QString stylePluginName = options.stylePluginIid();
|
||||
if (stylePluginName.isEmpty())
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "No Style Plugin Iid specified - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// .. to keep some compatibility to old resource structure TODO: rm !
|
||||
QDir::setSearchPaths(QLatin1String("icon"), QStringList(QLatin1String(":/style/icons/")));
|
||||
QDir::setSearchPaths(QLatin1String("icon"), QStringList(QLatin1String(":/style/"))); // FIXME: does qt check for recursion ??
|
||||
|
||||
|
||||
LtsUtils::StyleManager::getInstance()->loadStyle(stylePluginName);
|
||||
|
||||
|
||||
// Load Plugins
|
||||
LtsPluginManager::LtsPluginLoader *pluginLoader = LtsPluginManager::LtsPluginLoader::getInstance();
|
||||
|
||||
QString projectPluginName = options.projectPluginIid();
|
||||
|
||||
if (projectPluginName.isEmpty())
|
||||
{
|
||||
bool k;
|
||||
projectPluginName = QInputDialog::getText(nullptr,
|
||||
QCoreApplication::tr("No Project Plugin specified"),
|
||||
QCoreApplication::tr("Please specify a Project Plugin:"), QLineEdit::Normal,
|
||||
QString(), &k); // blocking, no event loop needed
|
||||
|
||||
if (!k || projectPluginName.isEmpty())
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "No Project Plugin Iid specified - abort.";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// load project plugin
|
||||
if (!pluginLoader->loadPlugins(LtsPluginManager::PluginType::PROJECT, nullptr, {projectPluginName}))
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Error loading Project Plugin - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
LtsUtils::ProjectSettings::initFromFile(QStringLiteral(":project/project_settings.json"));
|
||||
|
||||
// Setup Application
|
||||
if (options.multiMonitorMode())
|
||||
LtsMultiMonitor::LtsMultiMonitor::getInstance()->setEnableMultiMonitorMode();
|
||||
#ifdef LTS_DEBUG
|
||||
if (options.debugMultiMonitorMode())
|
||||
LtsMultiMonitor::LtsMultiMonitor::getInstance()->setDebugMultiMonitorMode();
|
||||
#endif
|
||||
|
||||
|
||||
// show splash
|
||||
LtsWidgets::Splash::getInstance()->show();
|
||||
|
||||
LtsAppDescriptor::App applicationId = LtsAppDescriptor::LtsAppDescriptor::appFromInteger(options.applicationId());
|
||||
int exerciseId = options.exerciseId(); // -1 = invalid, 0 = admin, >0 = exercise
|
||||
int replayId = options.replayId(); // -1 = invalid, TODO: comment doku
|
||||
int scriptId = options.scriptId(); // <0 = invalid, 0 = default = ignore, >0 script
|
||||
QString operatorName = options.operatorName();
|
||||
QString password = options.password();
|
||||
QStringList qos_file = QStringList(options.qosFile());
|
||||
|
||||
// TODO: log4cxx/NGLLlogger does not flush here !! messages not seen !
|
||||
|
||||
if (scriptId < 0)
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Given scriptId " << scriptId << " is invalid - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scriptId > 0 && applicationId != LtsAppDescriptor::App::Scripts)
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "ScriptId set but given app is not Scripts - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scriptId > 0 && exerciseId < 1)
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "ScriptId set but no exercise is given - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scriptId > 0 && exerciseId > 0 && applicationId == LtsAppDescriptor::App::Scripts)
|
||||
{
|
||||
LtsSessionData::LtsSessionData::getInstance()->setScriptId(scriptId);
|
||||
}
|
||||
|
||||
if (options.placeScriptScreens() && applicationId != LtsAppDescriptor::App::Scripts)
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "PlaceScriptScreensn is set but given app is not Scripts - abort.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
LtsSessionData::LtsSessionData::getInstance()->setPlaceScriptScreens(options.placeScriptScreens());
|
||||
|
||||
if (operatorName.isEmpty() != password.isEmpty()) // check for xor and warn user
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Specify -u if -p is specified & vise versa - abort.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (options.domainId() < 0)
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Invalid configuration for domainId (" << options.domainId() << ") from LtsConfig - abort.";
|
||||
QMessageBox::critical(nullptr, QCoreApplication::tr("Invalid Domain Id"), QCoreApplication::tr("Domain #%1 is not valid - abort.").arg(options.domainId()));
|
||||
return -1;
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
LtsSessionData::LtsSessionData *sessionData = LtsSessionData::LtsSessionData::getInstance();
|
||||
|
||||
sessionData->setDomainIdPreset(options.domainId());
|
||||
sessionData->setRequestedAppId(applicationId);
|
||||
|
||||
if (options.useTcpConnection())
|
||||
sessionData->setTcpConnectionUrl(options.tcpConnectionUrl());
|
||||
|
||||
if (options.checkRequirements())
|
||||
sessionData->setDebugFlagValue(QStringLiteral("PluginManager.CheckAppRequirements"), true);
|
||||
|
||||
// load JSON app description file
|
||||
QFile appsFile(QStringLiteral(":project/apps.json")); // TODO: convert Json => Binary Json
|
||||
|
||||
if (!appsFile.open(QFile::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Could not read App Description File";
|
||||
return -1;
|
||||
}
|
||||
|
||||
QStringList lastErrors;
|
||||
QString loginPluginIid;
|
||||
|
||||
LtsAppDescriptor::AppDescriptionVector appDescs = LtsAppDescriptor::LtsAppDescriptor::getAppDescriptionVector(appsFile.readAll(),
|
||||
lastErrors,
|
||||
options.ignoredPlugins(),
|
||||
loginPluginIid);
|
||||
|
||||
if (loginPluginIid.isEmpty())
|
||||
loginPluginIid = QStringLiteral("opm.login");
|
||||
|
||||
QString skipScreen = options.skipScreen();
|
||||
|
||||
int skipScreenId = -1;
|
||||
int skipSubScreenId = -1;
|
||||
|
||||
if (!skipScreen.isEmpty())
|
||||
{
|
||||
QStringList skipScreenList(skipScreen.split(QLatin1Char('.'), QString::SkipEmptyParts));
|
||||
|
||||
int skipScreenListCount = skipScreenList.count();
|
||||
|
||||
if (skipScreenListCount > 2)
|
||||
{
|
||||
qWarning() << "invalid skip screen syntax:" << skipScreen;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (skipScreenListCount > 0)
|
||||
{
|
||||
bool k = false;
|
||||
skipScreenId = skipScreenList.at(0).toInt(&k);
|
||||
|
||||
if (!k)
|
||||
{
|
||||
qWarning() << "invalid skip screen syntax:" << skipScreen;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (skipScreenListCount > 1)
|
||||
{
|
||||
bool k = false;
|
||||
skipSubScreenId = skipScreenList.at(1).toInt(&k);
|
||||
|
||||
if (!k)
|
||||
{
|
||||
qWarning() << "invalid skip screen syntax:" << skipScreen;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LtsMultiMonitor::LtsMultiMonitor::getInstance()->setSkipScreen(skipScreenId, skipSubScreenId);
|
||||
|
||||
appsFile.close();
|
||||
|
||||
if (!lastErrors.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(nullptr, QString(), lastErrors.join(QStringLiteral("\r\n\r\n")));
|
||||
// TODO: log precise msg !!
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if(options.isForcedTabletMode())
|
||||
sessionData->setAsTablet();
|
||||
else if (options.isForcedWSMode())
|
||||
sessionData->setAsTablet(false);
|
||||
else if (!QTouchDevice::devices().isEmpty())
|
||||
sessionData->setAsTablet();
|
||||
LtsWidgets::LtsComboBox::setUseSelectionDialog(sessionData->isTablet());
|
||||
|
||||
LtsAppManager::LtsAppManager *appManager = LtsAppManager::LtsAppManager::getInstance();
|
||||
appManager->setAvailableApps(appDescs);
|
||||
|
||||
|
||||
// Projection Specific Setup
|
||||
if (options.isProjectionWorkstation())
|
||||
{
|
||||
if (operatorName.isEmpty() && password.isEmpty())
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Projection-User & Password has to be specified when --projection option is active!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
applicationId = LtsAppDescriptor::App::Situation;
|
||||
|
||||
LtsProjectionWorkstation::LtsProjectionWorkstation::getInstance()->setProjectionOperatorPreset(operatorName, password);
|
||||
}
|
||||
// Normal Setup
|
||||
else
|
||||
{
|
||||
if (applicationId == LtsAppDescriptor::App::Login)
|
||||
INFO_LOG(app.baseLogger()) << "No Application specified - starting with App Chooser.";
|
||||
|
||||
// TODO: replayid can not life without exerciseId
|
||||
if (exerciseId >= 0 && replayId >= 0) // do not set both!
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Use either -e (exercise) or -r (replay) - abort.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!operatorName.isEmpty() && !password.isEmpty())
|
||||
{
|
||||
sessionData->setOperatorPreset(operatorName, password); // if -u and -p (no Login window !)
|
||||
}
|
||||
|
||||
if (exerciseId == 0) // Admin Session was requested explicitly
|
||||
{
|
||||
//sessionManager->setGlobalSessionVisible();
|
||||
sessionData->setPartitionPreset(exerciseId, IDL::PartitionType::Global);
|
||||
}
|
||||
|
||||
if (!qos_file.isEmpty()) // use defined qos file
|
||||
{
|
||||
//sessionManager->setGlobalSessionVisible();
|
||||
DEBUG_LOG(app.baseLogger()) << "QOS -> using new file" << qos_file.join(QStringLiteral(","));
|
||||
sessionData->setQosFile(qos_file);
|
||||
}
|
||||
|
||||
if (exerciseId > 0) // non Admin => Exercise
|
||||
sessionData->setPartitionPreset(exerciseId, IDL::PartitionType::Exercise);
|
||||
|
||||
if (replayId >= 0) // Replay
|
||||
sessionData->setPartitionPreset(replayId, IDL::PartitionType::Replay);
|
||||
}
|
||||
|
||||
appManager->setLoginPluginIid(loginPluginIid);
|
||||
appManager->setMainApp(applicationId);
|
||||
if (applicationId == LtsAppDescriptor::App::ThpSituationReplay)
|
||||
{
|
||||
LtsSessionData::LtsSessionData::getInstance()->setVisibleParties({});
|
||||
LtsSessionData::LtsSessionData::getInstance()->setOperatorRights({-1});
|
||||
QTimer::singleShot(0, appManager, [qos_file, appManager]()
|
||||
{
|
||||
LtsSession::DdsConnectionParams params;
|
||||
params.domainId = 1;
|
||||
params.exerciseId = 2;
|
||||
params.partitionId = 2;
|
||||
if (!qos_file.isEmpty())
|
||||
params.qos_file = qos_file;
|
||||
|
||||
params.partitionType = IDL::PartitionType::Replay;
|
||||
appManager->createApp(LtsAppDescriptor::App::Situation, params, {}, false, true);
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
appManager->showLogin();
|
||||
}
|
||||
|
||||
// Startup Application
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
int iRet = app.exec();
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
|
||||
return iRet;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <WINVER.H>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @OPAPP_VERSION_INFO@
|
||||
PRODUCTVERSION @OPAPP_VERSION_INFO@
|
||||
FILEFLAGSMASK 0x0L
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040704b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Rheinmetall Electronics GmbH"
|
||||
VALUE "FileDescription", "Operator Application (64bit)"
|
||||
VALUE "FileVersion", "@OPAPP_VERSION_INFO@"
|
||||
VALUE "InternalName", "OpApp"
|
||||
VALUE "LegalCopyright", "Copyright © 2018 Rheinmetall Electronics GmbH. Alle Rechte vorbehalten"
|
||||
VALUE "OriginalFilename", "OperatorApplication.exe"
|
||||
VALUE "ProductName", "Operator Application"
|
||||
VALUE "ProductVersion", "@OPAPP_VERSION_INFO@"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x407, 1200
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,127 @@
|
||||
#
|
||||
# THP-Viewer
|
||||
#
|
||||
ADD_SUBDIRECTORY(THP-Starter)
|
||||
FIND_PACKAGE(VLC REQUIRED)
|
||||
|
||||
SET(thp_viewer_SRCS
|
||||
main.cpp
|
||||
thp_plugin_provider.cpp
|
||||
thp_plugin_provider.h
|
||||
thp_situation_filter_interface_impl.cpp
|
||||
thp_situation_filter_interface_impl.h
|
||||
thp_viewer.cpp
|
||||
thp_viewer.h
|
||||
|
||||
thpwidgets/thp_audio_video_widget.cpp
|
||||
thpwidgets/thp_audio_video_widget.h
|
||||
thpwidgets/thp_audio_video_widget_p.h
|
||||
thpwidgets/thp_building_settings.cpp
|
||||
thpwidgets/thp_building_settings.h
|
||||
thpwidgets/thp_building_widget.cpp
|
||||
thpwidgets/thp_building_widget.h
|
||||
thpwidgets/thp_html_widget.cpp
|
||||
thpwidgets/thp_html_widget.h
|
||||
thpwidgets/thp_pdf_widget.cpp
|
||||
thpwidgets/thp_pdf_widget.h
|
||||
thpwidgets/thp_situation_building_base.h
|
||||
thpwidgets/thp_situation_building_base.cpp
|
||||
thpwidgets/thp_situation_filter_aes.cpp
|
||||
thpwidgets/thp_situation_filter_aes.h
|
||||
thpwidgets/thp_situation_filter_building_components.cpp
|
||||
thpwidgets/thp_situation_filter_building_components.h
|
||||
thpwidgets/thp_situation_filter_collapse_expand.cpp
|
||||
thpwidgets/thp_situation_filter_collapse_expand.h
|
||||
thpwidgets/thp_situation_filter_symbol_appearance.cpp
|
||||
thpwidgets/thp_situation_filter_symbol_appearance.h
|
||||
thpwidgets/thp_situation_filter_types.cpp
|
||||
thpwidgets/thp_situation_filter_types.h
|
||||
thpwidgets/thp_situation_widget.cpp
|
||||
thpwidgets/thp_situation_widget.h
|
||||
thpwidgets/thp_zoom_slider.cpp
|
||||
thpwidgets/thp_zoom_slider.h
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(thp_viewer_SRCS
|
||||
thp_viewer.ui
|
||||
thpwidgets/thp_audio_video_widget.ui
|
||||
thpwidgets/thp_building_settings.ui
|
||||
thpwidgets/thp_html_widget.ui
|
||||
thpwidgets/thp_pdf_widget.ui
|
||||
thpwidgets/thp_situation_building_base.ui
|
||||
)
|
||||
IF(WIN32)
|
||||
SET(JBN ${JENKINS_BUILD_NUMBER})
|
||||
IF (NOT JENKINS_BUILD_NUMBER)
|
||||
SET(JBN "0")
|
||||
ENDIF()
|
||||
SET(THP_VERSION_INFO "${LTS_VERSION_MAJOR}, ${LTS_VERSION_MINOR}, ${JBN}, ${LTS_VERSION_PATCH}")
|
||||
CONFIGURE_FILE(thp_viewer.rc.cmake ${CMAKE_CURRENT_BINARY_DIR}/thp_viewer.rc)
|
||||
LIST(APPEND thp_viewer_SRCS ${CMAKE_CURRENT_BINARY_DIR}/thp_viewer.rc)
|
||||
ENDIF(WIN32)
|
||||
NGL_ADD_APP_ICON(thp_viewer_SRCS)
|
||||
|
||||
NGL_ADD_EXECUTABLE(WS thp_viewer WIN32 ${thp_viewer_SRCS})
|
||||
NGL_INSTALL_TARGET(thp_viewer)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(thp_viewer
|
||||
PRIVATE
|
||||
${VLC_INCLUDE_DIR}
|
||||
)
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(thp_viewer
|
||||
PRIVATE
|
||||
${VLC_DEFINES}
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(thp_viewer
|
||||
ArcGISQt5Hack # make sure it's loaded *before* libEsriCommonQt.so
|
||||
|
||||
${VLC_LIBRARIES}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::PrintSupport
|
||||
Qt5::Svg
|
||||
Qt5::WebEngineCore
|
||||
Qt5::WebEngineWidgets
|
||||
Qt5::Widgets
|
||||
Qt5::Xml
|
||||
|
||||
RmeLightStyleQrc
|
||||
|
||||
AsbData
|
||||
AsbForeignDataPluginThp
|
||||
BuildingViewerCommon
|
||||
FltAesGuiCommon
|
||||
FltAesWidget
|
||||
FltBldgCmpntWidget
|
||||
FltParticipantWidget
|
||||
IsmDataPluginThp
|
||||
LtsCoordTrans
|
||||
LtsCommandLineParser
|
||||
NGLLogger
|
||||
nglsingleapplication
|
||||
ngltools
|
||||
ngltranslator
|
||||
nglwidgets
|
||||
PdmComboBoxGui
|
||||
PpmComboBoxGui
|
||||
SitmapDds
|
||||
SituationReplaySqlite
|
||||
|
||||
svcFlmCommon
|
||||
|
||||
svcAesClient
|
||||
svcBldClient
|
||||
svcCesClient
|
||||
svcGimClient
|
||||
svcIsmClient
|
||||
svcPpmClient
|
||||
svcPdmClient
|
||||
svcAlmClient
|
||||
)
|
||||
IF(WIN32)
|
||||
# NGL_INSTALL(WS FILES autorun.inf DESTINATION bin)
|
||||
# NGL_INSTALL(WS FILES readme.win32.en_US.txt DESTINATION bin)
|
||||
# NGL_INSTALL(WS FILES readme.win32.de_DE.txt DESTINATION bin)
|
||||
ENDIF()
|
||||
NGL_INSTALL(WS FILES log4cxx_thp_viewer.props DESTINATION bin)
|
||||
|
||||
ADD_SUBDIRECTORY(SitMapReplayTest)
|
||||
@@ -0,0 +1,101 @@
|
||||
#
|
||||
# Hinweise für das THP
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
N. Thoden, 12.03.2020
|
||||
|
||||
Das TakeHomePackage (für Windows) besteht aus 3 Komponenten:
|
||||
============================================================
|
||||
|
||||
1) den THP-Viewer / THP-Starter
|
||||
(inkl. Qt ; ohne MSVCRuntime, z.B. msvcr120.dll, in C:\Windows\system32 !?)
|
||||
http://jenkins-master.sl.defence-elec.de:8080/job/ahtc_OC-Tablet/
|
||||
thp.tgz
|
||||
2) die Kartendaten
|
||||
(evtl. für den Datenträger reduziert in Bezug auf die Speichergröße)
|
||||
3) die Topic-Daten (Video, Audio, DB-Abzug...)
|
||||
|
||||
|
||||
Woher kommt was?
|
||||
================
|
||||
1) Der THP-Viewer / THP-Starter
|
||||
Kann aus der CI-Umgebung (Jenkins) heruntergeladen werden (thp.tgz)
|
||||
Am besten mit 7Zip entpackt werden:
|
||||
(tgz -> gepackt und anschliessend komprimiert)
|
||||
- Per Kontext-Menue "entpacken nach hier"
|
||||
- die resultierende Datei "thp' "entpacken nach thp~".
|
||||
Dann sollte ein Verzeichnis "thp" MIT diversen Unterverzeichnissen entstehen.
|
||||
|
||||
Das THP-Verzeichnis wird auf jeder Workstation im Ordner /opt/THP als Quelle für den USB-Datentraeger bereitgestellt.
|
||||
|
||||
2) Diese werden manuell für das THP bereitgestellt (meist als tpk-Datei).
|
||||
|
||||
3) Die Topic-Daten werden in der OpApp mit "Präsentation exportieren" erzeugt.
|
||||
Sie werden unter /tmp/THP-Export generiert.
|
||||
|
||||
|
||||
Woher kommt das Verzeichnis 'Maps'?
|
||||
===================================
|
||||
Der Verzeichnisname 'Maps' ist fest und darf nicht verändert werden.
|
||||
Es müssen die für das Medium (CD, DVD, Stick..) passenden Basiskarten/Kartendaten hinein.
|
||||
Das sind also z.B.
|
||||
- 2020-03-03_UaeAerial_32639_Lvl6.tpk
|
||||
- 2020-03-03_UaeAerial_WebMerc_Lvl15.tpk
|
||||
- 2020-03-03_UaeTopo_32639_Lvl6.tpk
|
||||
- 2020-03-03_UaeTopo_WebMerc_Lvl15.tpk
|
||||
- AHTC_utm_dgm_surface_wgs84.tif
|
||||
|
||||
Das layerMapping.json hat nun die Aufgabe, diese (für das Übungsgebiet) spezifischen
|
||||
Dateinamen zu abstrahieren.
|
||||
Die bei der Ausführung des THPs geforderten Basiskarten (Annahme: eine Topo und zwei Aerial)
|
||||
können mit Hilfe der layerMapping.json auf eine geringere Anzahl Dateien gemappt werden.
|
||||
|
||||
Basiskarten: Mapping per layerMapping.json
|
||||
in der WS-App: Dateien in Dir 'Maps'
|
||||
-------------- ---------------------
|
||||
- Aerial2 -> 2020-03-03_UaeAerial_32639_Lvl6.tpk
|
||||
- Aerial1 -> 2020-03-03_UaeAerial_32639_Lvl6.tpk
|
||||
- Topo -> 2020-03-03_UaeTopo_32639_Lvl6.tpk
|
||||
|
||||
Best Practise:
|
||||
Daher ergibt es Sinn, eine layerMapping.json in dem Verzeichnis 'Maps' vorzubereiten
|
||||
und beim Zusammengefügen in die darüberliegende Dateiebene zu kopieren.
|
||||
|
||||
|
||||
Wie müssen die 3 Komponenten zusammengefügt werden?
|
||||
===================================================
|
||||
|
||||
Device:
|
||||
- Excersise_6
|
||||
- 1 <- Übungsdaten (Komponenten 3)
|
||||
- ...
|
||||
- index.html <- Übungsdaten (Komponenten 3)
|
||||
- ... <- Übungsdaten (Komponenten 3)
|
||||
|
||||
- Maps <- Kartendaten (Komponenten 2)
|
||||
- *.tpk
|
||||
- [layerMapping.json] <- Sonderfall AHTC 03/2020: Diese Datei in
|
||||
die darüberliegende Ebenen verschieben.
|
||||
- layerMapping.json <- Übungsdaten (Komponenten 2/3)
|
||||
(generiert, Sonderfall AHTC 03/2020:
|
||||
aus 'Maps' hierher transferieren)
|
||||
|
||||
- thp <- thp (Komponenten 1)
|
||||
- resources <- thp (Komponenten 1), hat mal gefehlt)
|
||||
- thv_viewer.exe <- thp (Komponenten 1)
|
||||
- vc.redist.x64.exe <- thp (Komponenten 1), für MSVCRuntime
|
||||
- thp_starter.exe <- thp (Komponenten 1)
|
||||
- autorun.inf <- thp (Komponenten 1)
|
||||
- [wappen.png] <- thp (Komponenten 1 oder 3) optional !?
|
||||
|
||||
|
||||
Logfiles zuir Fehlersuche
|
||||
=========================
|
||||
Ein Logfile befindet sich unter ~Benutzer\AppData\Local\Temp\.
|
||||
Bsp: C:\User\thoden\AppData\Local\Temp\thoden_thp.log
|
||||
C:\User\thoden\AppData\Local\Temp\thoden_thp.log.1
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# SitMapReplayTest
|
||||
#
|
||||
SET(SRPTEST_SRCS
|
||||
srp_main.cpp
|
||||
srp_main_window.cpp
|
||||
srp_main_window.h
|
||||
../thp_plugin_provider.cpp
|
||||
../thp_plugin_provider.h
|
||||
../thp_situation_filter_interface_impl.cpp
|
||||
../thp_situation_filter_interface_impl.h
|
||||
)
|
||||
NGL_WRAP_UI(SRPTEST_SRCS
|
||||
srp_main_window.ui
|
||||
)
|
||||
NGL_ADD_EXECUTABLE(WS SitMapReplayTest ${SRPTEST_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(SitMapReplayTest
|
||||
SituationReplaySqlite
|
||||
|
||||
ddsconnector
|
||||
Qt5::Core
|
||||
nglapplication
|
||||
SitmapDds
|
||||
|
||||
AsbForeignDataPluginThp
|
||||
BuildingViewerCommon
|
||||
FltAesGuiCommon
|
||||
IsmDataPluginThp
|
||||
|
||||
svcFlmCommon
|
||||
|
||||
svcAesClient
|
||||
svcBldClient
|
||||
svcCesClient
|
||||
svcGimClient
|
||||
svcIsmClient
|
||||
svcPpmClient
|
||||
svcPdmClient
|
||||
)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Main for SitMapReplayTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include <nglapplication/nglapplication.h>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <DDS/QosProfile/DDS_DefaultQos.h>
|
||||
#include <QNetworkProxy>
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
#include <SituationMap/situation_map_init.h>
|
||||
#include <SituationMap/Utils/movement_track_manager.h>
|
||||
#include "../thp_plugin_provider.h"
|
||||
#include "srp_main_window.h"
|
||||
#include "ui_srp_main_window.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
NGLApplication app(argc, argv);
|
||||
app.createLogger("SRP");
|
||||
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
SituationReplay::ConnectionParams connParams;
|
||||
connParams.domainId = 1;
|
||||
connParams.partitionId = 1;
|
||||
std::shared_ptr<SituationReplay::MainHandlerSqlite> srpMainHandler(new SituationReplay::MainHandlerSqlite);
|
||||
if (!srpMainHandler->initDds(connParams))
|
||||
return 1;
|
||||
// TODO: fixme or trash me
|
||||
SituationReplay::ReplayInformation ri;
|
||||
ri.databaseFilePath = QStringLiteral("dump.sqlite");
|
||||
ri.replayConfigPath = QStringLiteral("dump.json");
|
||||
if (!srpMainHandler->initDb(ri, {}, {}))
|
||||
return 2;
|
||||
|
||||
std::shared_ptr<DDSConnector::DdsConnector> ddsConn = srpMainHandler->ddsReplay();
|
||||
THP::SitMapPluginProvider *pp = new THP::SitMapPluginProvider;
|
||||
pp->init(ddsConn);
|
||||
|
||||
SituationMap::SituationMapInit *smi = new SituationMap::SituationMapInit(nullptr);
|
||||
smi->initPluginProvider(pp);
|
||||
|
||||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(smi));
|
||||
|
||||
smi->initAdapter(movementTrackMgr, false);
|
||||
smi->initMap(true, SituationMap::Mode::Mode_2D);
|
||||
|
||||
SituationReplay::MainWindow *mw = new SituationReplay::MainWindow(smi, srpMainHandler->handlerSrp());
|
||||
mw->show();
|
||||
|
||||
int ret = app.exec();
|
||||
|
||||
delete mw;
|
||||
delete smi;
|
||||
delete pp;
|
||||
ddsConn.reset();
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* MainWindow for SitMapReplayTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include "srp_main_window.h"
|
||||
#include "ui_srp_main_window.h"
|
||||
#include <SituationMap/situation_map_init.h>
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
|
||||
namespace SituationReplay
|
||||
{
|
||||
MainWindow::MainWindow(SituationMap::SituationMapInit *sitMap,
|
||||
const std::shared_ptr<HandlerSituationReplaySqlite> &srpHandler,
|
||||
QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_srpHandler(srpHandler)
|
||||
, m_ui(new Ui::SrpMainWindow)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setCentralWidget(sitMap->getWidget());
|
||||
connect(m_ui->actionStart_Replay, &QAction::triggered, this, &MainWindow::onStartReplay);
|
||||
connect(m_ui->actionStop_Replay, &QAction::triggered, this, &MainWindow::onStopReplay);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void MainWindow::onStartReplay()
|
||||
{
|
||||
const qint64 begin = (time(nullptr) - 60 * 60 * 30) * 1000;
|
||||
const qint64 end = 0;
|
||||
const double pace = 1;
|
||||
m_srpHandler->onStartReplayRequest(begin, end, pace);
|
||||
}
|
||||
|
||||
void MainWindow::onStopReplay()
|
||||
{
|
||||
m_srpHandler->onStopReplayRequest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* MainWindow for SitMapReplayTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <memory>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SrpMainWindow;
|
||||
}
|
||||
namespace SituationMap
|
||||
{
|
||||
class SituationMapInit;
|
||||
}
|
||||
namespace SituationReplay
|
||||
{
|
||||
class HandlerSituationReplaySqlite;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(SituationMap::SituationMapInit *sitMap,
|
||||
const std::shared_ptr<HandlerSituationReplaySqlite> &srpHandler,
|
||||
QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
protected slots:
|
||||
void onStartReplay();
|
||||
void onStopReplay();
|
||||
private:
|
||||
std::shared_ptr<HandlerSituationReplaySqlite> m_srpHandler;
|
||||
Ui::SrpMainWindow *m_ui;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SrpMainWindow</class>
|
||||
<widget class="QMainWindow" name="SrpMainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>29</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>Fi&le</string>
|
||||
</property>
|
||||
<addaction name="actionStart_Replay"/>
|
||||
<addaction name="actionStop_Replay"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionStart_Replay">
|
||||
<property name="text">
|
||||
<string>Start Replay</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStop_Replay">
|
||||
<property name="text">
|
||||
<string>Stop Replay</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
IF(WIN32)
|
||||
# static msvc runtime
|
||||
FOREACH(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
IF(${flag_var} MATCHES "/MD")
|
||||
STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
SET(THP_ICO "${CMAKE_SOURCE_DIR}/Lts/Common/LtsWidgets/resources/rde_icon_256.ico")
|
||||
CONFIGURE_FILE(thp_starter.rc.cmake ${CMAKE_CURRENT_BINARY_DIR}/thp_starter.rc)
|
||||
|
||||
NGL_ADD_EXECUTABLE(WS thp_starter WIN32 thp_starter.cpp ${CMAKE_CURRENT_BINARY_DIR}/thp_starter.rc)
|
||||
NGL_TARGET_LINK_LIBRARIES(thp_starter user32.lib opengl32.lib gdi32.lib)
|
||||
NGL_INSTALL_TARGET(thp_starter)
|
||||
ENDIF(WIN32)
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Small wrapper to automatically start thp_viewer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <gl/gl.h>
|
||||
#include <gl/glu.h>
|
||||
|
||||
static void* getGLExtensionFuncPtr(const char *funcName, const char *fallbackFuncName)
|
||||
{
|
||||
void* ptr = wglGetProcAddress(funcName);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
return wglGetProcAddress(fallbackFuncName);
|
||||
}
|
||||
|
||||
static int checkOpenGL(HWND hWnd)
|
||||
{
|
||||
HDC hDC = GetDC( hWnd );
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
ZeroMemory( &pfd, sizeof( pfd ) );
|
||||
pfd.nSize = sizeof( pfd );
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
|
||||
PFD_SUPPORT_OPENGL |
|
||||
PFD_DOUBLEBUFFER |
|
||||
PFD_SWAP_EXCHANGE;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cAlphaBits = 8;
|
||||
pfd.cDepthBits = 0;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
int iFormat = ChoosePixelFormat( hDC, &pfd );
|
||||
if( !SetPixelFormat( hDC, iFormat, &pfd ) ) {
|
||||
DWORD dw = GetLastError();
|
||||
int ret = MessageBox(NULL,
|
||||
L"Your system does not support some mandatory OpenGL Functions.\nThe THP-Viewer may not display all things correct!\nDo you really want to start the THP-viewer?",
|
||||
L"THP-Viewer startup",
|
||||
MB_ICONWARNING|MB_YESNO);
|
||||
if(ret == IDNO) {
|
||||
ReleaseDC( hWnd, hDC );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
HGLRC hRC = wglCreateContext( hDC );
|
||||
|
||||
DWORD dw = wglMakeCurrent( hDC, hRC );
|
||||
void *_glCompressedTexImage2D = getGLExtensionFuncPtr( "glCompressedTexImage2D", "glCompressedTexImage2DARB" );
|
||||
if(!_glCompressedTexImage2D) {
|
||||
int ret = MessageBox(NULL,
|
||||
L"Your system does not support the mandatory OpenGL Function glCompressedTexImage2D.\nThe THP-Viewer may not display all things correct!\nDo you really want to start the THP-viewer?",
|
||||
L"THP-Viewer startup",
|
||||
MB_ICONWARNING|MB_YESNO);
|
||||
if(ret == IDNO) {
|
||||
wglDeleteContext( hRC );
|
||||
ReleaseDC( hWnd, hDC );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
wglDeleteContext( hRC );
|
||||
ReleaseDC( hWnd, hDC );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int startThpViewer(HINSTANCE hInstance)
|
||||
{
|
||||
TCHAR fn[MAX_PATH*10];
|
||||
DWORD len = GetModuleFileName(hInstance, fn, sizeof(fn));
|
||||
|
||||
for(int i = len - 1; i >= 0; --i) {
|
||||
if(fn[i] == '\\')
|
||||
break;
|
||||
fn[i] = '\0';
|
||||
}
|
||||
wcscat(fn, L"thp\\thp_viewer.exe");
|
||||
|
||||
STARTUPINFO si; ZeroMemory(&si, sizeof(si));
|
||||
PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi));
|
||||
si.cb = sizeof(si);
|
||||
|
||||
DWORD ret = CreateProcess(fn,
|
||||
NULL, // lpCommandLine
|
||||
NULL, // lpProcessAttributes
|
||||
NULL, // lpThreadAttributes
|
||||
NULL, // bInheritHandles
|
||||
0, // dwCreationFlags
|
||||
NULL, // lpEnvironment
|
||||
NULL, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&pi); // lpProcessInformation
|
||||
|
||||
if(ret == 0) {
|
||||
MessageBox(NULL,
|
||||
L"Error starting the THP-Viewer!",
|
||||
L"THP-Viewer startup",
|
||||
MB_ICONWARNING|MB_OK);
|
||||
return 1;
|
||||
}
|
||||
// Wait until child process exits.
|
||||
WaitForSingleObject( pi.hProcess, INFINITE );
|
||||
|
||||
// Close process and thread handles.
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return DefWindowProc( hWnd, message, wParam, lParam );
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
ZeroMemory( &wc, sizeof(wc) );
|
||||
// register window class
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = L"THP_Viewer_startup";
|
||||
RegisterClass( &wc );
|
||||
|
||||
// create main window
|
||||
HWND hWnd = CreateWindow(L"THP_Viewer_startup",
|
||||
L"THP-Viewer startup",
|
||||
WS_CAPTION | WS_POPUPWINDOW,
|
||||
0, 0, 256, 256,
|
||||
NULL, NULL, hInstance, NULL );
|
||||
|
||||
int iRet = checkOpenGL(hWnd);
|
||||
if(iRet != 0)
|
||||
return iRet;
|
||||
return startThpViewer(hInstance);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "@THP_ICO@"
|
||||
@@ -0,0 +1,6 @@
|
||||
[autorun]
|
||||
OPEN=thp\bin\thp_viewer.exe
|
||||
ICON=thp\bin\thp_viewer.exe,0
|
||||
SHELL=readit
|
||||
SHELL\readit="THP-Viewer starten"
|
||||
SHELL\readit\command=thp\bin\thp_viewer.exe
|
||||
@@ -0,0 +1,28 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
#log4j.logger.GDW=WARN
|
||||
#log4j.logger.GDW_CTC=WARN
|
||||
#log4j.logger.KALA=WARN
|
||||
#
|
||||
# THP
|
||||
#
|
||||
#log4j.logger.THP=WARN
|
||||
#log4j.logger.THP.AudioVideoWidget=WARN
|
||||
#log4j.logger.THP.PlanFilter=WARN
|
||||
#log4j.logger.THP.SymbolLoaderThread=WARN
|
||||
#log4j.logger.THP.SHMFileHandler=WARN
|
||||
|
||||
# Appender
|
||||
############
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
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
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Main entry for thp viewer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include <nglapplication/nglsingleapplication.h>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkProxy>
|
||||
#include <QSplashScreen>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
#include "thp_viewer.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions::None)
|
||||
{
|
||||
addOption({{QStringLiteral("l"), QStringLiteral("lang")},
|
||||
QStringLiteral("Language iso code to use (de_DE, en_GB, en_US)"),
|
||||
QStringLiteral("<locale iso code>")
|
||||
});
|
||||
addOption({{QStringLiteral("t"), QStringLiteral("alwaysontop")},
|
||||
QStringLiteral("Set as always on top window")
|
||||
});
|
||||
}
|
||||
bool useAsAlwaysOnTop() const
|
||||
{
|
||||
return isSet(QStringLiteral("t"));
|
||||
}
|
||||
QString langIsoCode() const { return value(QStringLiteral("l")); }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
|
||||
NGLSingleApplication app(argc, argv);
|
||||
app.createLogger("THP", "log4cxx_thp_viewer.props");
|
||||
app.setOrganizationName(QStringLiteral("RME"));
|
||||
app.setApplicationName(QStringLiteral("thp_viewer"));
|
||||
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
QDir::setSearchPaths(QLatin1String("icon"), QStringList(QLatin1String(":/style/")));
|
||||
Q_INIT_RESOURCE(rme_light_style);
|
||||
|
||||
// Parse Options
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
// Set Translation
|
||||
QString langIsoCode = options.langIsoCode();
|
||||
if (langIsoCode.isEmpty())
|
||||
langIsoCode = QLocale::system().name();
|
||||
NGL::setTranslationLocale(langIsoCode.toLatin1());
|
||||
|
||||
//check for optional alyways on top flag
|
||||
bool alwaysOnTop = options.useAsAlwaysOnTop();
|
||||
|
||||
QString index;
|
||||
const QStringList args = options.positionalArguments();
|
||||
|
||||
// QString searchDir = QCoreApplication::applicationDirPath();
|
||||
QString searchDir(QDir::currentPath());
|
||||
|
||||
if (args.count() == 1)
|
||||
{
|
||||
QFileInfo fi(args.first());
|
||||
if (fi.isDir())
|
||||
searchDir = fi.absolutePath();
|
||||
else
|
||||
index = fi.absoluteFilePath();
|
||||
}
|
||||
|
||||
if (index.isEmpty())
|
||||
{
|
||||
const auto indexFiles = { QStringLiteral("index_%1.html").arg(langIsoCode),
|
||||
QStringLiteral("index.html") };
|
||||
for (const QString &indexFile : indexFiles)
|
||||
{
|
||||
QDir d(searchDir);
|
||||
index = d.absoluteFilePath(indexFile);
|
||||
while (!d.exists(index))
|
||||
{
|
||||
if (!d.cdUp())
|
||||
break;
|
||||
index = d.absoluteFilePath(indexFile);
|
||||
}
|
||||
if (d.exists(index))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo fi(index);
|
||||
QString basePath = fi.path() + QLatin1Char('/');
|
||||
if (!fi.exists() || !fi.isFile())
|
||||
{
|
||||
fprintf(stderr, "%s <path_to_html> basePath=%s\n", argv[0], basePath.toStdString().c_str());
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("File missing"),
|
||||
QObject::tr("Could not find a valid index.html - aborting"));
|
||||
return -1;
|
||||
}
|
||||
index = fi.absoluteFilePath();
|
||||
|
||||
if (app.sendMessage(index))
|
||||
return 0;
|
||||
|
||||
int ret = 1;
|
||||
{
|
||||
QString splashfile = basePath;
|
||||
static const auto extension = {QStringLiteral("gif"),
|
||||
QStringLiteral("jpg"),
|
||||
QStringLiteral("png")};
|
||||
for (const auto &ext : extension)
|
||||
{
|
||||
const QString fn = splashfile + QStringLiteral("/wappen.") + ext;
|
||||
if (!QFile::exists(fn))
|
||||
continue;
|
||||
splashfile = fn;
|
||||
break;
|
||||
}
|
||||
|
||||
const QPixmap splashPixmap(splashfile);
|
||||
QSplashScreen splash((splashPixmap));
|
||||
if (!splashPixmap.isNull())
|
||||
splash.show();
|
||||
|
||||
#ifdef BUILD_STATIC_LIBRARIES
|
||||
Q_INIT_RESOURCE(libsymbol);
|
||||
Q_INIT_RESOURCE(nglresources);
|
||||
#endif
|
||||
|
||||
NGL::ThpViewer view(QUrl::fromLocalFile(index));
|
||||
if (alwaysOnTop)
|
||||
{
|
||||
view.setWindowFlag(Qt::WindowStaysOnTopHint, true);
|
||||
view.setWindowFlag(Qt::WindowMinimizeButtonHint, false);
|
||||
}
|
||||
|
||||
if (!view.init())
|
||||
return ret;
|
||||
view.center();
|
||||
|
||||
QObject::connect(&app, &NGLSingleApplication::messageReceived,
|
||||
&view, &NGL::ThpViewer::onNewThp);
|
||||
view.show();
|
||||
splash.finish(&view);
|
||||
|
||||
ret = app.exec();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Plugin Provider for standalone SRP / THP
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AdvancedSymbology/Data/asb_foreign_interface_impl.h>
|
||||
#include <Buildings/bld_dtc.h>
|
||||
#include <CentralEffectSimulation/ces_dtc.h>
|
||||
#include <GuezIedManagement/gim_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <InfrastructureManagement/Data/ism_foreign_data_plugin.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
#include "thp_situation_filter_interface_impl.h"
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
QString SitMapPluginProvider::toString() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool SitMapPluginProvider::init(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
{
|
||||
m_ddsConnector = ddsConnector;
|
||||
|
||||
m_buildingPluginProvider = std::make_shared<BuildingPluginProvider>();
|
||||
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(ddsConnector);
|
||||
m_aesDtc->enableAll();
|
||||
m_bldDtc = Buildings::Interface::Dtc::create(ddsConnector);
|
||||
m_bldDtc->enableAll();
|
||||
m_cesDtc = CentralEffectSimulation::Interface::Dtc::create(ddsConnector);
|
||||
m_cesDtc->enableAll();
|
||||
m_gimDtc = GuezIedManagement::Interface::Dtc::create(ddsConnector);
|
||||
m_gimDtc->enableAll();
|
||||
// m_ismDtc = InfrastructureManagement::Interface::Dtc::create(ddsConnector);
|
||||
// m_ismDtc->enableAll();
|
||||
// m_ismForeign = std::make_shared<InfrastructureManagement::ForeignInterfaceImpl>(m_ismDtc);
|
||||
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(ddsConnector);
|
||||
m_ppmDtc->enableAll();
|
||||
m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(ddsConnector);
|
||||
m_pdmDtc->enableAll();
|
||||
|
||||
// needs m_ppmDtc
|
||||
m_fltParticipantIfc = std::make_shared<FilterManagement::ThpFilterInterfaceImpl>(m_ppmDtc);
|
||||
m_fltAesIfc = std::make_shared<FilterManagement::ThpFilterInterfaceImpl>(m_ppmDtc);
|
||||
m_fltBuildingComponentIfc = std::make_shared<FilterManagement::ThpFilterInterfaceImpl>(m_ppmDtc);
|
||||
// m_fltParticipantIfc = m_fltAesIfc; // Not sure, lets try
|
||||
|
||||
return m_buildingPluginProvider->init(ddsConnector, this);
|
||||
}
|
||||
|
||||
|
||||
bool BuildingPluginProvider::init(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
SitMapPluginProvider *smPluginProvider)
|
||||
{
|
||||
Q_ASSERT(smPluginProvider);
|
||||
m_smPluginProvider = smPluginProvider;
|
||||
connect(m_smPluginProvider, &SitMapPluginProvider::partitionTimeChanged,
|
||||
this, &BuildingPluginProvider::partitionTimeChanged);
|
||||
|
||||
m_connectionParams.domainId = ddsConnector->getDomainId();
|
||||
m_connectionParams.partitionId = ddsConnector->getPartitionId();
|
||||
m_connectionParams.exerciseId = ddsConnector->getPartitionId();
|
||||
m_connectionParams.tcpConnectionUrl = ddsConnector->getTcpConnectionUrl();
|
||||
|
||||
m_asbIfc = std::make_shared<AdvancedSymbology::ForeignInterfaceImpl>(m_smPluginProvider->ppmDtc(),
|
||||
m_smPluginProvider->aesDtc(),
|
||||
m_smPluginProvider->gimDtc());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> SitMapPluginProvider::ismDataIfc() const
|
||||
{
|
||||
if (!m_ismForeign)
|
||||
m_ismForeign = std::make_shared<InfrastructureManagement::ForeignInterfaceImpl>(ismDtc());
|
||||
|
||||
return m_ismForeign;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> SitMapPluginProvider::ismDtc() const
|
||||
{
|
||||
if (!m_ismDtc)
|
||||
{
|
||||
m_ismDtc = InfrastructureManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
m_ismDtc->enableAll();
|
||||
}
|
||||
|
||||
return m_ismDtc;
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Plugin Provider for standalone SRP / THP
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SituationMap/AdapterDds/plugin_provider.h>
|
||||
#include <BuildingViewer/Common/bdv_plugin_provider.h>
|
||||
#include <AlarmManagement/alm_info_gui_plugin_interface.h>
|
||||
#include <LtsAppDescriptor/lts_app_descriptor.h>
|
||||
#include <LtsSession/lts_session_data_dds.h>
|
||||
#include <QVector>
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class BuildingPluginProvider;
|
||||
class SitMapPluginProvider final : public SituationMap::PluginProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using SituationMap::PluginProvider::PluginProvider;
|
||||
|
||||
QString toString() const override;
|
||||
|
||||
bool init(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
|
||||
void emitPartitionTimeChanged(qint64 curTime) { m_curPartitionTime = curTime; emit partitionTimeChanged(curTime); }
|
||||
|
||||
void setExerciseId(int exerciseId) { m_exerciseId = exerciseId; }
|
||||
int exerciseId() const override { return m_exerciseId; }
|
||||
bool isSessionValid() const override { return true; }
|
||||
qint64 partitionTime() const override { return m_curPartitionTime; }
|
||||
int partitionId() const override { return -1; }
|
||||
int operatorId() const override { return 42; }
|
||||
LtsAppDescriptor::App appId() const override { return LtsAppDescriptor::App::ThpSituationReplay; }
|
||||
|
||||
bool isVisibleParty(int) const override { return true; }
|
||||
QString workspaceId() const override { return {}; }
|
||||
bool isReplayPartition() const override { return false; }
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> aesDtc() const override { return m_aesDtc; }
|
||||
std::shared_ptr<AreaEffectSimulation::ForeignInfoGuiInterface> aesInfoIfc() const override { return {}; }
|
||||
std::shared_ptr<AlarmManagement::Interface::Dtc> almDtc() const override { return {}; }
|
||||
std::shared_ptr<AlarmManagement::Interface::Ftc> almFtc() const override { return {}; }
|
||||
std::shared_ptr<AlarmManagement::ForeignInfoGuiInterface> almInfoIfc() const override { return {}; }
|
||||
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc() const override { return {}; }
|
||||
std::shared_ptr<AssetManagement::Interface::Ftc> asmFtc() const override { return {}; }
|
||||
std::shared_ptr<Buildings::Interface::Dtc> bldDtc() const override { return m_bldDtc; }
|
||||
std::shared_ptr<Buildings::Interface::Ftc> bldFtc() const override { return {}; }
|
||||
std::shared_ptr<Buildings::ForeignInfoGuiInterface> bldInfoIfc() const override { return {}; }
|
||||
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> cesDtc() const override { return m_cesDtc; }
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc() const override { return {}; }
|
||||
std::shared_ptr<ExerciseManagement::Interface::Ftc> exmFtc() const override { return {}; }
|
||||
std::shared_ptr<FilterManagement::Interface::Dtc> fltDtc() const override { return {}; }
|
||||
std::shared_ptr<FilterManagement::Interface::Ftc> fltFtc() const override { return {}; }
|
||||
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc() const override { return m_fltParticipantIfc; }
|
||||
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> fltAesIfc() const override { return m_fltAesIfc; }
|
||||
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> fltBuildingComponentIfc() const override { return m_fltBuildingComponentIfc; }
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> gimDtc() const override { return m_gimDtc; }
|
||||
std::shared_ptr<GuezIedManagement::ForeignGuiInterface> gimIfc() const override { return {}; }
|
||||
std::shared_ptr<GuezNasat::Interface::Dtc> gnaDtc() const override { return {}; }
|
||||
std::shared_ptr<GuezNasat::ForeignGuiInterface> gnaIfc() const override { return {}; }
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc() const override;
|
||||
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> ismDataIfc() const override;
|
||||
std::shared_ptr<InfrastructureManagement::ForeignResourceManagementGuiInterface> ismGuiIfc() const override { return {}; }
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> opmDtc() const override { return {}; }
|
||||
std::shared_ptr<OperatorManagement::Interface::Ftc> opmFtc() const override { return {}; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> ppmDtc() const override { return m_ppmDtc; }
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> ppmFtc() const override { return {}; }
|
||||
std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> ppmParticipantInfoIfc() const override { return {}; }
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const override { return m_pdmDtc; }
|
||||
std::shared_ptr<SituationReplay::Interface::Dtc> srpDtc() const override { return m_srpDtc; }
|
||||
std::shared_ptr<OcSituationClient::ForeignParticipantInfoGuiInterface> ocParticipantInfoIfc() const override { return {}; }
|
||||
std::shared_ptr<ServiceMonitor::ForeignGuiInterface> smoServiceMonitorIfc() const override { return {}; }
|
||||
std::shared_ptr<TargetManagement::Interface::Dtc> tgtDtc() const override { return {}; }
|
||||
std::shared_ptr<ComponentMonitor::Interface::Dtc> cmoDtc() const override { return {}; }
|
||||
|
||||
// for BuildingPluginProvider
|
||||
BuildingPluginProvider *buildingPluginProvider() { return m_buildingPluginProvider.get(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
|
||||
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
|
||||
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> m_fltParticipantIfc;
|
||||
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> m_fltAesIfc;
|
||||
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> m_fltBuildingComponentIfc;
|
||||
std::shared_ptr<GuezIedManagement::Interface::Dtc> m_gimDtc;
|
||||
mutable std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
mutable std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_ismForeign;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<SituationReplay::Interface::Dtc> m_srpDtc;
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
qint64 m_curPartitionTime = 0;
|
||||
int m_exerciseId = 0;
|
||||
|
||||
std::shared_ptr<BuildingPluginProvider> m_buildingPluginProvider;
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
};
|
||||
|
||||
class BuildingPluginProvider final : public BuildingViewer::PluginProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using BuildingViewer::PluginProvider::PluginProvider;
|
||||
|
||||
BuildingPluginProvider() = default;
|
||||
|
||||
QString toString() const override { return m_smPluginProvider->toString(); }
|
||||
|
||||
bool init(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
SitMapPluginProvider *smPluginProvider);
|
||||
|
||||
void emitPartitionTimeChanged(qint64 curTime) { m_smPluginProvider->emitPartitionTimeChanged(curTime); }
|
||||
|
||||
int exerciseId() const override { return m_smPluginProvider->exerciseId(); }
|
||||
qint64 partitionTime() const override { return m_smPluginProvider->partitionTime(); }
|
||||
bool isReplayPartition() const override { return false; }
|
||||
bool isVisibleParty(int partyId) const override { return m_smPluginProvider->isVisibleParty(partyId); }
|
||||
LtsSession::DdsConnectionParams connParams() const override { return m_connectionParams; }
|
||||
|
||||
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> asbIfc() const override { return m_asbIfc; }
|
||||
std::shared_ptr<AudioVideoManagement::ForeignDataInterface> avmDataIfc() const override { return nullptr; } // optional
|
||||
std::shared_ptr<Buildings::Interface::Dtc> bldDtc() const override { return m_smPluginProvider->bldDtc(); }
|
||||
std::shared_ptr<Buildings::ForeignInfoGuiInterface> bldInfoIfc() const override { return m_smPluginProvider->bldInfoIfc(); } // optional
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc() const override { return m_smPluginProvider->ismDtc(); }
|
||||
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> ismDataIfc() const override { return m_smPluginProvider->ismDataIfc(); }
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> aesDtc() const override { return m_smPluginProvider->aesDtc(); } // optional
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> ppmDtc() const override { return m_smPluginProvider->ppmDtc(); } // optional
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const override { return m_smPluginProvider->pdmDtc(); } // optional
|
||||
std::shared_ptr<SituationReplay::Interface::Dtc> srpDtc() const override { return m_smPluginProvider->srpDtc(); } // optional
|
||||
std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> ppmParticipantInfoIfc() const override { return m_smPluginProvider->ppmParticipantInfoIfc(); } // optional
|
||||
|
||||
private:
|
||||
SitMapPluginProvider *m_smPluginProvider{nullptr};
|
||||
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
|
||||
LtsSession::DdsConnectionParams m_connectionParams;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Simple implmentation of FilterHandling for THP
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_interface_impl.h"
|
||||
#include <FilterManagement/Gui/Aes/Common/symbol_appearance_settings_impl.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/aes_display_filter_impl.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/building_cmpnt_settings_impl.h>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
ThpFilterInterfaceImpl::ThpFilterInterfaceImpl(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtcPpm)
|
||||
: m_fltSymbols(std::make_shared<SymbolAppearanceSettingsImpl>(dtcPpm))
|
||||
, m_fltAes(std::make_shared<AesDisplayFilterImpl>())
|
||||
, m_fltBuildingComponentSettings(std::make_shared<BuildingComponentSettingsImpl>())
|
||||
{
|
||||
m_fltAes->setVisiblePartiesCheck([](int) -> bool { return true; });
|
||||
}
|
||||
|
||||
std::shared_ptr<SymbolAppearanceSettings> ThpFilterInterfaceImpl::symbolAppearanceForOperator(int operatorId, const QString &context)
|
||||
{
|
||||
Q_UNUSED(operatorId);
|
||||
Q_UNUSED(context);
|
||||
return m_fltSymbols;
|
||||
}
|
||||
|
||||
std::shared_ptr<AesDisplayFilter> ThpFilterInterfaceImpl::aesFilterForOperator(int operatorId, const QString &context)
|
||||
{
|
||||
Q_UNUSED(operatorId);
|
||||
Q_UNUSED(context);
|
||||
return m_fltAes;
|
||||
}
|
||||
|
||||
std::shared_ptr<BuildingComponentSettings> ThpFilterInterfaceImpl::buildingComponentSettingsForOperator(int operatorId, const QString &context)
|
||||
{
|
||||
Q_UNUSED(operatorId);
|
||||
Q_UNUSED(context);
|
||||
return m_fltBuildingComponentSettings;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Simple implmentation of FilterHandling for THP
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <FilterManagement/flt_participant_plugin_interface.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class ThpFilterInterfaceImpl : public ForeignFltParticipantGuiInterface,
|
||||
public ForeignAesGuiInterface,
|
||||
public ForeignFltBuildingComponentGuiInterface
|
||||
{
|
||||
public:
|
||||
explicit ThpFilterInterfaceImpl(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtcPpm);
|
||||
|
||||
// from Participant
|
||||
std::shared_ptr<SymbolAppearanceSettings> symbolAppearanceForOperator(int operatorId, const QString &context) override;
|
||||
|
||||
// from Aes
|
||||
std::shared_ptr<AesDisplayFilter> aesFilterForOperator(int operatorId, const QString &context) override;
|
||||
|
||||
// from BuildingComponent
|
||||
std::shared_ptr<BuildingComponentSettings> buildingComponentSettingsForOperator(int operatorId, const QString &context) override;
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr<SymbolAppearanceSettings> m_fltSymbols;
|
||||
std::shared_ptr<AesDisplayFilter> m_fltAes;
|
||||
std::shared_ptr<BuildingComponentSettings> m_fltBuildingComponentSettings;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,686 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Main thp viewer widget
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_viewer.h"
|
||||
#include "ui_thp_viewer.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QKeyEvent>
|
||||
#include <QPrintDialog>
|
||||
#include <QPrinter>
|
||||
#include <QPainter>
|
||||
#include <QMessageBox>
|
||||
#include <QTextDocument>
|
||||
#include <QScreen>
|
||||
#include <QDesktopServices>
|
||||
#include <QDomElement>
|
||||
#include <QDomDocument>
|
||||
#include <QUrl>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QInputDialog>
|
||||
#include <QDir>
|
||||
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
/*
|
||||
* ThpViewer base class
|
||||
*/
|
||||
ThpViewer::ThpViewer(const QUrl &url, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::thpViewer)
|
||||
, m_scaleFactor(1.0)
|
||||
, m_homeLink(url)
|
||||
, m_homePath(QFileInfo(m_homeLink.toLocalFile()).absolutePath())
|
||||
, m_trainingName(QString())
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("ThpViewer"))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->audioWidget->setAV(true);
|
||||
ui->videoWidget->setAV(false);
|
||||
|
||||
/*
|
||||
TODO
|
||||
if (!conffile.isEmpty())
|
||||
{
|
||||
QSettings thpsettings(conffile, QSettings::IniFormat, this);
|
||||
|
||||
// needed?
|
||||
const char timeZone = thpsettings.value(QStringLiteral("Time/Timezone"), QStringLiteral("Z")).toString().at(0).toLatin1();
|
||||
DTG::setTimezone(timeZone, true);
|
||||
}
|
||||
*/
|
||||
|
||||
QString basedir(url.toLocalFile());
|
||||
basedir = basedir.left(basedir.lastIndexOf(QLatin1Char('/')));
|
||||
|
||||
DEBUG_LOG(m_logger) << "url: " << url.toString() << " basedir: " << basedir;
|
||||
|
||||
QFont f = ui->mainLabel->font();
|
||||
f.setBold(true);
|
||||
f.setPointSizeF(f.pointSizeF() * 1.2);
|
||||
ui->mainLabel->setFont(f);
|
||||
|
||||
connect(ui->closeButton, &QToolButton::clicked, this, &ThpViewer::close);
|
||||
connect(ui->backButton, &QToolButton::clicked, this, &ThpViewer::onBack);
|
||||
connect(ui->homeButton, &QToolButton::clicked, this, &ThpViewer::onHome);
|
||||
connect(ui->helpButton, &QToolButton::clicked, this, &ThpViewer::onHelp);
|
||||
connect(ui->printButton, &QToolButton::clicked, this, &ThpViewer::onPrint);
|
||||
connect(ui->fullScreenButton, &QToolButton::clicked, this, &ThpViewer::onFullScreen);
|
||||
connect(ui->htmlWidget, &THP::HtmlWidget::linkClicked, this, &ThpViewer::onLinkClicked);
|
||||
connect(ui->htmlWidget, &THP::HtmlWidget::urlChanged, this, &ThpViewer::onUrlChanged);
|
||||
connect(ui->htmlWidget, &THP::HtmlWidget::titleChanged, this, &ThpViewer::onTitleChanged);
|
||||
|
||||
ui->backButton->setEnabled(false);
|
||||
ui->helpButton->setVisible(false); // Help disabled for now
|
||||
#ifndef Q_WS_WIN
|
||||
setWindowIcon(QIcon(QStringLiteral(":icons/16x16/rde.ico")));
|
||||
#endif
|
||||
setWindowTitle(tr("Combat Training Center"));
|
||||
}
|
||||
|
||||
ThpViewer::~ThpViewer()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool ThpViewer::init()
|
||||
{
|
||||
QFile file(m_homePath + QStringLiteral("/data.json"));
|
||||
int exerciseId = 0;
|
||||
if (file.exists() && file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
const auto obj = QJsonDocument::fromJson(file.readAll()).object();
|
||||
exerciseId = obj.value(QLatin1String("exerciseId")).toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
QFile file2(m_homePath + QStringLiteral("/../data.json"));
|
||||
if (file2.exists() && file2.open(QIODevice::ReadOnly))
|
||||
{
|
||||
const auto obj = QJsonDocument::fromJson(file2.readAll()).object();
|
||||
exerciseId = obj.value(QLatin1String("exerciseId")).toInt();
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Use EXERCISE" << exerciseId;
|
||||
|
||||
if (!ui->situationWidget->init(m_homePath, exerciseId))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init situation widget - abort";
|
||||
return false;
|
||||
}
|
||||
if (!ui->buildingWidget->init(ui->situationWidget->replayHandler(),
|
||||
ui->situationWidget->pluginProvider()->buildingPluginProvider(),
|
||||
m_homePath))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not init situation widget - abort";
|
||||
return false;
|
||||
}
|
||||
|
||||
onZoomChanged();
|
||||
onLinkClicked(m_homeLink);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThpViewer::center()
|
||||
{
|
||||
QRect rect = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
// 80 %
|
||||
int width = rect.width() * 4 / 5;
|
||||
int height = rect.height() * 4 / 5;
|
||||
int x = rect.width() / 2 - width / 2;
|
||||
int y = rect.height() / 2 - height / 2;
|
||||
resize(width, height);
|
||||
move(x, y);
|
||||
}
|
||||
|
||||
void ThpViewer::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// explicit delete those two widgets here, otherwise we may get in trouble
|
||||
// on windows when the app is closed with the 'X' button from the window frame
|
||||
delete ui->buildingWidget;
|
||||
ui->buildingWidget = nullptr;
|
||||
delete ui->situationWidget;
|
||||
ui->situationWidget = nullptr;
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void ThpViewer::onNewThp(const QString &index)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onNewThp: " << index;
|
||||
|
||||
if (index.isEmpty())
|
||||
return;
|
||||
m_homeLink = QUrl::fromLocalFile(index);
|
||||
m_homePath = QFileInfo(m_homeLink.toLocalFile()).absolutePath();
|
||||
DEBUG_LOG(m_logger) << "home: " << m_homeLink.toString();
|
||||
onLinkClicked(m_homeLink);
|
||||
ui->backButton->setEnabled(false);
|
||||
this->raise();
|
||||
}
|
||||
|
||||
void ThpViewer::onTitleChanged(const QString &title)
|
||||
{
|
||||
if (title.endsWith(QLatin1String("html")) ||
|
||||
title.endsWith(QLatin1String("html#!/")))
|
||||
return;
|
||||
if (m_trainingName.isEmpty())
|
||||
m_trainingName = title;
|
||||
ui->mainLabel->setText(m_trainingName == title ? m_trainingName : QStringLiteral("%1 - %2").arg(m_trainingName, title));
|
||||
}
|
||||
|
||||
void ThpViewer::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
switch (e->key())
|
||||
{
|
||||
case Qt::Key_Backspace:
|
||||
onBack();
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
if (ui->stackedWidget->isVisible() && ui->stackedWidget->currentWidget() == ui->situationWidget)
|
||||
return;
|
||||
if (m_scaleFactor < 10)
|
||||
{
|
||||
m_scaleFactor *= 1.5;
|
||||
onZoomChanged();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
{
|
||||
if (QApplication::queryKeyboardModifiers() == Qt::ControlModifier)
|
||||
onLinkClicked(QUrl::fromLocalFile(QDir::currentPath() + QStringLiteral("/") + QInputDialog::getText(this, {}, QStringLiteral("href_local"))));
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Minus:
|
||||
if (ui->stackedWidget->isVisible() && ui->stackedWidget->currentWidget() == ui->situationWidget)
|
||||
return;
|
||||
if (m_scaleFactor > 0.05)
|
||||
{
|
||||
m_scaleFactor /= 1.5;
|
||||
onZoomChanged();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F1:
|
||||
onHelp();
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
if (isFullScreen())
|
||||
onFullScreen();
|
||||
break;
|
||||
default:
|
||||
QWidget::keyPressEvent(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ThpViewer::onHelp()
|
||||
{
|
||||
QFileInfo f(QStringLiteral("%1/../DATA/help/%2/help.html").arg(QCoreApplication::applicationDirPath(), QString::fromLatin1(NGL::translationLocale())));
|
||||
if (f.exists())
|
||||
onLinkClicked(QUrl::fromLocalFile(f.absoluteFilePath())); // TODO Pfad anpassen!
|
||||
else
|
||||
{
|
||||
f.setFile(qApp->applicationDirPath() + QStringLiteral("/../DATA/help/en_US/help.html")); // TODO Pfad anpassen!
|
||||
if (f.exists())
|
||||
onLinkClicked(QUrl::fromLocalFile(f.absoluteFilePath()));
|
||||
}
|
||||
}
|
||||
|
||||
void ThpViewer::onZoomChanged()
|
||||
{
|
||||
ui->pdfWidget->setZoomFactor(m_scaleFactor);
|
||||
ui->htmlWidget->setZoomFactor(m_scaleFactor);
|
||||
|
||||
// double zoom = ( int ) ( m_scaleFactor * 100. + 0.5 );
|
||||
// ui->statusbar->showMessage ( tr ( "zoom: %1 %" ).arg ( zoom ) );
|
||||
}
|
||||
|
||||
void ThpViewer::onLinkClicked(const QUrl &url)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "url: " << url.toString();
|
||||
|
||||
const QString path = url.path();
|
||||
const QString lpath = path.toLower();
|
||||
|
||||
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
|
||||
const QStringRef ext2Chars = ext.left(2);
|
||||
|
||||
ui->audioWidget->stop();
|
||||
ui->videoWidget->stop();
|
||||
// Video-only
|
||||
if (lpath.endsWith(QLatin1String("video.pls")) ||
|
||||
ext == QLatin1String("mpg") ||
|
||||
ext == QLatin1String("avi") ||
|
||||
ext == QLatin1String("ogg"))
|
||||
{
|
||||
ui->videoWidget->play(url);
|
||||
|
||||
ui->stackedWidget->hide();
|
||||
ui->videoWidget->show();
|
||||
ui->audioWidget->hide();
|
||||
|
||||
ui->backButton->setEnabled(true);
|
||||
// Audio-only
|
||||
}
|
||||
else if (lpath.endsWith(QLatin1String("audio.pls")) ||
|
||||
ext == QLatin1String("mp3"))
|
||||
{
|
||||
ui->audioWidget->play(url);
|
||||
|
||||
// Ermitteln der Groesse des AudioWidgets
|
||||
QSize sizeAudio = ui->audioWidget->sizeHint();
|
||||
QSize sizeStack = ui->stackedWidget->sizeHint();
|
||||
sizeStack -= sizeAudio;
|
||||
QList<int> l;
|
||||
l << sizeStack.height() << sizeAudio.height();
|
||||
ui->splitter_1->setSizes(l);
|
||||
|
||||
ui->stackedWidget->show(); // hier können wir html mit anzeigen
|
||||
ui->videoWidget->hide();
|
||||
ui->audioWidget->show();
|
||||
|
||||
ui->backButton->setEnabled(true);
|
||||
// PDF-only
|
||||
}
|
||||
else if (ext == QLatin1String("pdf"))
|
||||
{
|
||||
if (ui->pdfWidget->showPDF(url))
|
||||
{
|
||||
|
||||
ui->stackedWidget->setCurrentWidget(ui->pdfWidget);
|
||||
ui->stackedWidget->show();
|
||||
ui->pdfWidget->resizePdfToWidth();
|
||||
ui->videoWidget->hide();
|
||||
ui->audioWidget->hide();
|
||||
|
||||
ui->backButton->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Opening PDF file"),
|
||||
tr("Can not open PDF file %1 - missing or corrupt file!").arg(url.toString()));
|
||||
}
|
||||
}
|
||||
else if (lpath.endsWith(QLatin1String("sitmap.json"), Qt::CaseInsensitive))
|
||||
{
|
||||
|
||||
// 2D oder 3D ?
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " lpath = '" << lpath << "'";
|
||||
// peek into <lpath>/sitreplay.json:
|
||||
|
||||
QFileInfo fi(path);
|
||||
const QString basePath = fi.absolutePath();
|
||||
const QString replayConfigFile = basePath + QDir::separator() + QStringLiteral("sitreplay.json"); // aka replayConfigPath
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " replayConfigFile = '" << replayConfigFile << "'";
|
||||
}
|
||||
|
||||
// Lage-only
|
||||
QString localFile = url.toLocalFile();
|
||||
QString basePath = localFile;
|
||||
int idx = basePath.lastIndexOf(QLatin1Char('/'));
|
||||
idx = basePath.lastIndexOf(QLatin1Char('/'), idx - 1);
|
||||
if (idx >= 0)
|
||||
basePath.chop(basePath.size() - idx - 1);
|
||||
|
||||
ui->situationWidget->showSituation(url.toLocalFile(),
|
||||
basePath);
|
||||
|
||||
ui->stackedWidget->setCurrentWidget(ui->situationWidget);
|
||||
ui->stackedWidget->show();
|
||||
ui->videoWidget->hide();
|
||||
ui->audioWidget->hide();
|
||||
|
||||
ui->backButton->setEnabled(true);
|
||||
}
|
||||
else if (lpath.endsWith(QLatin1String("buildingViewer.json"), Qt::CaseInsensitive))
|
||||
{
|
||||
// BuildingViewer-only
|
||||
QString localFile = url.toLocalFile();
|
||||
QString basePath = localFile;
|
||||
int idx = basePath.lastIndexOf(QLatin1Char('/'));
|
||||
idx = basePath.lastIndexOf(QLatin1Char('/'), idx - 1);
|
||||
if (idx >= 0)
|
||||
basePath.chop(basePath.size() - idx - 1);
|
||||
ui->buildingWidget->showSituation(url.toLocalFile(),
|
||||
basePath);
|
||||
|
||||
ui->stackedWidget->setCurrentWidget(ui->buildingWidget);
|
||||
ui->stackedWidget->show();
|
||||
ui->videoWidget->hide();
|
||||
ui->audioWidget->hide();
|
||||
|
||||
ui->backButton->setEnabled(true);
|
||||
}
|
||||
else if (ext == QLatin1String("html") &&
|
||||
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
{
|
||||
// Kombiniert
|
||||
QHash<QString, QUrl> urls = getCombinedPlaybackDetails(url);
|
||||
|
||||
if (urls.isEmpty())
|
||||
return;
|
||||
|
||||
if (urls.contains(QLatin1String("audio")))
|
||||
{
|
||||
ui->audioWidget->show();
|
||||
ui->audioWidget->play(urls[QLatin1String("audio")]);
|
||||
}
|
||||
if (urls.contains(QLatin1String("video")))
|
||||
{
|
||||
ui->videoWidget->show();
|
||||
ui->videoWidget->play(urls[QLatin1String("video")]);
|
||||
}
|
||||
|
||||
// Einer von dreien:
|
||||
if (urls.contains(QLatin1String("pdf")))
|
||||
{
|
||||
ui->stackedWidget->setCurrentWidget(ui->pdfWidget);
|
||||
ui->pdfWidget->showPDF(urls[QLatin1String("pdf")]);
|
||||
ui->stackedWidget->show();
|
||||
}
|
||||
else if (urls.contains(QLatin1String("html")))
|
||||
{
|
||||
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
|
||||
ui->htmlWidget->showHTML(urls[QLatin1String("html")]);
|
||||
ui->stackedWidget->show();
|
||||
}
|
||||
else if (urls.contains(QLatin1String("jpg")))
|
||||
{
|
||||
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
|
||||
ui->htmlWidget->showHTML(urls[QLatin1String("jpg")]);
|
||||
ui->stackedWidget->show();
|
||||
}
|
||||
else if (urls.contains(QLatin1String("png")))
|
||||
{
|
||||
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
|
||||
ui->htmlWidget->showHTML(urls[QLatin1String("png")]);
|
||||
ui->stackedWidget->show();
|
||||
}
|
||||
else
|
||||
ui->stackedWidget->hide();
|
||||
ui->backButton->setEnabled(true);
|
||||
}
|
||||
else if (ext2Chars == QLatin1String("do") ||
|
||||
ext2Chars == QLatin1String("xl") ||
|
||||
ext2Chars == QLatin1String("pp"))
|
||||
QDesktopServices::openUrl(url);
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Trying to open url: " << url.toString();
|
||||
ui->htmlWidget->showHTML(url);
|
||||
|
||||
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
|
||||
ui->stackedWidget->show();
|
||||
ui->videoWidget->hide();
|
||||
ui->audioWidget->hide();
|
||||
|
||||
ui->backButton->setEnabled(url != m_homeLink);
|
||||
}
|
||||
}
|
||||
/********************************************************************************************
|
||||
* Parsed eine HTML-Dateinach allen Links, die sich direkt unterhalb des BODY-Tags befinden
|
||||
* und liefert die entsprechenden Link-URLs zurück, wenn diese das Tag ID besitzen.
|
||||
*
|
||||
* Von der aufrufenden Funktion derzeit ausgewertete Werte für ID sind:
|
||||
* html, audio, video, lage, pdf (alles klein geschrieben!)
|
||||
*/
|
||||
QHash<QString, QUrl> ThpViewer::getCombinedPlaybackDetails(const QUrl &url) const
|
||||
{
|
||||
QHash<QString, QUrl> hash;
|
||||
QFile file(url.toLocalFile());
|
||||
QDomDocument doc(QStringLiteral("RSS"));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return hash;
|
||||
QString errorStr;
|
||||
int errorLine, errorColumn;
|
||||
if (!doc.setContent(&file, true, &errorStr, &errorLine, &errorColumn))
|
||||
{
|
||||
file.close();
|
||||
return hash;
|
||||
}
|
||||
QDomElement domel = doc.documentElement();
|
||||
domel = domel.firstChildElement(QStringLiteral("BODY"));
|
||||
domel = domel.firstChildElement(QStringLiteral("A"));
|
||||
|
||||
while (!domel.isNull())
|
||||
{
|
||||
if (!domel.attribute(QStringLiteral("id")).isEmpty())
|
||||
{
|
||||
QUrl linkurl(domel.attribute(QStringLiteral("HREF")));
|
||||
if (linkurl.isRelative())
|
||||
linkurl = url.resolved(linkurl);
|
||||
DEBUG_LOG(m_logger) << "attr: " << domel.attribute(QStringLiteral("id")).toLower() << " url: " << linkurl.toString();
|
||||
hash[domel.attribute(QStringLiteral("id")).toLower()] = linkurl;
|
||||
}
|
||||
domel = domel.nextSiblingElement(QStringLiteral("A"));
|
||||
}
|
||||
file.close();
|
||||
return hash;
|
||||
}
|
||||
|
||||
void ThpViewer::onPrint()
|
||||
{
|
||||
if (ui->stackedWidget->isVisible())
|
||||
{
|
||||
if (ui->stackedWidget->currentWidget() == ui->situationWidget)
|
||||
{
|
||||
QImage image = ui->situationWidget->grabFrameBuffer();
|
||||
|
||||
QPrinter printer;
|
||||
QPrintDialog *dialog = new QPrintDialog(&printer, this);
|
||||
dialog->setWindowTitle(tr("Print Document"));
|
||||
if (dialog->exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(&printer);
|
||||
|
||||
QRectF rect = painter.viewport();
|
||||
|
||||
double mmH = printer.logicalDpiY() / 25.4; // 25.4 = mm/inch
|
||||
double mmW = printer.logicalDpiX() / 25.4;
|
||||
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 30));
|
||||
QString title = tr("Combat Training Center");
|
||||
QRectF textBox = painter.boundingRect(QRectF(), Qt::AlignLeft & Qt::TextSingleLine, title);
|
||||
textBox.setWidth(painter.viewport().width());
|
||||
painter.drawText(textBox, Qt::AlignCenter & Qt::TextSingleLine, title);
|
||||
QPointF underImage;
|
||||
|
||||
if (printer.orientation() == QPrinter::Portrait)
|
||||
{
|
||||
const QPointF textBlockBegin = QPointF(0 * mmW, 25 * mmH); // Baseline 25mm unter Seitenbeginn
|
||||
|
||||
// Noch mal schauen, welches (auch übersetzt!) der breiteste Bezeichner (also 1. Spalte) ist!
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
|
||||
textBox = painter.boundingRect(QRect(), Qt::AlignLeft & Qt::TextSingleLine, tr("Center point:\nExercise:\nTime:"));
|
||||
|
||||
// Textbox hat 3 Zeilen, also ist der Faktor pro Zeile 0.33 = 1/3
|
||||
// Spalte 1
|
||||
painter.drawText(textBlockBegin, tr("Exercise:"));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.33 * textBox.height()), tr("Time:"));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.66 * textBox.height()), tr("Center point:"));
|
||||
|
||||
// Zwischen Spalte 1 und Spalte 2 noch 3mm Platz lassen
|
||||
// Spalte 2
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
|
||||
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0), m_trainingName);
|
||||
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0.33 * textBox.height()), ui->situationWidget->currentDTGTime());
|
||||
painter.drawText(textBlockBegin + QPointF(textBox.width() + 3 * mmW, 0.66 * textBox.height()), ui->situationWidget->centerPointString());
|
||||
|
||||
// Das Bild soll formatfüllend angezeigt werden, das Rechteck muss 45mm "flacher" sein, da es erst ab 45mm gedruckt werden soll.
|
||||
QSizeF size = image.size();
|
||||
rect.adjust(0, 0, 0, -45 * mmH);
|
||||
size.scale(rect.size(), Qt::KeepAspectRatio);
|
||||
|
||||
// Und ab 45mm von oben drucken:
|
||||
QRectF imgrect = QRectF(QPointF(0 * mmW, 45 * mmH), size);
|
||||
painter.drawImage(imgrect, image);
|
||||
|
||||
// Untere linke Ecke des Bildes
|
||||
underImage = imgrect.bottomLeft();
|
||||
|
||||
}
|
||||
else // Landscape
|
||||
{
|
||||
// Noch mal schauen, welches (auch übersetzt!) der breiteste Bezeichner oder variable Text ist!
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
|
||||
textBox = painter.boundingRect(QRect(), Qt::AlignLeft, tr("Center point:\n%1\n\nTime:\n%2\n\nExercise:\n%3")
|
||||
.arg(m_trainingName,
|
||||
ui->situationWidget->currentDTGTime(),
|
||||
ui->situationWidget->centerPointString()));
|
||||
|
||||
// TextBlock fängt an: Notwendige Breite von rechts und 15 mm + 1 Zeilenhöhe (=1/8 der Textboxhöhe) von oben.
|
||||
// Die Zeilenhöhe ist notwendig weil drawText(QPoint, QString) den QPoint auf die Baseline setzt!
|
||||
QPointF textBlockBegin = QPointF(painter.viewport().width() - textBox.width(), 15 * mmH + 0.125 * textBox.height());
|
||||
|
||||
// Die Textbox hat 8 Zeilen, also ist der Faktor pro Zeile 1/8 = 0.125
|
||||
// Übung
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
|
||||
painter.drawText(textBlockBegin, tr("Exercise:"));
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.125 * textBox.height()), m_trainingName);
|
||||
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.375 * textBox.height()), tr("Time:"));
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.500 * textBox.height()), ui->situationWidget->currentDTGTime());
|
||||
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Bold, false));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.750 * textBox.height()), tr("Center point:"));
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 14, QFont::Normal, false));
|
||||
painter.drawText(textBlockBegin + QPointF(0, 0.875 * textBox.height()), ui->situationWidget->centerPointString());
|
||||
|
||||
// Das Bild soll formatfüllend angezeigt werden, das Rechteck muss 15mm "flacher" sein, da es erst ab 15mm gedruckt werden soll.
|
||||
// Ausserdem müssen in der Breite die Textboxbreite und 3mm Luft dazwischen abgezogen werden.
|
||||
QSizeF size = image.size();
|
||||
rect.adjust(0, 0, -textBox.width() - 3 * mmW, -15 * mmH);
|
||||
size.scale(rect.size(), Qt::KeepAspectRatio);
|
||||
|
||||
// Und ab 15mm von oben drucken:
|
||||
QRectF imgrect = QRectF(QPointF(0 * mmW, 15 * mmH), size);
|
||||
painter.drawImage(imgrect, image);
|
||||
|
||||
// Untere linke Ecke des Bildes
|
||||
underImage = imgrect.bottomLeft();
|
||||
}
|
||||
|
||||
painter.setFont(QFont(QStringLiteral("Arial"), 12));
|
||||
// String für Breite und Höhe erstellen
|
||||
const QRectF extent = ui->situationWidget->extentMgrs();
|
||||
QString areasize = tr("Width: %1m, Height: %2m").arg(extent.width()).arg(extent.height());
|
||||
// Die Größe herausfinden
|
||||
textBox = painter.boundingRect(QRect(), Qt::AlignLeft & Qt::TextSingleLine, areasize);
|
||||
// Einen Dot vergrößern (siehe QRect: Die Rahmenpixel unten und rechts sind nicht Teil der Rechteckgröße)
|
||||
textBox.adjust(0, 0, 1, 1);
|
||||
// An die richtige Stelle bugsieren
|
||||
textBox.moveBottomLeft(underImage);
|
||||
// Und mit weiß und 50% Deckkraft vollmalen.
|
||||
painter.fillRect(textBox, QColor(255, 255, 255, 128));
|
||||
//Dann den Text drüberlegen
|
||||
painter.drawText(underImage, areasize);
|
||||
|
||||
painter.end();
|
||||
}
|
||||
else if (ui->stackedWidget->currentWidget() == ui->pdfWidget)
|
||||
{
|
||||
QPrinter printer;
|
||||
QPrintDialog *dialog = new QPrintDialog(&printer, this);
|
||||
dialog->setWindowTitle(tr("Print Document"));
|
||||
if (dialog->exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
QVector<QImage> images = ui->pdfWidget->getPrintableImages(printer.resolution());
|
||||
int lastItem = images.size() - 1;
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(&printer);
|
||||
for (int i = 0; i < images.size(); ++i)
|
||||
{
|
||||
QRect rect = painter.viewport();
|
||||
QSize size = images.at(i).size();
|
||||
size.scale(rect.size(), Qt::KeepAspectRatio);
|
||||
painter.setViewport(rect.x(), rect.y(),
|
||||
size.width(), size.height());
|
||||
painter.setWindow(images.at(i).rect());
|
||||
painter.drawImage(0, 0, images.at(i));
|
||||
if (i != lastItem)
|
||||
printer.newPage();
|
||||
}
|
||||
painter.end();
|
||||
}
|
||||
else if (ui->stackedWidget->currentWidget() == ui->htmlWidget)
|
||||
{
|
||||
QPrinter printer;
|
||||
QPrintDialog *dialog = new QPrintDialog(&printer, this);
|
||||
dialog->setWindowTitle(tr("Print Document"));
|
||||
if (dialog->exec() != QDialog::Accepted)
|
||||
return;
|
||||
ui->htmlWidget->print(&printer);
|
||||
}
|
||||
else // Audio/Video-Widget
|
||||
{
|
||||
}
|
||||
}
|
||||
else // nur HTML sichtbar...
|
||||
{
|
||||
QPrinter printer;
|
||||
QPrintDialog *dialog = new QPrintDialog(&printer, this);
|
||||
dialog->setWindowTitle(tr("Print Document"));
|
||||
if (dialog->exec() != QDialog::Accepted)
|
||||
return;
|
||||
ui->htmlWidget->print(&printer);
|
||||
}
|
||||
}
|
||||
|
||||
void ThpViewer::onBack()
|
||||
{
|
||||
ui->audioWidget->stop();
|
||||
ui->videoWidget->stop();
|
||||
ui->situationWidget->stop();
|
||||
|
||||
ui->audioWidget->hide();
|
||||
ui->videoWidget->hide();
|
||||
if (ui->stackedWidget->currentWidget() == ui->htmlWidget &&
|
||||
ui->stackedWidget->isVisible())
|
||||
ui->htmlWidget->back();
|
||||
ui->stackedWidget->show();
|
||||
ui->stackedWidget->setCurrentWidget(ui->htmlWidget);
|
||||
onUrlChanged(ui->htmlWidget->url());
|
||||
}
|
||||
|
||||
void ThpViewer::onHome()
|
||||
{
|
||||
ui->htmlWidget->show();
|
||||
onLinkClicked(m_homeLink);
|
||||
}
|
||||
|
||||
void ThpViewer::onFullScreen()
|
||||
{
|
||||
setWindowState(windowState() ^ Qt::WindowFullScreen);
|
||||
}
|
||||
|
||||
void ThpViewer::onUrlChanged(const QUrl &url)
|
||||
{
|
||||
ui->backButton->setEnabled(url != m_homeLink);
|
||||
}
|
||||
|
||||
} // namespace NGL
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Main thp viewer widget
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QUrl>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class thpViewer;
|
||||
}
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class ThpViewer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThpViewer(const QUrl &url, QWidget *parent = nullptr);
|
||||
~ThpViewer();
|
||||
|
||||
bool init();
|
||||
void center();
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
protected:
|
||||
QHash<QString, QUrl> getCombinedPlaybackDetails(const QUrl &url) const;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onLinkClicked(const QUrl &url);
|
||||
void onZoomChanged();
|
||||
void onBack();
|
||||
void onHome();
|
||||
void onHelp();
|
||||
void onPrint();
|
||||
void onFullScreen();
|
||||
void onTitleChanged(const QString &title);
|
||||
void onUrlChanged(const QUrl &url);
|
||||
public Q_SLOTS:
|
||||
void onNewThp(const QString &index);
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
protected:
|
||||
Ui::thpViewer *ui;
|
||||
double m_scaleFactor;
|
||||
QUrl m_homeLink;
|
||||
QString m_homePath;
|
||||
QString m_trainingName;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace NGL
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <WINVER.H>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @THP_VERSION_INFO@
|
||||
PRODUCTVERSION @THP_VERSION_INFO@
|
||||
FILEFLAGSMASK 0x0L
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040704b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Rheinmetall Electronics GmbH"
|
||||
VALUE "FileDescription", "Take Home Package Viewer"
|
||||
VALUE "FileVersion", "@THP_VERSION_INFO@"
|
||||
VALUE "InternalName", "THP"
|
||||
VALUE "LegalCopyright", "Copyright © 2018 Rheinmetall Electronics GmbH. Alle Rechte vorbehalten"
|
||||
VALUE "OriginalFilename", "thp_viewer.exe"
|
||||
VALUE "ProductName", "Take Home Package Viewer (THP)"
|
||||
VALUE "ProductVersion", "@THP_VERSION_INFO@"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x407, 1200
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>thpViewer</class>
|
||||
<widget class="QWidget" name="thpViewer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>793</width>
|
||||
<height>675</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>793</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">MainWindow</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="backButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-previous.png</normaloff>:icons/16x16/go-previous.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fullScreenButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/view-fullscreen.png</normaloff>:icons/16x16/view-fullscreen.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F11</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="homeButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-home.png</normaloff>:icons/16x16/go-home.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="mainLabel">
|
||||
<property name="text">
|
||||
<string notr="true">THP-Viewer</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QToolButton" name="printButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/document-print.png</normaloff>:icons/16x16/document-print.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="helpButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/system-help.png</normaloff>:icons/16x16/system-help.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="closeButton">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/dialog-close.png</normaloff>:icons/16x16/dialog-close.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QSplitter" name="splitter_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="THP::AudioVideoWidget" name="videoWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<widget class="THP::HtmlWidget" name="htmlWidget"/>
|
||||
<widget class="THP::BuildingWidget" name="buildingWidget"/>
|
||||
<widget class="THP::PdfWidget" name="pdfWidget"/>
|
||||
<widget class="THP::SituationWidget" name="situationWidget"/>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="THP::AudioVideoWidget" name="audioWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>THP::AudioVideoWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>thpwidgets/thp_audio_video_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>THP::PdfWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>thpwidgets/thp_pdf_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>THP::HtmlWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>thpwidgets/thp_html_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>THP::SituationWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>thpwidgets/thp_situation_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>THP::BuildingWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>thpwidgets/thp_building_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,629 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_audio_video_widget.h"
|
||||
#include "thp_audio_video_widget_p.h"
|
||||
#include "ui_thp_audio_video_widget.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QMutex>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QGuiApplication>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vlc/libvlc_version.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
static const float s_speedArray[] =
|
||||
{
|
||||
1. / 8.,
|
||||
1. / 4.,
|
||||
1. / 2.,
|
||||
1.,
|
||||
2.,
|
||||
4.,
|
||||
8.
|
||||
};
|
||||
|
||||
/**
|
||||
* AudioVideoWidget::Private
|
||||
*/
|
||||
AudioVideoWidget::Private::Private(QFrame *parent)
|
||||
: m_vlcinstance(nullptr)
|
||||
, m_mPlayer(nullptr)
|
||||
, m_mListPlayer(nullptr)
|
||||
, m_mediaList(nullptr)
|
||||
, currentSpeedIdx(3)
|
||||
, m_parent(parent)
|
||||
, m_timer(new QTimer)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("THP.AudioVideoWidget"))
|
||||
{
|
||||
init();
|
||||
|
||||
connect(ui->btnSlower, &QToolButton::clicked, this, &AudioVideoWidget::Private::onSlower);
|
||||
connect(ui->btnFaster, &QToolButton::clicked, this, &AudioVideoWidget::Private::onFaster);
|
||||
connect(ui->btn100pct, &QToolButton::clicked, this, &AudioVideoWidget::Private::on100pct);
|
||||
connect(ui->btnPlay, &QToolButton::clicked, this, &AudioVideoWidget::Private::onPlay);
|
||||
connect(ui->btnStop, &QToolButton::clicked, this, &AudioVideoWidget::Private::onStop);
|
||||
connect(ui->sldPosition, &QSlider::sliderMoved, this, &AudioVideoWidget::Private::onPositionChanged);
|
||||
connect(ui->sldVolume, &QSlider::sliderMoved, this, &AudioVideoWidget::Private::onVolumeChanged);
|
||||
connect(m_timer, &QTimer::timeout, this, &AudioVideoWidget::Private::onUpdateGUI);
|
||||
|
||||
m_initThread = new AudioVideoInitThread(this);
|
||||
connect(m_initThread, &AudioVideoInitThread::finished, this, &AudioVideoWidget::Private::onVLCInstanceInitializd);
|
||||
m_initThread->start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
AudioVideoWidget::Private::~Private()
|
||||
{
|
||||
uninitVLCPlayer();
|
||||
uninitVLCInstance();
|
||||
delete ui;
|
||||
delete m_timer;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::init()
|
||||
{
|
||||
if (!m_parent)
|
||||
return false;
|
||||
ui = new Ui::audioVideoWidget();
|
||||
ui->setupUi(m_parent);
|
||||
|
||||
QPixmap pm(10, 10);
|
||||
pm.fill(Qt::black);
|
||||
ui->outputWidget->setPixmap(pm);
|
||||
ui->outputWidget->setScaledContents(true);
|
||||
|
||||
ui->sldPosition->setMaximum(1000);
|
||||
ui->sldVolume->setMaximum(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onVLCInstanceInitializd()
|
||||
{
|
||||
m_initThread->deleteLater();
|
||||
m_initThread = nullptr;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::setAV(bool isAudio)
|
||||
{
|
||||
if (isAudio)
|
||||
{
|
||||
delete ui->btn100pct;
|
||||
delete ui->btnFaster;
|
||||
delete ui->btnSlower;
|
||||
delete ui->outputWidget;
|
||||
ui->outputWidget = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// delete ui->verticalSpacer; ui->verticalSpacer = 0;
|
||||
delete ui->lblAudio;
|
||||
}
|
||||
}
|
||||
|
||||
static QMutex *serializeVLCInit()
|
||||
{
|
||||
static QMutex s_serializeVLCInit;
|
||||
return &s_serializeVLCInit;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::initVLCInstance(bool bInInitThread)
|
||||
{
|
||||
QMutexLocker l(serializeVLCInit());
|
||||
|
||||
if (!bInInitThread && m_initThread != nullptr)
|
||||
{
|
||||
QLabel myLabel;
|
||||
myLabel.setWindowTitle(tr("Loading VLC player..."));
|
||||
myLabel.setText(tr("Waiting until VLC player is loaded"));
|
||||
QRect r = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
myLabel.show();
|
||||
myLabel.move(r.width() / 2 - myLabel.width() / 2, r.height() / 2 - myLabel.height() / 2);
|
||||
myLabel.setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde.ico")));
|
||||
|
||||
while (m_initThread)
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
if (m_vlcinstance != nullptr)
|
||||
return true;
|
||||
|
||||
//preparation of the vlc command
|
||||
const char *vlc_argv[20];
|
||||
int iCount = 0;
|
||||
vlc_argv[iCount++] = "-I";
|
||||
vlc_argv[iCount++] = "dummy"; // Don't use any interface
|
||||
// vlc_argv[iCount++] = "--ignore-config"; // Don't use VLC's config
|
||||
#ifdef LTS_DEBUG
|
||||
vlc_argv[iCount++] = "--extraintf=logger"; // log anything
|
||||
vlc_argv[iCount++] = "--verbose=2"; // be much more verbose then normal for debugging purpose
|
||||
#else
|
||||
vlc_argv[iCount++] = "--quiet";
|
||||
#endif
|
||||
if (bInInitThread)
|
||||
vlc_argv[iCount++] = "--no-media-library";
|
||||
vlc_argv[iCount++] = "--";
|
||||
vlc_argv[iCount] = nullptr;
|
||||
|
||||
//Initialize an instance of vlc
|
||||
//create a new libvlc instance
|
||||
m_vlcinstance = libvlc_new(iCount, vlc_argv); //tricky calculation of the char space used
|
||||
if (!m_vlcinstance)
|
||||
ERROR_LOG(m_logger) << "Error initializing libVLC - unable to play audio or video";
|
||||
|
||||
return (m_vlcinstance != nullptr);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::uninitVLCInstance()
|
||||
{
|
||||
QMutexLocker l(serializeVLCInit());
|
||||
|
||||
if (!uninitVLCPlayer())
|
||||
return false;
|
||||
|
||||
if (m_vlcinstance)
|
||||
{
|
||||
libvlc_release(m_vlcinstance);
|
||||
m_vlcinstance = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::initVLCPlayer()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Initializing libVLC";
|
||||
if (m_mPlayer)
|
||||
{
|
||||
if (!ui)
|
||||
return false;
|
||||
ui->sldVolume->setValue(libvlc_audio_get_volume(m_mPlayer));
|
||||
return true;
|
||||
}
|
||||
|
||||
initVLCInstance();
|
||||
|
||||
//Initialize an instance of vlc
|
||||
//Create a media player playing environement
|
||||
m_mPlayer = libvlc_media_player_new(m_vlcinstance);
|
||||
m_mListPlayer = libvlc_media_list_player_new(m_vlcinstance);
|
||||
m_mediaList = libvlc_media_list_new(m_vlcinstance);
|
||||
|
||||
libvlc_media_list_player_set_media_player(m_mListPlayer, m_mPlayer);
|
||||
libvlc_media_list_player_set_media_list(m_mListPlayer, m_mediaList);
|
||||
|
||||
ui->sldVolume->setValue(libvlc_audio_get_volume(m_mPlayer));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::uninitVLCPlayer()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Uninitializing libVLC";
|
||||
|
||||
if (m_mListPlayer)
|
||||
{
|
||||
/* Stop playing */
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
/* Free the media_player */
|
||||
libvlc_media_list_player_release(m_mListPlayer);
|
||||
m_mListPlayer = nullptr;
|
||||
}
|
||||
if (m_mediaList)
|
||||
{
|
||||
clearMediaList();
|
||||
libvlc_media_list_release(m_mediaList);
|
||||
m_mediaList = nullptr;
|
||||
}
|
||||
if (m_mPlayer)
|
||||
{
|
||||
/* Stop playing */
|
||||
libvlc_media_player_stop(m_mPlayer);
|
||||
/* Free the media_player */
|
||||
libvlc_media_player_release(m_mPlayer);
|
||||
|
||||
m_mPlayer = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::clearMediaList()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Clearing current playlist";
|
||||
|
||||
if (!m_mediaList)
|
||||
return;
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
for (int i = cnt - 1; i >= 0; --i)
|
||||
libvlc_media_list_remove_index(m_mediaList, i);
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::playVLC(const QUrl &url)
|
||||
{
|
||||
if (!ui)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Try to play " << url.toString();
|
||||
|
||||
const QString path = url.toLocalFile();
|
||||
if (path.isEmpty())
|
||||
return false;
|
||||
|
||||
clearMediaList();
|
||||
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
QFileInfo fi(path);
|
||||
DEBUG_LOG(m_logger) << "path: " << path << " isFile: " << fi.isFile();
|
||||
if (fi.isFile() && path.endsWith(QLatin1String(".pls")))
|
||||
{
|
||||
// pls parsing scheint nicht mehr richtig zu funktionieren - selbst machen
|
||||
DEBUG_LOG(m_logger) << "Parse Playlist";
|
||||
QFile f(path);
|
||||
if (f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Parse Playlist2 " << f.canReadLine();
|
||||
QMap<int, QByteArray> fileMap;
|
||||
QByteArray baAll = f.readAll();
|
||||
const QList<QByteArray> lines = baAll.split('\n');
|
||||
for (const QByteArray &line : lines)
|
||||
{
|
||||
QByteArray ba = line.trimmed();
|
||||
DEBUG_LOG(m_logger) << "ba: " << ba;
|
||||
if (!ba.startsWith("File "))
|
||||
continue;
|
||||
ba = ba.mid(qstrlen("File "));
|
||||
int idx = ba.indexOf('=');
|
||||
DEBUG_LOG(m_logger) << "idx: " << idx;
|
||||
if (idx < 0)
|
||||
continue;
|
||||
bool bOk;
|
||||
int id = ba.left(idx).toInt(&bOk);
|
||||
DEBUG_LOG(m_logger) << "id: " << id << " bOk: " << bOk << " str: " << ba.left(idx);
|
||||
if (!bOk)
|
||||
continue;
|
||||
QByteArray filename = ba.mid(idx + 1);
|
||||
DEBUG_LOG(m_logger) << "filename: " << filename;
|
||||
fileMap.insertMulti(id, fi.absolutePath().toLocal8Bit() + '/' + filename);
|
||||
}
|
||||
for (const QByteArray &fn : fileMap)
|
||||
{
|
||||
const QByteArray pNative = QDir::toNativeSeparators(QString::fromLocal8Bit(fn)).toLocal8Bit();
|
||||
DEBUG_LOG(m_logger) << "pNative: " << pNative;
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to " << pNative;
|
||||
return false;
|
||||
}
|
||||
//add option to disable hardware acceleration
|
||||
libvlc_media_add_option(media, ":avcodec-hw=none");
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
#if LIBVLC_VERSION_MAJOR > 2
|
||||
libvlc_media_parse_with_options(media, libvlc_media_parse_local, 0);
|
||||
#else
|
||||
libvlc_media_parse(media);
|
||||
#endif
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fi.isFile())
|
||||
{
|
||||
const QByteArray pNative = QDir::toNativeSeparators(path).toLocal8Bit();
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to '" << pNative << "'";
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
else if (fi.isDir())
|
||||
{
|
||||
QDirIterator dirIt(fi.absoluteFilePath());
|
||||
while (dirIt.hasNext())
|
||||
{
|
||||
const QString fn = dirIt.next();
|
||||
fi.setFile(fn);
|
||||
if (!fi.isFile())
|
||||
continue;
|
||||
const QByteArray pNative = QDir::toNativeSeparators(fn).toLocal8Bit();
|
||||
libvlc_media_t *media = libvlc_media_new_path(m_vlcinstance, pNative.data());
|
||||
if (!media)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error setting media to " << pNative;
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_add_media(m_mediaList, media);
|
||||
#if LIBVLC_VERSION_MAJOR > 2
|
||||
libvlc_media_parse_with_options(media, libvlc_media_parse_local, 0);
|
||||
#else
|
||||
libvlc_media_parse(media);
|
||||
#endif
|
||||
libvlc_media_release(media); // libvlc_media_new_location(), ref-counting!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Unknown media given: " << path;
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
return false;
|
||||
}
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
|
||||
if (ui->outputWidget)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
libvlc_media_player_set_hwnd(m_mPlayer, (HWND)ui->outputWidget->winId());
|
||||
#elif defined(Q_OS_MAC)
|
||||
libvlc_media_player_set_agl(m_mPlayer, ui->outputWidget->winId()) ;
|
||||
#else //Linux
|
||||
libvlc_media_player_set_xwindow(m_mPlayer, ui->outputWidget->winId());
|
||||
#endif
|
||||
}
|
||||
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
ui->btnPlay->setEnabled(true);
|
||||
ui->sldPosition->setEnabled(false);
|
||||
ui->btnStop->setEnabled(true);
|
||||
|
||||
currentSpeedIdx = 3;
|
||||
|
||||
QTimer::singleShot(0, this, &AudioVideoWidget::Private::onPlay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::Private::stopVLC()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Stop playing";
|
||||
|
||||
QTimer::singleShot(0, this, &AudioVideoWidget::Private::onStop);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::setRate()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Setting speed to " << s_speedArray[currentSpeedIdx];
|
||||
|
||||
libvlc_state_t state = getState();
|
||||
if (state == libvlc_Playing || state == libvlc_Paused)
|
||||
libvlc_media_player_set_rate(m_mPlayer, s_speedArray[currentSpeedIdx]);
|
||||
}
|
||||
|
||||
libvlc_state_t AudioVideoWidget::Private::getState() const
|
||||
{
|
||||
libvlc_state_t s = libvlc_media_list_player_get_state(m_mListPlayer);
|
||||
static libvlc_state_t lastState = libvlc_NothingSpecial;
|
||||
if (s == lastState)
|
||||
return s;
|
||||
lastState = s;
|
||||
if (s == libvlc_Error)
|
||||
ERROR_LOG(m_logger) << "libVLC error: " << libvlc_errmsg();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void AudioVideoWidget::Private::onSlower()
|
||||
{
|
||||
if (currentSpeedIdx == 0)
|
||||
return;
|
||||
--currentSpeedIdx;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onFaster()
|
||||
{
|
||||
if (currentSpeedIdx == 6)
|
||||
return;
|
||||
++currentSpeedIdx;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::on100pct()
|
||||
{
|
||||
currentSpeedIdx = 3;
|
||||
setRate();
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onPlay()
|
||||
{
|
||||
if (libvlc_media_list_player_is_playing(m_mListPlayer))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Pause playing";
|
||||
libvlc_media_list_player_pause(m_mListPlayer);
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_timer->stop();
|
||||
onUpdateGUIWithState(libvlc_Paused);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Start playing";
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-pause.png")));
|
||||
ui->sldPosition->setEnabled(true);
|
||||
|
||||
libvlc_media_list_player_play(m_mListPlayer);
|
||||
setRate();
|
||||
|
||||
m_timer->start(100);
|
||||
onUpdateGUIWithState(libvlc_Playing);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onStop()
|
||||
{
|
||||
if (!m_mListPlayer)
|
||||
return;
|
||||
|
||||
libvlc_state_t state = getState();
|
||||
|
||||
if (state == libvlc_Stopped)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Stop playing";
|
||||
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onPositionChanged(int newPosition)
|
||||
{
|
||||
libvlc_state_t state = getState();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Slider changed - going to new position";
|
||||
|
||||
if (state != libvlc_Playing && state != libvlc_Paused)
|
||||
return;
|
||||
|
||||
// Position geht von 0..1, Slider hat 1000 Steps
|
||||
libvlc_media_player_set_position(m_mPlayer, newPosition / 1000.);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onVolumeChanged(int newVol)
|
||||
{
|
||||
libvlc_audio_set_volume(m_mPlayer, newVol);
|
||||
onUpdateGUI();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onUpdateGUI()
|
||||
{
|
||||
onUpdateGUIWithState(libvlc_NothingSpecial);
|
||||
}
|
||||
|
||||
void AudioVideoWidget::Private::onUpdateGUIWithState(libvlc_state_t overwrite_state)
|
||||
{
|
||||
libvlc_state_t state = overwrite_state;
|
||||
if (state == libvlc_NothingSpecial)
|
||||
state = getState();
|
||||
DEBUG_LOG(m_logger) << "onUpdateGUI for state " << state;
|
||||
|
||||
if (state == libvlc_Playing || state == libvlc_Paused)
|
||||
{
|
||||
double maxTime = libvlc_media_player_get_length(m_mPlayer) / 1000.;
|
||||
if (maxTime > 0.1)
|
||||
{
|
||||
libvlc_media_list_lock(m_mediaList);
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
for (int i = cnt - 1; i >= 0; --i)
|
||||
{
|
||||
libvlc_media_t *media = libvlc_media_list_item_at_index(m_mediaList, i);
|
||||
DEBUG_LOG(m_logger) << "Duration: " << libvlc_media_get_duration(media);
|
||||
libvlc_media_release(media);
|
||||
}
|
||||
libvlc_media_list_unlock(m_mediaList);
|
||||
|
||||
}
|
||||
double curTime = libvlc_media_player_get_time(m_mPlayer) / 1000.;
|
||||
auto curPos = libvlc_media_player_get_position(m_mPlayer);
|
||||
// Slider ist in 1000 Schritte eingeteilt
|
||||
ui->sldPosition->setValue(qRound(curPos * 1000));
|
||||
|
||||
const int minutesCur = floor(curTime / 60.);
|
||||
const int secondsCur = curTime - 60 * minutesCur;
|
||||
const int minutesAbs = floor(maxTime / 60.);
|
||||
const int secondsAbs = maxTime - 60 * minutesAbs;
|
||||
char timeStr[64];
|
||||
snprintf(timeStr, sizeof(timeStr), "%02d:%02d / %02d:%02d", minutesCur, secondsCur, minutesAbs, secondsAbs);
|
||||
ui->lblPosition->setText(QString::fromLatin1(timeStr));
|
||||
|
||||
}
|
||||
else if (state == libvlc_Stopped || state == libvlc_Ended)
|
||||
{
|
||||
// wir können nicht onStop() aufrufen -> rekursion!
|
||||
bool bStop = true;
|
||||
if (state == libvlc_Ended)
|
||||
{
|
||||
// Timer und VLC *nicht* stoppen da der aktuelle State ggf. genau zwischen den einzelnen
|
||||
// Video-Schnipseln einer Playlist abgefragt wurde
|
||||
// --> prüfen, ob es das letzte Video der Playlist war
|
||||
libvlc_media_t *media = libvlc_media_player_get_media(m_mPlayer);
|
||||
if (media != nullptr)
|
||||
{
|
||||
const int cnt = libvlc_media_list_count(m_mediaList);
|
||||
if (cnt > 0)
|
||||
{
|
||||
libvlc_media_t *media2 = libvlc_media_list_item_at_index(m_mediaList, cnt - 1);
|
||||
bStop = (media2 == media);
|
||||
libvlc_media_release(media2);
|
||||
}
|
||||
libvlc_media_release(media);
|
||||
}
|
||||
if (bStop)
|
||||
libvlc_media_list_player_stop(m_mListPlayer);
|
||||
}
|
||||
if (bStop)
|
||||
{
|
||||
ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
ui->sldPosition->setEnabled(false);
|
||||
m_timer->stop();
|
||||
ui->sldPosition->setValue(0);
|
||||
ui->lblPosition->setText(QLatin1String("--:-- / --:--"));
|
||||
}
|
||||
}
|
||||
|
||||
QString speedStr = QStringLiteral("%1x").arg(s_speedArray[currentSpeedIdx], 4, 'f', 2);
|
||||
ui->lblSpeed->setText(speedStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* AudioVideoInitThread
|
||||
*/
|
||||
AudioVideoInitThread::AudioVideoInitThread(AudioVideoWidget::Private *p)
|
||||
: m_private(p)
|
||||
{}
|
||||
|
||||
void AudioVideoInitThread::run()
|
||||
{
|
||||
m_private->initVLCInstance(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* AudioVideoWidget
|
||||
*/
|
||||
AudioVideoWidget::AudioVideoWidget(QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, d(new Private(this))
|
||||
{}
|
||||
|
||||
AudioVideoWidget::~AudioVideoWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::play(const QUrl &file)
|
||||
{
|
||||
d->initVLCPlayer();
|
||||
return d->playVLC(file);
|
||||
}
|
||||
|
||||
bool AudioVideoWidget::stop()
|
||||
{
|
||||
return d->stopVLC();
|
||||
}
|
||||
|
||||
void AudioVideoWidget::setAV(bool isAudio)
|
||||
{
|
||||
d->setAV(isAudio);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class AudioVideoWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioVideoWidget(QWidget *parent = nullptr);
|
||||
~AudioVideoWidget();
|
||||
|
||||
bool play(const QUrl &file);
|
||||
bool stop();
|
||||
void setAV(bool isAudio = false);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
friend class AudioVideoInitThread;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>audioVideoWidget</class>
|
||||
<widget class="QFrame" name="audioVideoWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>911</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="outputWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAudio">
|
||||
<property name="text">
|
||||
<string>Audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldPosition">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPosition">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">55:55 / 55:55</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-playback-start.png</normaloff>:icons/16x16/media-playback-start.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-playback-stop.png</normaloff>:icons/16x16/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnSlower">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-slower.png</normaloff>:icons/16x16/media-play-slower.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn100pct">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-normal.png</normaloff>:icons/16x16/media-play-normal.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFaster">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../Z/src/nglwidgets/nglresources.qrc">
|
||||
<normaloff>:icons/16x16/media-play-faster.png</normaloff>:icons/16x16/media-play-faster.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSpeed">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">100 %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Volume:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldVolume">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../Z/src/nglwidgets/nglresources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle Audio/Video output for thp through libvlc, private data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// no ssize_t with msdn...
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#include <vlc/vlc.h>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "thp_audio_video_widget.h"
|
||||
|
||||
class QUrl;
|
||||
class QFrame;
|
||||
class QTimer;
|
||||
namespace Ui
|
||||
{
|
||||
class audioVideoWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class AudioVideoInitThread;
|
||||
class AudioVideoWidget::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Private(QFrame *parent);
|
||||
~Private();
|
||||
|
||||
bool initVLCInstance(bool bInInitThread = false);
|
||||
bool uninitVLCInstance();
|
||||
bool initVLCPlayer();
|
||||
bool uninitVLCPlayer();
|
||||
bool playVLC(const QUrl &url);
|
||||
bool stopVLC();
|
||||
void setAV(bool isAudio);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onSlower();
|
||||
void onFaster();
|
||||
void on100pct();
|
||||
void onPlay();
|
||||
void onStop();
|
||||
void onPositionChanged(int);
|
||||
void onVolumeChanged(int);
|
||||
void onUpdateGUI();
|
||||
void onVLCInstanceInitializd();
|
||||
|
||||
protected:
|
||||
void clearMediaList();
|
||||
void playVLCInternal();
|
||||
void onUpdateGUIWithState(libvlc_state_t overwrite_state);
|
||||
bool init();
|
||||
void setRate();
|
||||
libvlc_state_t getState() const;
|
||||
|
||||
libvlc_instance_t *m_vlcinstance;
|
||||
libvlc_media_player_t *m_mPlayer;
|
||||
libvlc_media_list_player_t *m_mListPlayer;
|
||||
libvlc_media_list_t *m_mediaList;
|
||||
|
||||
int currentSpeedIdx;
|
||||
|
||||
QFrame *m_parent;
|
||||
QTimer *m_timer;
|
||||
AudioVideoInitThread *m_initThread;
|
||||
|
||||
Ui::audioVideoWidget *ui;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
class AudioVideoInitThread final : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioVideoInitThread(AudioVideoWidget::Private *p);
|
||||
protected:
|
||||
void run() override;
|
||||
protected:
|
||||
AudioVideoWidget::Private *m_private;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for MeteoDataManagement - Meteo Data Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-10-05
|
||||
*/
|
||||
|
||||
#include "thp_building_settings.h"
|
||||
#include "ui_thp_building_settings.h"
|
||||
#include <Common/bdv_controller.h>
|
||||
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
static QVariant getSetting(const QString &key, const QVariant &def)
|
||||
{
|
||||
return LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("BgViewer"), key, def);
|
||||
}
|
||||
|
||||
static void setSetting(const QString &key, const QVariant &val)
|
||||
{
|
||||
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("BgViewer"), key, val);
|
||||
}
|
||||
|
||||
BgViewerSettingsView::BgViewerSettingsView(BuildingViewer::BgViewerController *pBgvController,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::BgViewerSettingsUI)
|
||||
, m_pBgvController(pBgvController)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->m_pCheckBoxGlobalIsoMode, &QCheckBox::clicked, this, &BgViewerSettingsView::onViewModeChanged);
|
||||
connect(m_ui->m_pCheckBoxUseDotsMode, &QCheckBox::clicked, this, &BgViewerSettingsView::onPlayerDisplayModeChanged);
|
||||
connect(m_ui->m_pSliderGlobalTransparency, &QSlider::valueChanged, this, &BgViewerSettingsView::onTransparencyChanged);
|
||||
connect(m_ui->m_pSliderPlayerSymbolSize, &QSlider::valueChanged, this, &BgViewerSettingsView::onSymbolSizeChanged);
|
||||
connect(m_ui->m_slider_SymbolFlashing, &QSlider::valueChanged, this, &BgViewerSettingsView::onSymbolFireEventFlashingChanged);
|
||||
connect(m_ui->m_slider_HitlineDuration, &QSlider::valueChanged, this, &BgViewerSettingsView::onHitLineDisplayLengthChanged);
|
||||
|
||||
resetValues();
|
||||
onSymbolFireEventFlashingChanged(m_ui->m_slider_HitlineDuration->value());
|
||||
onHitLineDisplayLengthChanged(m_ui->m_slider_SymbolFlashing->value());
|
||||
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &BgViewerSettingsView::accept);
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &BgViewerSettingsView::reject);
|
||||
}
|
||||
|
||||
|
||||
BgViewerSettingsView::~BgViewerSettingsView()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void BgViewerSettingsView::accept()
|
||||
{
|
||||
setSetting(QStringLiteral("GlobalTransparency"), m_ui->m_pSliderGlobalTransparency->value());
|
||||
setSetting(QStringLiteral("UseIsoMode"), m_ui->m_pCheckBoxGlobalIsoMode->isChecked());
|
||||
setSetting(QStringLiteral("UseDotsMode"), m_ui->m_pCheckBoxUseDotsMode->isChecked());
|
||||
setSetting(QStringLiteral("PlayerSymbolSize"), m_ui->m_pSliderPlayerSymbolSize->value());
|
||||
setSetting(QStringLiteral("maxHitlineDurationTime_s"), m_ui->m_slider_HitlineDuration->value());
|
||||
setSetting(QStringLiteral("GearFlashTime_s"), m_ui->m_slider_SymbolFlashing->value());
|
||||
setSetting(QStringLiteral("maxGearFlashTime_s"), m_ui->m_slider_SymbolFlashing->maximum());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::reject()
|
||||
{
|
||||
resetValues();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::resetValues()
|
||||
{
|
||||
m_ui->m_pSliderGlobalTransparency->setValue(getSetting(QStringLiteral("GlobalTransparency"), 75).toInt());
|
||||
m_ui->m_pCheckBoxGlobalIsoMode->setChecked(getSetting(QStringLiteral("UseIsoMode"), false).toBool());
|
||||
m_ui->m_pCheckBoxUseDotsMode->setChecked(getSetting(QStringLiteral("UseDotsMode"), false).toBool()) ;
|
||||
m_ui->m_pSliderPlayerSymbolSize->setValue(getSetting(QStringLiteral("PlayerSymbolSize"), 20).toInt());
|
||||
m_ui->m_slider_HitlineDuration->setValue(getSetting(QStringLiteral("maxHitlineDurationTime_s"), 10).toInt());
|
||||
m_ui->m_slider_SymbolFlashing->setValue(getSetting(QStringLiteral("GearFlashTime_s"), 10).toInt());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onViewModeChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalViewMode(m_ui->m_pCheckBoxGlobalIsoMode->isChecked());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onPlayerDisplayModeChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalDotsMode(m_ui->m_pCheckBoxUseDotsMode->isChecked());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onSymbolSizeChanged()
|
||||
{
|
||||
m_pBgvController->updatePlayerSymbols(m_ui->m_pSliderPlayerSymbolSize->value());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onTransparencyChanged()
|
||||
{
|
||||
m_pBgvController->excSetGlobalTransparency(m_ui->m_pSliderGlobalTransparency->value());
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onSymbolFireEventFlashingChanged(int val)
|
||||
{
|
||||
// only modified per config setting...
|
||||
m_ui->m_label_durationSymbolFlashing->setText(tr("%1 sec").arg(val));
|
||||
}
|
||||
|
||||
void BgViewerSettingsView::onHitLineDisplayLengthChanged(int val)
|
||||
{
|
||||
m_pBgvController->excSetHitlineDuration(val);
|
||||
m_ui->m_label_HitlineDuration->setText(tr("%1 sec").arg(val));
|
||||
}
|
||||
|
||||
} // namespace BuildingViewer
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for MeteoDataManagement - Meteo Data Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-10-05
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class BgViewerSettingsUI;
|
||||
}
|
||||
|
||||
namespace BuildingViewer
|
||||
{
|
||||
class BgViewerController;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class BgViewerSettingsView final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BgViewerSettingsView(BuildingViewer::BgViewerController *pBgvController,
|
||||
QWidget *parent = nullptr);
|
||||
~BgViewerSettingsView();
|
||||
|
||||
private slots:
|
||||
void onViewModeChanged();
|
||||
void onPlayerDisplayModeChanged();
|
||||
void onTransparencyChanged();
|
||||
void onSymbolSizeChanged();
|
||||
void onSymbolFireEventFlashingChanged(int val);
|
||||
void onHitLineDisplayLengthChanged(int val);
|
||||
|
||||
private:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
void resetValues();
|
||||
|
||||
Ui::BgViewerSettingsUI *m_ui;
|
||||
BuildingViewer::BgViewerController *m_pBgvController;
|
||||
};
|
||||
|
||||
} // namespace BuildingViewer
|
||||
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BgViewerSettingsUI</class>
|
||||
<widget class="QWidget" name="BgViewerSettingsUI">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">General Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="2">
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="m_pSliderGlobalTransparency">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>75</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="m_pCheckBoxGlobalIsoMode">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use orthographic view mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Player symbol size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="m_label_durationSymbolFlashing">
|
||||
<property name="text">
|
||||
<string>%1 sec</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="m_label_HitlineDuration">
|
||||
<property name="text">
|
||||
<string>%1 sec</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Symbol fire event flashing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSlider" name="m_pSliderPlayerSymbolSize">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>45</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Transparency value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Hit line display length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSlider" name="m_slider_HitlineDuration">
|
||||
<property name="maximum">
|
||||
<number>120</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="m_pCheckBoxUseDotsMode">
|
||||
<property name="text">
|
||||
<string>Use dots mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSlider" name="m_slider_SymbolFlashing">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>120</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle bulding display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_building_widget.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
#include "thp_building_settings.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
#include <BuildingViewer/Common/bdv_controller.h>
|
||||
#include <BuildingViewer/Common/bdv_plugin_provider.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsWidgets/lts_dialog_helper.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
using namespace SituationReplay;
|
||||
|
||||
BuildingWidget::BuildingWidget(QWidget *parent)
|
||||
: SituationBuildingBase("THP.BuildingWidget", parent)
|
||||
{
|
||||
QMenu *m = new QMenu(m_ui->btnFilter);
|
||||
m->addAction(tr("Global Settings"), this, &BuildingWidget::onGlobalSettings);
|
||||
m_ui->btnFilter->setMenu(m);
|
||||
}
|
||||
|
||||
BuildingWidget::~BuildingWidget()
|
||||
{
|
||||
delete m_bgvController;
|
||||
}
|
||||
|
||||
bool BuildingWidget::init(SituationReplay::MainHandlerSqlite *mhs, BuildingPluginProvider *pp, const QString &homePath)
|
||||
{
|
||||
if (!SituationBuildingBase::init(mhs))
|
||||
return false;
|
||||
m_replayHandler = mhs;
|
||||
m_pluginProvider = pp;
|
||||
|
||||
// parse json, create xml, init buildingviewer
|
||||
delete m_bgvController;
|
||||
m_bgvController = new BuildingViewer::BgViewerController(this);
|
||||
if (!m_bgvController->init(m_pluginProvider, true, homePath + QStringLiteral("/BuildingModels/")))
|
||||
return false;
|
||||
|
||||
auto w = m_bgvController->getBgViewerWidget();
|
||||
w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildingWidget::showSituationInternal()
|
||||
{
|
||||
m_bgvController->excRestoreViewState(m_attributes[QStringLiteral("arrBuildingStates")]);
|
||||
if (!SituationBuildingBase::showSituationInternal())
|
||||
return false;
|
||||
onInitDone();
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildingWidget::emitPartitionTimeChanged(qint64 curTime)
|
||||
{
|
||||
m_pluginProvider->emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void BuildingWidget::onGlobalSettings()
|
||||
{
|
||||
if (!m_globalSettingsDialog)
|
||||
m_globalSettingsDialog = new BgViewerSettingsView(m_bgvController, this);
|
||||
m_globalSettingsDialog->show();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle bulding display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
#include "thp_situation_building_base.h"
|
||||
|
||||
namespace BuildingViewer
|
||||
{
|
||||
class BgViewerController;
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
class BuildingWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class BuildingPluginProvider;
|
||||
class BgViewerSettingsView;
|
||||
class BuildingWidget : public SituationBuildingBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BuildingWidget(QWidget *parent = nullptr);
|
||||
~BuildingWidget();
|
||||
|
||||
bool init(SituationReplay::MainHandlerSqlite *mhs,
|
||||
BuildingPluginProvider *pp,
|
||||
const QString &homePath);
|
||||
|
||||
protected:
|
||||
bool showSituationInternal() override;
|
||||
void emitPartitionTimeChanged(qint64 curTime) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onGlobalSettings();
|
||||
virtual void applyCurentFilter(const SituationReplay::FilterInformation &) override {}
|
||||
virtual void applyNewOverlay(int) override {}
|
||||
virtual void removeOverlay(int) override {}
|
||||
private:
|
||||
BuildingPluginProvider *m_pluginProvider = nullptr;
|
||||
BuildingViewer::BgViewerController *m_bgvController = nullptr;
|
||||
BgViewerSettingsView *m_globalSettingsDialog = nullptr;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle HTML output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_html_widget.h"
|
||||
#include "ui_thp_html_widget.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QWebEnginePage>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
class MyQWebEnginePage : public QWebEnginePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyQWebEnginePage(NGL::INGLLogger &logger, QObject *parent = nullptr)
|
||||
: QWebEnginePage(parent)
|
||||
, m_logger(logger)
|
||||
{}
|
||||
MyQWebEnginePage(NGL::INGLLogger &logger, QWebEngineProfile *profile, QObject *parent = nullptr)
|
||||
: QWebEnginePage(profile, parent)
|
||||
, m_logger(logger)
|
||||
{}
|
||||
|
||||
bool needsToBeOpenedExternally(const QUrl &url)
|
||||
{
|
||||
const QString lpath = url.toString();
|
||||
const QStringRef ext = lpath.splitRef(QLatin1Char('.')).last();
|
||||
const QStringRef ext2Chars = ext.left(2);
|
||||
if (ext == QLatin1String("html") &&
|
||||
lpath.midRef(lpath.lastIndexOf(QLatin1Char('/')) + 1).startsWith(QLatin1String("combined_")))
|
||||
return true;
|
||||
// PDF
|
||||
if (ext == QLatin1String("pdf"))
|
||||
return true;
|
||||
// A/V playlist
|
||||
if (ext == QLatin1String("pls"))
|
||||
return true;
|
||||
// Situation
|
||||
if (ext == QLatin1String("json"))
|
||||
return true;
|
||||
// Word/Excel/PowerPoint
|
||||
if (ext2Chars == QLatin1String("do") ||
|
||||
ext2Chars == QLatin1String("xl") ||
|
||||
ext2Chars == QLatin1String("pp"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool acceptNavigationRequest(const QUrl &url,
|
||||
QWebEnginePage::NavigationType type,
|
||||
bool isMainFrame) override
|
||||
{
|
||||
Q_UNUSED(isMainFrame)
|
||||
if (type == QWebEnginePage::NavigationTypeLinkClicked)
|
||||
{
|
||||
if (needsToBeOpenedExternally(url))
|
||||
{
|
||||
emit linkClicked(url);
|
||||
DEBUG_LOG(m_logger) << "acceptNavigationRequest denied for " << url.toString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "acceptNavigationRequest allowed for " << url.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void linkClicked(const QUrl &url);
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
HtmlWidget::HtmlWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::HtmlWidget)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("THP.HtmlWidget"))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto webEnginePage = new MyQWebEnginePage(m_logger, this);
|
||||
ui->html->setPage(webEnginePage);
|
||||
connect(webEnginePage, &MyQWebEnginePage::linkClicked, this, &HtmlWidget::linkClicked);
|
||||
connect(ui->html, &QWebEngineView::loadFinished, this, &HtmlWidget::loadFinished);
|
||||
connect(ui->html, &QWebEngineView::urlChanged, this, &HtmlWidget::urlChanged);
|
||||
connect(ui->html, &QWebEngineView::titleChanged, this, &HtmlWidget::titleChanged);
|
||||
}
|
||||
|
||||
HtmlWidget::~HtmlWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void HtmlWidget::back()
|
||||
{
|
||||
ui->html->back();
|
||||
}
|
||||
|
||||
QString HtmlWidget::title() const
|
||||
{
|
||||
return ui->html->title();
|
||||
}
|
||||
|
||||
QUrl HtmlWidget::url() const
|
||||
{
|
||||
return ui->html->url();
|
||||
}
|
||||
|
||||
bool HtmlWidget::showHTML(const QUrl &url)
|
||||
{
|
||||
if (!url.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Invalid url: " << url.toString();
|
||||
return false;
|
||||
}
|
||||
ui->html->load(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HtmlWidget::setZoomFactor(double newZoomFactor)
|
||||
{
|
||||
ui->html->setZoomFactor(newZoomFactor);
|
||||
}
|
||||
|
||||
void HtmlWidget::print(QPrinter *printer) const
|
||||
{
|
||||
ui->html->page()->print(printer, [](bool) {});
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
#include "thp_html_widget.moc"
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle HTML output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
class QUrl;
|
||||
class QPrinter;
|
||||
namespace Ui
|
||||
{
|
||||
class HtmlWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class HtmlWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HtmlWidget(QWidget *parent = nullptr);
|
||||
~HtmlWidget();
|
||||
|
||||
void back();
|
||||
void print(QPrinter *printer) const;
|
||||
void setZoomFactor(double newZoomFactor);
|
||||
QString title() const;
|
||||
QUrl url() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool showHTML(const QUrl &url);
|
||||
|
||||
Q_SIGNALS:
|
||||
void linkClicked(const QUrl &link);
|
||||
void loadFinished(bool);
|
||||
void urlChanged(const QUrl &url);
|
||||
void titleChanged(const QString &title);
|
||||
protected:
|
||||
Ui::HtmlWidget *ui;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>HtmlWidget</class>
|
||||
<widget class="QWidget" name="HtmlWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>719</width>
|
||||
<height>540</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWebEngineView" name="html">
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle PDF output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "thp_pdf_widget.h"
|
||||
#include "ui_thp_pdf_widget.h"
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
PdfWidget::PdfWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::PdfWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->previousPage, &QToolButton::clicked, this, &PdfWidget::onPreviousPage);
|
||||
connect(ui->nextPage, &QToolButton::clicked, this, &PdfWidget::onNextPage);
|
||||
connect(ui->pdfDocument, &NGL::PDFDocument::currentPageChanged, this, &PdfWidget::pageChanged);
|
||||
}
|
||||
|
||||
PdfWidget::~PdfWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool PdfWidget::showPDF(const QUrl &pdf)
|
||||
{
|
||||
return ui->pdfDocument->showPDF(pdf);
|
||||
}
|
||||
|
||||
void PdfWidget::setZoomFactor(double newZoomFactor)
|
||||
{
|
||||
ui->pdfDocument->setZoomFactor(newZoomFactor);
|
||||
}
|
||||
|
||||
void PdfWidget::onPreviousPage()
|
||||
{
|
||||
ui->pdfDocument->previousPage();
|
||||
}
|
||||
|
||||
void PdfWidget::onNextPage()
|
||||
{
|
||||
ui->pdfDocument->nextPage();
|
||||
}
|
||||
|
||||
QVector<QImage> PdfWidget::getPrintableImages(int resolution)
|
||||
{
|
||||
return ui->pdfDocument->getPrintableImages(resolution);
|
||||
}
|
||||
|
||||
void PdfWidget::resizePdfToWidth()
|
||||
{
|
||||
ui->pdfDocument->resizePdfToWidth();
|
||||
}
|
||||
|
||||
void PdfWidget::pageChanged(int cur, int max)
|
||||
{
|
||||
ui->pageLabel->setText(tr("Page %1 of %2").arg(cur).arg(max));
|
||||
ui->nextPage->setEnabled(cur < max);
|
||||
ui->previousPage->setEnabled(cur > 1);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle PDF output for thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
class QUrl;
|
||||
namespace Ui
|
||||
{
|
||||
class PdfWidget;
|
||||
}
|
||||
|
||||
namespace THP
|
||||
{
|
||||
class PdfWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PdfWidget(QWidget *parent = nullptr);
|
||||
~PdfWidget();
|
||||
|
||||
bool showPDF(const QUrl &pdf);
|
||||
void setZoomFactor(double newZoomFactor);
|
||||
QVector<QImage> getPrintableImages(int resolution = 300);
|
||||
void resizePdfToWidth();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPreviousPage();
|
||||
void onNextPage();
|
||||
void pageChanged(int cur, int max);
|
||||
protected:
|
||||
|
||||
Ui::PdfWidget *ui;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PdfWidget</class>
|
||||
<widget class="QWidget" name="PdfWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>580</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="NGL::PDFDocument" name="pdfDocument" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>202</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QToolButton" name="previousPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-previous.png</normaloff>:icons/16x16/go-previous.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pageLabel">
|
||||
<property name="text">
|
||||
<string>page %1 of %2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="nextPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/go-next.png</normaloff>:icons/16x16/go-next.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>201</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NGL::PDFDocument</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">nglwidgets/nglpdfdocument.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_building_base.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
#include "thp_situation_filter_types.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QTimer>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
#include <PlanOverlays/Gui/plan_overlay_model.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
using namespace SituationReplay;
|
||||
|
||||
SituationBuildingBase::SituationBuildingBase(const char *loggerName,
|
||||
QWidget *parent)
|
||||
: QFrame(parent)
|
||||
, m_playTimer(new QTimer(this))
|
||||
, m_ui(new Ui::SituationBuildingBase)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->zoomSlider->hide();
|
||||
m_ui->sldPosition->setMinimum(0);
|
||||
m_ui->sldPosition->setMaximum(s_sliderMax);
|
||||
|
||||
m_playTimer->setSingleShot(true);
|
||||
connect(m_playTimer, &QTimer::timeout, this, &SituationBuildingBase::onPlay);
|
||||
|
||||
connect(m_ui->btnSlower, &QToolButton::clicked, this, &SituationBuildingBase::onSlower);
|
||||
connect(m_ui->btnFaster, &QToolButton::clicked, this, &SituationBuildingBase::onFaster);
|
||||
connect(m_ui->btn100pct, &QToolButton::clicked, this, &SituationBuildingBase::on100pct);
|
||||
connect(m_ui->btnPlay, &QToolButton::clicked, this, &SituationBuildingBase::onPlay);
|
||||
connect(m_ui->btnStop, &QToolButton::clicked, this, &SituationBuildingBase::onStop);
|
||||
|
||||
connect(m_ui->sldPosition, &QSlider::sliderPressed, this, &SituationBuildingBase::onSliderPressed);
|
||||
connect(m_ui->sldPosition, &QSlider::sliderMoved, this, &SituationBuildingBase::onSliderPositionChanged);
|
||||
connect(m_ui->sldPosition, &QSlider::sliderReleased, this, &SituationBuildingBase::onSliderReleased);
|
||||
|
||||
connect(m_ui->cbPlaybackParts, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &SituationBuildingBase::onCbPlaybackPartsChanged);
|
||||
}
|
||||
|
||||
SituationBuildingBase::~SituationBuildingBase()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::init(SituationReplay::MainHandlerSqlite *replayHandler)
|
||||
{
|
||||
if (m_replayHandler)
|
||||
m_replayHandler->disconnect(this);
|
||||
m_replayHandler = replayHandler;
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::initialReplaySpeed,
|
||||
this, &SituationBuildingBase::setSpeed);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::applyCurentFilter,
|
||||
this, &SituationBuildingBase::applyCurentFilter);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::applyNewOverlay,
|
||||
this, &SituationBuildingBase::applyNewOverlay);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::removeOverlay,
|
||||
this, &SituationBuildingBase::removeOverlay);
|
||||
connect(m_replayHandler, &SituationReplay::MainHandlerSqlite::fileContentAvailable,
|
||||
this, &SituationBuildingBase::onFileContentAvailable);
|
||||
updatePositionLabel(LtsUtils::QPoint3D(), false);
|
||||
updateSpeedLabel();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::showSituation(const QString &sitReplayDescription,
|
||||
const QString &basePath)
|
||||
{
|
||||
// read ReplayInformation from sitmap.json (key 'replays')
|
||||
|
||||
QFile f(sitReplayDescription); // ...Exercise_123//n/m/sitmap.json
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open file '" << sitReplayDescription << "': " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi(f);
|
||||
m_scriptPath = fi.absolutePath();
|
||||
|
||||
QJsonParseError jError;
|
||||
const QByteArray ba = f.readAll();
|
||||
QJsonDocument doc(QJsonDocument::fromJson(ba, &jError));
|
||||
if (jError.error)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: " << jError.errorString();
|
||||
return false;
|
||||
}
|
||||
const QJsonObject rootObj = doc.object();
|
||||
const QJsonArray arrReplays(rootObj[QStringLiteral("replays")].toArray());
|
||||
QVector<ReplayInformation> replayInformation;
|
||||
replayInformation.reserve(arrReplays.size());
|
||||
for (const auto &val : arrReplays)
|
||||
{
|
||||
const QJsonObject obj = val.toObject();
|
||||
const QJsonObject objPb = obj[QStringLiteral("playbackTime")].toObject();
|
||||
const QJsonObject objSqlite = obj[QStringLiteral("replayInformation")].toObject();
|
||||
const QJsonObject objTip = objSqlite[QStringLiteral("timeInPresentation")].toObject();
|
||||
ReplayInformation info;
|
||||
info.id = obj[QStringLiteral("id")].toInt();
|
||||
info.timeSpan = TimeSpan::fromJson(objPb);
|
||||
info.relativeTimeSpan = TimeSpan::fromJson(objTip);
|
||||
const int sqliteFolderId = objSqlite[QStringLiteral("id")].toInt();
|
||||
info.databaseFilePath = QStringLiteral("%1/%2/sitreplay.sqlite").arg(basePath).arg(sqliteFolderId);
|
||||
info.replayConfigPath = QStringLiteral("%1/%2/sitreplay.json").arg(basePath).arg(sqliteFolderId);
|
||||
if (info.relativeTimeSpan.begin < 0 ||
|
||||
info.relativeTimeSpan.end <= info.relativeTimeSpan.begin ||
|
||||
sqliteFolderId == 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
replayInformation.push_back(std::move(info));
|
||||
}
|
||||
const QJsonObject attributes(rootObj[QStringLiteral("attributes")].toObject());
|
||||
const QJsonArray arrFilters1(attributes[QStringLiteral("Filters")].toArray());
|
||||
QVector<FilterInformation> filterInformation;
|
||||
QVector<FilterInformation> overlayInformation;
|
||||
|
||||
for (const auto &arrVal : arrFilters1)
|
||||
{
|
||||
// const QJsonArray arrFilters2(arrVal.toArray());
|
||||
// for (const auto &val : arrFilters2)
|
||||
// {
|
||||
FilterInformation filter;
|
||||
const QJsonObject obj = arrVal.toObject();
|
||||
LtsScriptTimeline::TrackEntry te;
|
||||
te.fromJson(obj);
|
||||
if (te.m_topicId <= 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not load filter information from '" << QJsonDocument(obj).toJson() << "'";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (te.m_type != LtsScriptTimeline::TrackEntryType::SituationMapFilter &&
|
||||
te.m_type != LtsScriptTimeline::TrackEntryType::TacticalPlan)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Unknown Filter type " << te.m_type << " - ignoring: " << QJsonDocument(obj).toJson() << "'";
|
||||
continue;
|
||||
}
|
||||
|
||||
filter.id = te.m_topicId;
|
||||
filter.relativeTimeSpan.begin = te.m_startTime * 1000LL;
|
||||
filter.relativeTimeSpan.end = te.m_length * 1000LL + filter.relativeTimeSpan.begin;
|
||||
const QJsonObject details = obj[QStringLiteral("detailData")].toObject();
|
||||
if (te.m_type == LtsScriptTimeline::TrackEntryType::SituationMapFilter)
|
||||
{
|
||||
const QJsonObject filters = te.m_detailData[QStringLiteral("filters")].toObject();
|
||||
filter.aesFilters = filters[QStringLiteral("AesFilterJson")].toObject();
|
||||
filter.symbolSettings = filters[QStringLiteral("SymbolAppearanceJson")].toObject();
|
||||
filter.buildingComponentSettings = filters[QStringLiteral("BuildingComponentSettingsJson")].toObject();
|
||||
filter.mapSettings = details[QStringLiteral("settings")].toObject();
|
||||
|
||||
if (filter.relativeTimeSpan.begin < 0 || filter.aesFilters.isEmpty() || filter.symbolSettings.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
if (filter.buildingComponentSettings.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data 'BuildingComponentSettingsJson', json= " << QJsonDocument(obj).toJson();
|
||||
// return false; // support older thps with this thpViewer
|
||||
}
|
||||
|
||||
|
||||
filterInformation.push_back(std::move(filter));
|
||||
}
|
||||
else if (te.m_type == LtsScriptTimeline::TrackEntryType::TacticalPlan)
|
||||
{
|
||||
if (filter.relativeTimeSpan.begin < 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(obj).toJson();
|
||||
return false;
|
||||
}
|
||||
|
||||
// old version (before 2020/02)
|
||||
filter.overlayId = details[QStringLiteral("FileId")].toInt(-1);
|
||||
if (filter.overlayId >= 0)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Add overlay with id " << filter.overlayId;
|
||||
overlayInformation.push_back(std::move(filter));
|
||||
continue;
|
||||
}
|
||||
const QJsonArray arr = details[QStringLiteral("PlanItems")].toArray();
|
||||
if (arr.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No PlanItems given - " << QJsonDocument(details).toJson();
|
||||
}
|
||||
for (const auto &ele : arr)
|
||||
{
|
||||
const auto pi = PlanOverlaysPlugin::PlanOverlayModel::PlanItem::fromJson(ele.toObject());
|
||||
if (!pi.isValid() || pi.m_fileId <= 0)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document - can not read filter data " << QJsonDocument(ele.toObject()).toJson();
|
||||
return false;
|
||||
}
|
||||
filter.overlayId = pi.m_fileId;
|
||||
DEBUG_LOG(m_logger) << "Add overlay with id " << filter.overlayId;
|
||||
overlayInformation.push_back(filter);
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
m_replayInformation = replayInformation;
|
||||
m_filterInformation = filterInformation;
|
||||
m_overlayInformation = overlayInformation;
|
||||
m_attributes = rootObj[QStringLiteral("attributes")].toObject();
|
||||
return showSituationInternal();
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::showSituationInternal()
|
||||
{
|
||||
m_ui->cbPlaybackParts->setVisible(m_replayInformation.size() > 1);
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString sqliteDb = m_replayInformation.first().databaseFilePath;
|
||||
if (sqliteDb.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No database given...";
|
||||
return false;
|
||||
}
|
||||
QFileInfo fi(sqliteDb);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
WARNING_LOG(m_logger) << "Can not access sqlite database '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ui->cbPlaybackParts->clear();
|
||||
m_ui->cbPlaybackParts->blockSignals(true);
|
||||
for (int i = 0; i < m_replayInformation.size(); ++i)
|
||||
{
|
||||
const ReplayInformation &info = m_replayInformation.at(i);
|
||||
m_ui->cbPlaybackParts->addItem(QStringLiteral("%1: %2 - %3").arg(i+1).arg(DTG::toStringMSec(info.timeSpan.begin, DTG::Long),
|
||||
DTG::toStringMSec(info.timeSpan.end, DTG::Long)), i);
|
||||
}
|
||||
m_ui->cbPlaybackParts->setCurrentIndex(0);
|
||||
m_ui->cbPlaybackParts->blockSignals(false);
|
||||
onCbPlaybackPartsChanged(); // creates replayHandler for correct db etc.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::setSpeed(double newSpeed)
|
||||
{
|
||||
m_speedVal = qBound(0.0, newSpeed, 16.0);
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPaceChangeRequest(m_speedVal);
|
||||
|
||||
updateSpeedLabel();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSlower()
|
||||
{
|
||||
// cur speed = 9 -> new speed = 7
|
||||
// cur speed = 4 -> new speed = 3
|
||||
int diff = lrint(sqrt(m_speedVal) - 1);
|
||||
if (diff < 1)
|
||||
diff = 1;
|
||||
setSpeed(m_speedVal - diff);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onFaster()
|
||||
{
|
||||
int diff = lrint(sqrt(m_speedVal) - 1);
|
||||
if (diff < 1)
|
||||
diff = 1;
|
||||
setSpeed(m_speedVal + diff);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::on100pct()
|
||||
{
|
||||
setSpeed(1.0);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onPlay()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "OnPlay " << int(m_state);
|
||||
switch (m_state)
|
||||
{
|
||||
case State::PS_STOP:
|
||||
m_state = State::PS_PLAY;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStartReplayRequest(m_speedVal);
|
||||
break;
|
||||
case State::PS_PAUSE:
|
||||
m_state = State::PS_PLAY;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onResumeReplayRequest();
|
||||
break;
|
||||
case State::PS_PLAY:
|
||||
m_state = State::PS_PAUSE;
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPauseReplayRequest();
|
||||
break;
|
||||
case State::PS_UNDEFINED:
|
||||
// dürfte nicht vorkommen
|
||||
break;
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onStop()
|
||||
{
|
||||
auto srp = m_replayHandler->handlerSrp();
|
||||
if (srp)
|
||||
{
|
||||
srp->onStopReplayRequest();
|
||||
onUpdateTimeSlider(srp->beginTime());
|
||||
}
|
||||
m_state = State::PS_STOP;
|
||||
updateButtons();
|
||||
m_ui->sldPosition->setValue(0);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderPressed()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onPauseReplayRequest();
|
||||
m_state = State::PS_PAUSE;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderPositionChanged(int newPosition)
|
||||
{
|
||||
if (!m_replayHandler->handlerSrp())
|
||||
return;
|
||||
auto srp = m_replayHandler->handlerSrp();
|
||||
const double len = (srp->endTime() - srp->beginTime());
|
||||
const double ofs = newPosition * len / s_sliderMax;
|
||||
m_sliderMoveTime = qRound64(srp->beginTime() + ofs);
|
||||
|
||||
m_currentTimeDTGString = DTG::toStringMSec(m_sliderMoveTime, DTG::Long);
|
||||
m_ui->lblPosition->setText(m_currentTimeDTGString);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onSliderReleased()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStartReplayRequest(m_sliderMoveTime,
|
||||
m_replayHandler->handlerSrp()->endTime(),
|
||||
m_speedVal);
|
||||
m_state = State::PS_PLAY;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onUpdateTimeSlider(qint64 curTime)
|
||||
{
|
||||
if (!m_replayHandler->handlerSrp() || m_state == State::PS_STOP)
|
||||
return;
|
||||
const auto srp = m_replayHandler->handlerSrp();
|
||||
const double len = (srp->endTime() - srp->beginTime());
|
||||
const double ofs = (curTime - srp->beginTime());
|
||||
double pos = ofs / len * s_sliderMax;
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
if (pos >= s_sliderMax)
|
||||
{
|
||||
onStop();
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "onUpdateTimeSlider: " << curTime << ", pos: " << pos;
|
||||
m_ui->sldPosition->setValue(qRound(pos));
|
||||
|
||||
m_currentTimeDTGString = DTG::toStringMSec(curTime, DTG::Long);
|
||||
m_ui->lblPosition->setText(m_currentTimeDTGString);
|
||||
emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onCbPlaybackPartsChanged()
|
||||
{
|
||||
onStop();
|
||||
int idx = m_ui->cbPlaybackParts->currentData().toInt();
|
||||
if (idx < 0 || idx >= m_replayInformation.size())
|
||||
return;
|
||||
const ReplayInformation &info = m_replayInformation.at(idx);
|
||||
if (!m_replayHandler->initDb(info, m_filterInformation, m_overlayInformation))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not initialize replay handler (" << info.databaseFilePath << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
// currently after initDb since there handlerSrp is (re)created
|
||||
connect(m_replayHandler->handlerSrp().get(), &SituationReplay::HandlerSituationReplaySqlite::replayTimeChanged,
|
||||
this, &SituationBuildingBase::onUpdateTimeSlider, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updateSpeedLabel()
|
||||
{
|
||||
QString speedStr = QStringLiteral("%1x").arg(m_speedVal, 4, 'f', 2);
|
||||
m_ui->lblSpeed->setText(speedStr);
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updatePositionLabel(const LtsUtils::QPoint3D &geoPos, bool isValid)
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.x(), geoPos.y()));
|
||||
m_ui->lblCursorPos->setText(coord.mgrs());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->lblCursorPos->setText(QString());
|
||||
}
|
||||
}
|
||||
|
||||
QString SituationBuildingBase::currentDTGTime() const
|
||||
{
|
||||
return m_currentTimeDTGString;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::updateButtons()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case State::PS_UNDEFINED:
|
||||
m_ui->btnStop->setEnabled(false);
|
||||
m_ui->btnPlay->setEnabled(false);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(false);
|
||||
break;
|
||||
case State::PS_STOP:
|
||||
m_ui->btnStop->setEnabled(false);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
case State::PS_PLAY:
|
||||
m_ui->btnStop->setEnabled(true);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-pause.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
case State::PS_PAUSE:
|
||||
m_ui->btnStop->setEnabled(true);
|
||||
m_ui->btnPlay->setEnabled(true);
|
||||
m_ui->btnPlay->setIcon(QIcon(QStringLiteral(":icons/16x16/media-playback-start.png")));
|
||||
m_ui->sldPosition->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SituationBuildingBase::stop()
|
||||
{
|
||||
onStop();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationBuildingBase::onInitDone()
|
||||
{
|
||||
m_state = State::PS_STOP;
|
||||
m_playTimer->start();
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation / building display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
|
||||
namespace FileManagement
|
||||
{
|
||||
namespace Database
|
||||
{
|
||||
struct FlmFileContent;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SituationReplay
|
||||
{
|
||||
class MainHandlerSqlite;
|
||||
}
|
||||
namespace LtsUtils
|
||||
{
|
||||
class QPoint3D;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SituationBuildingBase;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
enum class State
|
||||
{
|
||||
PS_UNDEFINED = 0,
|
||||
PS_STOP = 1,
|
||||
PS_PLAY = 2,
|
||||
PS_PAUSE = 3
|
||||
};
|
||||
constexpr int s_sliderMax = 1000; // 0 .. 1000
|
||||
|
||||
class SituationBuildingBase : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationBuildingBase(const char *loggerName,
|
||||
QWidget *parent = nullptr);
|
||||
~SituationBuildingBase();
|
||||
|
||||
bool init(SituationReplay::MainHandlerSqlite *replayHandler);
|
||||
bool showSituation(const QString &sitReplayDescription, const QString &basePath);
|
||||
|
||||
void updateButtons();
|
||||
bool stop();
|
||||
QString currentDTGTime() const;
|
||||
|
||||
protected:
|
||||
virtual bool showSituationInternal();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void setSpeed(double newSpeed);
|
||||
virtual void applyCurentFilter(const SituationReplay::FilterInformation &filter) = 0;
|
||||
virtual void applyNewOverlay(int overlayId) = 0;
|
||||
virtual void removeOverlay(int overlayId) = 0;
|
||||
void onSlower();
|
||||
void onFaster();
|
||||
void on100pct();
|
||||
void onPlay();
|
||||
void onStop();
|
||||
|
||||
void onSliderPressed();
|
||||
void onSliderPositionChanged(int newPosition);
|
||||
void onSliderReleased();
|
||||
void updateSpeedLabel();
|
||||
void onUpdateTimeSlider(qint64 curTime);
|
||||
void onCbPlaybackPartsChanged();
|
||||
void updatePositionLabel(const LtsUtils::QPoint3D &geoPos, bool isValid);
|
||||
virtual void updateZoomSlider() {}
|
||||
|
||||
virtual void onInitDone();
|
||||
virtual void emitPartitionTimeChanged(qint64 curTime) = 0;
|
||||
|
||||
virtual void onFileContentAvailable(const FileManagement::Database::FlmFileContent &) {}
|
||||
protected:
|
||||
QVector<SituationReplay::ReplayInformation> m_replayInformation;
|
||||
QVector<SituationReplay::FilterInformation> m_filterInformation;
|
||||
QVector<SituationReplay::FilterInformation> m_overlayInformation;
|
||||
QJsonObject m_attributes;
|
||||
QString m_scriptPath; // sitmap.json
|
||||
double m_speedVal = 1;
|
||||
State m_state = State::PS_STOP;
|
||||
QTimer *m_playTimer = nullptr;
|
||||
SituationReplay::MainHandlerSqlite *m_replayHandler = nullptr;
|
||||
|
||||
QString m_currentTimeDTGString;
|
||||
qint64 m_sliderMoveTime = 0;
|
||||
|
||||
Ui::SituationBuildingBase *m_ui;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SituationBuildingBase</class>
|
||||
<widget class="QFrame" name="SituationBuildingBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>911</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="vLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="THP::ZoomSlider" name="zoomSlider" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sldPosition">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPosition">
|
||||
<property name="text">
|
||||
<string notr="true">--:-- / --:--</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnPlay">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-playback-start.png</normaloff>:icons/16x16/media-playback-start.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-playback-stop.png</normaloff>:icons/16x16/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnSlower">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-slower.png</normaloff>:icons/16x16/media-play-slower.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btn100pct">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-normal.png</normaloff>:icons/16x16/media-play-normal.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFaster">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:icons/16x16/media-play-faster.png</normaloff>:icons/16x16/media-play-faster.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSpeed">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">100 %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbPlaybackParts">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCursorPos">
|
||||
<property name="text">
|
||||
<string notr="true">MGRS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnFilter">
|
||||
<property name="text">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>THP::ZoomSlider</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>thpwidgets/thp_zoom_slider.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Aes/flt_aes_filter_widget.h>
|
||||
#include <ProjectDataManagement/Gui/PdmComboBox/pdm_combobox_foreign_gui_interface_impl.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterAes::SituatationFilterAes(const std::shared_ptr<FilterManagement::AesDisplayFilter> &aesFilter,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::AesFilterWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Area Effect Simulation filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::AesFilterWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterAes::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterAes::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::ForeignGuiInterfaceImpl>
|
||||
ifcPdmCbx(std::make_shared<ProjectDataManagement::ForeignGuiInterfaceImpl>());
|
||||
ifcPdmCbx->init(pluginProvider->pdmDtc());
|
||||
|
||||
m_filterWidget->init(ifcPpmCbx, ifcPdmCbx, aesFilter);
|
||||
// make sure to update ui when filter changes
|
||||
connect(m_filterWidget, &FilterManagement::AesFilterWidget::unknownChangesRecognized,
|
||||
m_filterWidget, &FilterManagement::AesFilterWidget::updateGuiToFilter);
|
||||
}
|
||||
|
||||
void SituatationFilterAes::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterAes::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class AesFilterWidget;
|
||||
class AesDisplayFilter;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterAes final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterAes(const std::shared_ptr<FilterManagement::AesDisplayFilter> &aesFilter,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::AesFilterWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_building_components.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/BuildingComponents/flt_building_component_settings_widget.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituationFilterBuildingComponent::SituationFilterBuildingComponent(const std::shared_ptr<FilterManagement::BuildingComponentSettings> &bcs,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::BuildingComponentSettingsWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Building / Component filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::BuildingComponentSettingsWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituationFilterBuildingComponent::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituationFilterBuildingComponent::reject);
|
||||
|
||||
m_filterWidget->init(bcs, pluginProvider->ismDtc());
|
||||
}
|
||||
|
||||
void SituationFilterBuildingComponent::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituationFilterBuildingComponent::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class BuildingComponentSettings;
|
||||
class BuildingComponentSettingsWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituationFilterBuildingComponent final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationFilterBuildingComponent(const std::shared_ptr<FilterManagement::BuildingComponentSettings> &bcs,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::BuildingComponentSettingsWidget *m_filterWidget{nullptr};
|
||||
};
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <AdvancedSymbology/Data/asb_foreign_interface_impl.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_collapse_expand_participants_widget.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterCollapseExpand::SituatationFilterCollapseExpand(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::CollapseExpandParticipantWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Collapse/Expand Participant filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::CollapseExpandParticipantWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterCollapseExpand::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterCollapseExpand::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
std::shared_ptr<AdvancedSymbology::ForeignInterfaceImpl>
|
||||
ifcAsb(std::make_shared<AdvancedSymbology::ForeignInterfaceImpl>(pluginProvider->ppmDtc(),
|
||||
pluginProvider->aesDtc(),
|
||||
pluginProvider->gimDtc()));
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc(),
|
||||
ifcPpmCbx,
|
||||
ifcAsb,
|
||||
// pluginProvider->fltParticipantIfc(),
|
||||
sas);
|
||||
}
|
||||
|
||||
void SituatationFilterCollapseExpand::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterCollapseExpand::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Collapse/Expand filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class CollapseExpandParticipantWidget;
|
||||
class SymbolAppearanceSettings;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterCollapseExpand final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterCollapseExpand(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::CollapseExpandParticipantWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_symbol_appearance_widget.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterSymbolAppearance::SituatationFilterSymbolAppearance(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::SymbolAppearanceWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Symbol Appearance filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::SymbolAppearanceWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterSymbolAppearance::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterSymbolAppearance::reject);
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc()->partys(), sas);
|
||||
}
|
||||
|
||||
void SituatationFilterSymbolAppearance::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterSymbolAppearance::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Symbol Appearance filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class SymbolAppearanceSettings;
|
||||
class SymbolAppearanceWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterSymbolAppearance final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterSymbolAppearance(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::SymbolAppearanceWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_filter_types.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/Gui/Participant/flt_type_filter_widget.h>
|
||||
#include <ParticipantManagement/Gui/PpmComboBox/ppm_combobox_foreign_gui_interface_impl.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
SituatationFilterTypes::SituatationFilterTypes(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_filterWidget(new FilterManagement::TypeFilterWidget(this))
|
||||
{
|
||||
setWindowTitle(tr("Type filter settings"));
|
||||
QGridLayout *gl = new QGridLayout(this);
|
||||
m_filterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
gl->addWidget(m_filterWidget, 0, 0);
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
gl->addWidget(line, 1, 0);
|
||||
QDialogButtonBox *bb = new QDialogButtonBox(this);
|
||||
gl->addWidget(bb, 2, 0);
|
||||
|
||||
|
||||
bb->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Cancel);
|
||||
connect(bb->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
m_filterWidget, &FilterManagement::TypeFilterWidget::apply);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
||||
this, &SituatationFilterTypes::accept);
|
||||
connect(bb->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
|
||||
this, &SituatationFilterTypes::reject);
|
||||
|
||||
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>
|
||||
ifcPpmCbx(std::make_shared<ParticipantManagement::ForeignGuiComboboxInterfaceImpl>());
|
||||
ifcPpmCbx->init(pluginProvider->ppmDtc());
|
||||
|
||||
m_filterWidget->init(pluginProvider->ppmDtc(),
|
||||
ifcPpmCbx,
|
||||
sas);
|
||||
}
|
||||
|
||||
void SituatationFilterTypes::accept()
|
||||
{
|
||||
m_filterWidget->apply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SituatationFilterTypes::reject()
|
||||
{
|
||||
m_filterWidget->dialogCanceled();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Type filter dialog for situation map/thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "thp_plugin_provider.h"
|
||||
#include <QDialog>
|
||||
|
||||
namespace FilterManagement
|
||||
{
|
||||
class SymbolAppearanceSettings;
|
||||
class TypeFilterWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterTypes final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituatationFilterTypes(const std::shared_ptr<FilterManagement::SymbolAppearanceSettings> &sas,
|
||||
SitMapPluginProvider *pluginProvider,
|
||||
QWidget *parent = nullptr);
|
||||
protected:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
private:
|
||||
FilterManagement::TypeFilterWidget *m_filterWidget;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,650 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_situation_widget.h"
|
||||
#include "ui_thp_situation_building_base.h"
|
||||
|
||||
#include "thp_situation_filter_aes.h"
|
||||
#include "thp_situation_filter_symbol_appearance.h"
|
||||
#include "thp_situation_filter_collapse_expand.h"
|
||||
#include "thp_situation_filter_types.h"
|
||||
#include "thp_situation_filter_building_components.h"
|
||||
#include "thp_plugin_provider.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <FileManagement/flm_db_structs.h>
|
||||
#include <FilterManagement/flt_participant_plugin_interface.h>
|
||||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||||
#include <FilterManagement/flt_building_cmpnt_settings.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/aes_display_filter_impl.h>
|
||||
#include <FilterManagement/Gui/Aes/Common/symbol_appearance_settings_impl.h>
|
||||
|
||||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||||
|
||||
#include <SituationMap/situation_map_init.h>
|
||||
#include <SituationMap/Utils/movement_track_manager.h>
|
||||
#include <SituationMap/Map/grid.h>
|
||||
#include <SituationMap/Map/point3D.h>
|
||||
#include <SituationMap/Map/map_initializer.h>
|
||||
#include <SituationMap/Map/map_notifier.h>
|
||||
#include <SituationMap/Map/operator_map_settings.h>
|
||||
#include <SituationMap/Map/overlay_handler.h>
|
||||
#include <SituationMap/Symbology/sidc_codec.h>
|
||||
#include <PlanOverlays/Gui/plan_overlay_model.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
class MySitMapIinit final : public SituationMap::SituationMapInit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using SituationMap::SituationMapInit::SituationMapInit;
|
||||
|
||||
bool trainingAreaExists() const override { return true; }
|
||||
SituationMap::MapSettingsJson getMapSettingsFromService() const override { return m_mapSettingsJson; }
|
||||
void setMapSettingsJson(const SituationMap::MapSettingsJson &settings) { m_mapSettingsJson = settings; }
|
||||
const SituationMap::MapSettingsJson & getMapSettingsJson() const { return m_mapSettingsJson; }
|
||||
|
||||
private:
|
||||
SituationMap::MapSettingsJson m_mapSettingsJson;
|
||||
};
|
||||
|
||||
using namespace SituationReplay;
|
||||
|
||||
SituationWidget::SituationWidget(QWidget *parent)
|
||||
: SituationBuildingBase("THP.SituationWidget", parent)
|
||||
, m_pluginProvider(new SitMapPluginProvider)
|
||||
, m_situationMapInit(new MySitMapIinit(nullptr))
|
||||
{
|
||||
QMenu *m = new QMenu(m_ui->btnFilter);
|
||||
m->addAction(tr("AES Filter"), this, &SituationWidget::onFilterAes);
|
||||
// 29.09.2022, Norbert Thoden
|
||||
// SWPÄ 2:22 GUEZE-1477 Kartenfilter für Komponenten:
|
||||
// Es wurde der Komponenten Filter eingeführt.
|
||||
// in der LiveLage werden allerdings nur MountingPoints angezeigt, die auch eine
|
||||
// zugeordnetes Asset haben. Die Zuordnug befindet sich in der Tabelle ism.sim_mounting_point_asset.
|
||||
// ism.sim_mounting_point_asset wird derzeit nicht in die sitreplay.sqlite
|
||||
// überführt. Es koennen also keine Komponenten angezeigt / gefiltert werden...
|
||||
// FilterDialog nicht anzeigen:
|
||||
// m->addAction(tr("Building / Component"), this, &SituationWidget::onFilterBuildingComponent);
|
||||
|
||||
m->addAction(tr("Symbol Appearance"), this, &SituationWidget::onFilterSymbolAppearance);
|
||||
m->addAction(tr("Collpase/Expand"), this, &SituationWidget::onFilterCollapseExpand);
|
||||
m->addAction(tr("Type filter"), this, &SituationWidget::onFilterTypes);
|
||||
m_ui->btnFilter->setMenu(m);
|
||||
}
|
||||
|
||||
SituationWidget::~SituationWidget()
|
||||
{
|
||||
if (m_replayHandler->handlerSrp())
|
||||
m_replayHandler->handlerSrp()->onStopReplayRequest();
|
||||
delete m_situationMapInit;
|
||||
delete m_pluginProvider;
|
||||
delete m_replayHandler;
|
||||
}
|
||||
|
||||
bool SituationWidget::init(const QString &homePath, int exerciseId)
|
||||
{
|
||||
m_pluginProvider->setExerciseId(exerciseId);
|
||||
delete m_replayHandler;
|
||||
m_replayHandler = new SituationReplay::MainHandlerSqlite;
|
||||
|
||||
if (!SituationBuildingBase::init(m_replayHandler))
|
||||
return false;
|
||||
|
||||
loadLayerMappings(homePath);
|
||||
|
||||
SituationReplay::ConnectionParams connParams;
|
||||
connParams.domainId = 1;
|
||||
connParams.partitionId = 1;
|
||||
if (!m_replayHandler->initDds(connParams))
|
||||
return false;
|
||||
|
||||
if (!m_pluginProvider->init(m_replayHandler->ddsReplay()))
|
||||
return false;
|
||||
if (!m_situationMapInit->initPluginProvider(m_pluginProvider))
|
||||
return false;
|
||||
|
||||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||||
|
||||
FATAL_LOG(m_logger) << LOGFUNCTION << " XXXX initMap....";
|
||||
|
||||
if (!m_situationMapInit->initMap(false, SituationMap::Mode::Mode_2D))
|
||||
return false;
|
||||
|
||||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||||
return false;
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||||
this, &SituationWidget::updatePositionLabel,
|
||||
Qt::UniqueConnection);
|
||||
connect(map, &SituationMap::Map::extentChanged,
|
||||
this, &SituationWidget::updateZoomSlider);
|
||||
|
||||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, map);
|
||||
|
||||
m_aesDisplayFilter = m_pluginProvider->fltAesIfc()->aesFilterForOperator(0, QString());
|
||||
m_symbolAppaearanceSettings = m_pluginProvider->fltParticipantIfc()->symbolAppearanceForOperator(0, QString());
|
||||
m_buildingComponentSettings = m_pluginProvider->fltBuildingComponentIfc()->buildingComponentSettingsForOperator(0, QString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationWidget::showSituationInternal()
|
||||
{
|
||||
// cleanup 'old' map:
|
||||
// remove old overlays from former session:
|
||||
{
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map)
|
||||
map->overlayHandler().removeAllOverlays();
|
||||
}
|
||||
|
||||
|
||||
m_ui->cbPlaybackParts->setVisible(m_replayInformation.size() > 1);
|
||||
|
||||
// MAYBE there are filter to be applied:
|
||||
applyFilterFromReplayConfigFile();
|
||||
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString sqliteDb = m_replayInformation.first().databaseFilePath;
|
||||
if (sqliteDb.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No database given...";
|
||||
return false;
|
||||
}
|
||||
QFileInfo fi(sqliteDb);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
WARNING_LOG(m_logger) << "Can not access sqlite database '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ui->cbPlaybackParts->clear();
|
||||
m_ui->cbPlaybackParts->blockSignals(true);
|
||||
for (int i = 0; i < m_replayInformation.size(); ++i)
|
||||
{
|
||||
const ReplayInformation &info = m_replayInformation.at(i);
|
||||
m_ui->cbPlaybackParts->addItem(QStringLiteral("%1: %2 - %3").arg(i+1).arg(DTG::toStringMSec(info.timeSpan.begin, DTG::Long),
|
||||
DTG::toStringMSec(info.timeSpan.end, DTG::Long)), i);
|
||||
}
|
||||
m_ui->cbPlaybackParts->setCurrentIndex(0);
|
||||
m_ui->cbPlaybackParts->blockSignals(false);
|
||||
onCbPlaybackPartsChanged(); // creates replayHandler for correct db etc.
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map->isReady())
|
||||
QTimer::singleShot(0, this, &SituationWidget::onInitDone);
|
||||
else
|
||||
connect(map, &SituationMap::Map::mapReady,
|
||||
this, &SituationWidget::onInitDone, Qt::QueuedConnection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SituationWidget::applyFilterFromReplayConfigFile()
|
||||
{
|
||||
// Maybe the Situation topic has own Filter (AesFilter, SymbolAppearance; OperatorMapSettings)
|
||||
// Read and apply them:
|
||||
if (m_replayInformation.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replay information given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString replayConfigFile = m_replayInformation.first().replayConfigPath; // sitreplay.json
|
||||
if (replayConfigFile.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No replayConfigFile given...";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi(replayConfigFile);
|
||||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not access replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile f(replayConfigFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open replayConfigFile '" << fi.absoluteFilePath() << "': " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonParseError jError;
|
||||
const QByteArray ba = f.readAll();
|
||||
QJsonDocument doc(QJsonDocument::fromJson(ba, &jError));
|
||||
if (jError.error)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not parse json document: "
|
||||
<< ", replayConfigFile '" << fi.absoluteFilePath() << "'"
|
||||
<< ", errorString= " << jError.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
const QJsonObject &rootObj = doc.object();
|
||||
const QJsonObject &filters = rootObj[QStringLiteral("filters")].toObject(); // optional!!!
|
||||
|
||||
if (filters.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "no 'filters' provided at "
|
||||
<< " replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " XXXX replayConfigFile='" << fi.absoluteFilePath() << "'"
|
||||
<< " doc.toJson = " << doc.toJson();
|
||||
|
||||
// fine, put together
|
||||
FilterInformation filterInfo;
|
||||
filterInfo.aesFilters = filters[QStringLiteral("AesFilterJson")].toObject();
|
||||
filterInfo.symbolSettings = filters[QStringLiteral("SymbolAppearanceJson")].toObject();
|
||||
filterInfo.buildingComponentSettings = filters[QStringLiteral("BuildingComponentSettingsJson")].toObject();
|
||||
|
||||
filterInfo.mapSettings = rootObj[QStringLiteral("settings")].toObject();
|
||||
|
||||
applyCurentFilter(filterInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationWidget::applyCurentFilter(const SituationReplay::FilterInformation &filter)
|
||||
{
|
||||
m_aesDisplayFilter->setFilterFromData(filter.aesFilters);
|
||||
m_symbolAppaearanceSettings->setSettings(filter.symbolSettings, FilterManagement::SymbolAppearanceSettings::Part::All);
|
||||
m_buildingComponentSettings->setBldCmpSettings(filter.buildingComponentSettings);
|
||||
|
||||
SituationMap::OperatorMapSettings oms;
|
||||
oms.fromJsonObject(filter.mapSettings);
|
||||
if (oms.isEmpty() || oms.mode == SituationMap::Mode::Undefined)
|
||||
return;
|
||||
|
||||
|
||||
if (oms.mode != m_situationMapInit->getWidget()->mode())
|
||||
{
|
||||
INFO_LOG(m_logger) << " Switching to new mode : " << oms.mode;
|
||||
|
||||
SituationMap::MapSettingsJson savedMapSettingsJson;
|
||||
if (m_situationMapInit)
|
||||
{
|
||||
savedMapSettingsJson = m_situationMapInit->getMapSettingsJson(); // containing path from layerMappping.json
|
||||
m_situationMapInit->stopDisplay();
|
||||
m_situationMapInit->clearObjects();
|
||||
}
|
||||
delete m_situationMapInit;
|
||||
m_situationMapInit = new MySitMapIinit(nullptr);
|
||||
m_situationMapInit->setMapSettingsJson(savedMapSettingsJson);
|
||||
m_situationMapInit->initPluginProvider(m_pluginProvider);
|
||||
|
||||
m_situationMapInit->initMap(false, oms.mode);
|
||||
|
||||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||||
return;
|
||||
|
||||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||||
if (map)
|
||||
{
|
||||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||||
this, &SituationWidget::updatePositionLabel,
|
||||
Qt::UniqueConnection);
|
||||
connect(map, &SituationMap::Map::extentChanged,
|
||||
this, &SituationWidget::updateZoomSlider);
|
||||
|
||||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_ui->vLayout->insertWidget(0, map);
|
||||
|
||||
|
||||
static bool s_waitFlag = true;
|
||||
|
||||
QPointer<SituationMap::MapNotifier> mapNotifier = map->createMapNotifier();
|
||||
if (mapNotifier)
|
||||
{
|
||||
connect(mapNotifier.data(), &SituationMap::MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this, oms]()
|
||||
{
|
||||
s_waitFlag = false;
|
||||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||||
|
||||
});
|
||||
mapNotifier->run();
|
||||
|
||||
// snyc wait :-(
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC BEGIN";
|
||||
int i=0;
|
||||
while(i<100 && s_waitFlag) // 100 * 50ms = 5000ms
|
||||
{
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers, 50);
|
||||
QThread::msleep(50);
|
||||
++i;
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC ..., i=" << i;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC ...DONE, i=" << i;
|
||||
DEBUG_LOG(m_logger) << " WAIT_SYNC, m_situationMapInit->getWidget()->mode()" << m_situationMapInit->getWidget()->mode();
|
||||
m_situationMapInit->startDisplay();
|
||||
}
|
||||
} // if (mapNotifier)
|
||||
}
|
||||
} else {
|
||||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||||
}
|
||||
}
|
||||
|
||||
bool SituationWidget::restoreOperatorMapSettingsOverlays(const SituationMap::OperatorMapSettings &oms)
|
||||
{
|
||||
if (!m_situationMapInit || !m_situationMapInit->getWidget() || oms.isEmpty())
|
||||
return false;
|
||||
|
||||
if (!m_situationMapInit->getWidget()->restoreOperatorMapSettings(oms))
|
||||
WARNING_LOG(m_logger) << LOGFUNCTION << " restoreOperatorMapSettings failed";
|
||||
|
||||
// continue!!! maybe just LayerOrder failed.... ToDo
|
||||
|
||||
// 2. handle Overlays :
|
||||
// SituationMap can`t restore the overlays on it´s own:
|
||||
// So we have to do it here:
|
||||
const QList<int> &orderedOverlayIds = oms.orderedOverlays;
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " restore OverlayIds...";
|
||||
for (auto overlayId : qAsConst(orderedOverlayIds))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " applyNewOverlay , overlayId=" << overlayId;
|
||||
applyNewOverlay(overlayId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SituationWidget::applyNewOverlay(int overlayId)
|
||||
{
|
||||
const QString filename = QStringLiteral("%1/%2.TacticalPlan").arg(m_scriptPath).arg(overlayId);
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Can not open tactical plan '" << filename << "': " << f.errorString();
|
||||
return;
|
||||
}
|
||||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||||
if (!overlayHandler.setOverlay(overlayId, tr("Plan '%1'").arg(overlayId), f.readAll(), false))
|
||||
WARNING_LOG(m_logger) << "can not display overlay " << filename;
|
||||
|
||||
}
|
||||
|
||||
void SituationWidget::removeOverlay(int overlayId)
|
||||
{
|
||||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||||
overlayHandler.removeOverlay(overlayId);
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterAes()
|
||||
{
|
||||
if (!m_filterAesDialog)
|
||||
m_filterAesDialog = new SituatationFilterAes(m_aesDisplayFilter,
|
||||
m_pluginProvider, this);
|
||||
m_filterAesDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterSymbolAppearance()
|
||||
{
|
||||
if (!m_filterSymbolAppearanceDialog)
|
||||
m_filterSymbolAppearanceDialog = new SituatationFilterSymbolAppearance(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterSymbolAppearanceDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterCollapseExpand()
|
||||
{
|
||||
if (!m_filterCollapseExpandDialog)
|
||||
m_filterCollapseExpandDialog = new SituatationFilterCollapseExpand(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterCollapseExpandDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterTypes()
|
||||
{
|
||||
if (!m_filterTypesDialog)
|
||||
m_filterTypesDialog = new SituatationFilterTypes(m_symbolAppaearanceSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterTypesDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::onFilterBuildingComponent()
|
||||
{
|
||||
if (!m_filterBuildingComponentDialog)
|
||||
m_filterBuildingComponentDialog = new SituationFilterBuildingComponent(m_buildingComponentSettings,
|
||||
m_pluginProvider, this);
|
||||
m_filterBuildingComponentDialog->show();
|
||||
}
|
||||
|
||||
void SituationWidget::emitPartitionTimeChanged(qint64 curTime)
|
||||
{
|
||||
m_pluginProvider->emitPartitionTimeChanged(curTime);
|
||||
}
|
||||
|
||||
void SituationWidget::updateZoomSlider()
|
||||
{
|
||||
// this is not really what we want to display... but currently we hide the slider anyway
|
||||
m_ui->zoomSlider->setZoomValue(m_situationMapInit->getWidget()->scale() / 1000);
|
||||
}
|
||||
|
||||
|
||||
QString SituationWidget::centerPointString() const
|
||||
{
|
||||
const QPointF center = m_situationMapInit->getWidget()->centerPoint();
|
||||
LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(center.x(), center.y()));
|
||||
return coord.mgrs();
|
||||
}
|
||||
|
||||
QRectF SituationWidget::extentMgrs() const
|
||||
{
|
||||
const QRectF r = m_situationMapInit->getWidget()->extent();
|
||||
LtsCoordTrans::UtmCoordinate topLeft(LtsCoordTrans::UtmCoordinate::fromGeographic(r.left(), r.top()));
|
||||
LtsCoordTrans::UtmCoordinate bottomRight(LtsCoordTrans::UtmCoordinate::fromGeographic(r.right(), r.bottom(), topLeft.zone));
|
||||
return QRectF(QPointF(topLeft.x, topLeft.y), QPointF(bottomRight.x, bottomRight.y));
|
||||
}
|
||||
|
||||
QImage SituationWidget::grabFrameBuffer() const
|
||||
{
|
||||
return m_situationMapInit->getWidget()->grab().toImage();
|
||||
}
|
||||
|
||||
void SituationWidget::onInitDone()
|
||||
{
|
||||
SituationBuildingBase::onInitDone();
|
||||
m_situationMapInit->startDisplay();
|
||||
}
|
||||
|
||||
void SituationWidget::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_F10:
|
||||
onMgrsGrid();
|
||||
break;
|
||||
case Qt::Key_PageUp:
|
||||
onRotate(10);
|
||||
break;
|
||||
case Qt::Key_PageDown:
|
||||
onRotate(-10);
|
||||
break;
|
||||
default:
|
||||
QFrame::keyPressEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SituationWidget::onMgrsGrid()
|
||||
{
|
||||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||||
m->grid().setVisible(!m->grid().isVisible());
|
||||
}
|
||||
|
||||
void SituationWidget::onRotate(int degrees)
|
||||
{
|
||||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||||
m->setRotation(m->rotation() + degrees);
|
||||
}
|
||||
|
||||
void SituationWidget::onFileContentAvailable(const FileManagement::Database::FlmFileContent &data)
|
||||
{
|
||||
if (data.fileTypeId != FileManagement::FileType::OperatorDefinedSymbol ||
|
||||
data.fileStatusId != FileManagement::FileStatus::Valid ||
|
||||
data.content.size() == 0)
|
||||
return;
|
||||
|
||||
QColor colorToBeReplaced;
|
||||
bool bIsXml = false;
|
||||
|
||||
if (!data.properties.isEmpty())
|
||||
{
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument jDoc(QJsonDocument::fromJson(data.properties.toUtf8(), &parseError));
|
||||
const QJsonObject obj(jDoc.object());
|
||||
const QLatin1String imageFormatKey("imageFormat");
|
||||
bIsXml = obj.value(imageFormatKey).toString() == QLatin1String("xml");
|
||||
if (!bIsXml)
|
||||
{
|
||||
// partyColor
|
||||
const QLatin1String partyColorStr("partyColor");
|
||||
if (obj.contains(partyColorStr))
|
||||
{
|
||||
const QJsonObject partyColor = obj[partyColorStr].toObject();
|
||||
if (partyColor.size() == 3) // r, g, b
|
||||
{
|
||||
// update map:
|
||||
colorToBeReplaced.setRgb(
|
||||
partyColor[QLatin1String("r")].toInt(),
|
||||
partyColor[QLatin1String("g")].toInt(),
|
||||
partyColor[QLatin1String("b")].toInt());
|
||||
} // if (partyColor.size() == 3)
|
||||
} // if (obj.contains(partyColorStr))
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedSymbology::SymbologyType symType = AdvancedSymbology::SymbolDictionary::defaultSymbologyType();
|
||||
AdvancedSymbology::SymbolDictionary &dict =
|
||||
AdvancedSymbology::SymbolDictionary::dictionary(symType);
|
||||
if (bIsXml)
|
||||
{
|
||||
dict.setXmlSymbol(data.id, data.name, QStringLiteral("OperatorName"), 0, QString::fromUtf8(data.content), AdvancedSymbology::SymbolProperties());
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage image;
|
||||
QSvgRenderer svgRenderer;
|
||||
if (!svgRenderer.load(data.content))
|
||||
return;
|
||||
|
||||
// prepare Image:
|
||||
constexpr int size = 200; // pixel
|
||||
QImage imageOut(size, size, QImage::Format_ARGB32);
|
||||
imageOut.fill(Qt::transparent);
|
||||
|
||||
// render
|
||||
QPainter painter(&imageOut);
|
||||
svgRenderer.render(&painter);
|
||||
painter.end();
|
||||
|
||||
AdvancedSymbology::SymbolProperties symProps;
|
||||
symProps.setKey(data.name);
|
||||
symProps.setSidc(AdvancedSymbology::SidcCodec::encodeCivilEts(data.name));
|
||||
symProps.setName(data.name);
|
||||
symProps.setSymbolClass(QLatin1String("3")); // 18.10.2016, N.Thoden: 3 == PointSymbol (mil2525d.stylx - QuartzRelease)
|
||||
symProps.setGeometryType(AdvancedSymbology::GeometryType::Point); // ETS-Symbols are always Points
|
||||
symProps.setTags({data.name});
|
||||
symProps.setColorToBeReplaced(colorToBeReplaced);
|
||||
|
||||
dict.setEtsSymbol(data.id, data.name, symProps, image);
|
||||
}
|
||||
}
|
||||
|
||||
void SituationWidget::loadLayerMappings(const QString &homePath)
|
||||
{
|
||||
const QString mappingsFile = homePath + QStringLiteral("/layerMapping.json");
|
||||
|
||||
QFile f(mappingsFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
fprintf(stderr, "Could not load layer mappings from '%s' - %s\n", mappingsFile.toStdString().c_str(), f.errorString().toStdString().c_str());
|
||||
WARNING_LOG(m_logger) << "Could not load layer mappings from " << mappingsFile << ": " << f.errorString();
|
||||
return;
|
||||
}
|
||||
m_layerMapping.clear();
|
||||
const QJsonObject obj = QJsonDocument::fromJson(f.readAll()).object();
|
||||
|
||||
SituationMap::MapSettingsJson settings;
|
||||
if (!settings.fromJsonObject(obj))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not parse layer mappings from " << mappingsFile;
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setMapUrls(fixupUrls(settings.getMapUrls(), homePath));
|
||||
settings.setSceneUrls(fixupUrls(settings.getSceneUrls(), homePath));
|
||||
settings.setSceneObjectUrls(fixupUrls(settings.getSceneObjectUrls(), homePath));
|
||||
settings.setElevationUrls(fixupUrls(settings.getElevationUrls(), homePath));
|
||||
|
||||
m_situationMapInit->setMapSettingsJson(settings);
|
||||
}
|
||||
|
||||
QVector<SituationMap::BaseUrl> SituationWidget::fixupUrls(const QVector<SituationMap::BaseUrl> &in,
|
||||
const QString &homePath)
|
||||
{
|
||||
QVector<SituationMap::BaseUrl> out;
|
||||
for (auto url : in)
|
||||
{
|
||||
const QString fn = QStringLiteral("%1/Maps/%2").arg(homePath, url.url());
|
||||
if (!QFile::exists(fn))
|
||||
{
|
||||
fprintf(stderr, "Can not find map data file '%s'\n", fn.toStdString().c_str());
|
||||
QMessageBox::warning(this, tr("Can not find map data"),
|
||||
tr("Can not find map data file '%1' - can't start application").arg(fn));
|
||||
QCoreApplication::quit();
|
||||
return out;
|
||||
}
|
||||
url.setUrl(QUrl::fromLocalFile(fn).toString());
|
||||
out.push_back(std::move(url));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
#include "thp_situation_widget.moc"
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Handle situation display in thp
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SituationReplay/main_handler_sqlite.h>
|
||||
#include "thp_situation_building_base.h"
|
||||
|
||||
namespace SituationReplay
|
||||
{
|
||||
class HandlerSituationReplaySqlite;
|
||||
}
|
||||
namespace SituationMap
|
||||
{
|
||||
class BaseUrl;
|
||||
struct OperatorMapSettings;
|
||||
}
|
||||
namespace FilterManagement
|
||||
{
|
||||
class AesDisplayFilter;
|
||||
class SymbolAppearanceSettings;
|
||||
class BuildingComponentSettings;
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SituationWidget;
|
||||
}
|
||||
namespace THP
|
||||
{
|
||||
class SitMapPluginProvider;
|
||||
class SituatationFilterAes;
|
||||
class SituatationFilterSymbolAppearance;
|
||||
class SituatationFilterCollapseExpand;
|
||||
class SituatationFilterTypes;
|
||||
class SituationFilterBuildingComponent;
|
||||
class MySitMapIinit;
|
||||
|
||||
class SituationWidget : public SituationBuildingBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SituationWidget(QWidget *parent = nullptr);
|
||||
~SituationWidget();
|
||||
|
||||
bool init(const QString &homePath, int exerciseId);
|
||||
|
||||
SituationReplay::MainHandlerSqlite *replayHandler() { return m_replayHandler; }
|
||||
SitMapPluginProvider *pluginProvider() { return m_pluginProvider; }
|
||||
|
||||
|
||||
QImage grabFrameBuffer() const;
|
||||
QString centerPointString() const;
|
||||
QRectF extentMgrs() const; // mgrs
|
||||
|
||||
protected:
|
||||
bool showSituationInternal() override;
|
||||
bool applyFilterFromReplayConfigFile();
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void loadLayerMappings(const QString &homePath);
|
||||
QVector<SituationMap::BaseUrl> fixupUrls(const QVector<SituationMap::BaseUrl> &in,
|
||||
const QString &homePath);
|
||||
|
||||
bool restoreOperatorMapSettingsOverlays(const SituationMap::OperatorMapSettings &oms);
|
||||
|
||||
private Q_SLOTS:
|
||||
void applyCurentFilter(const SituationReplay::FilterInformation &filter) override;
|
||||
void applyNewOverlay(int overlayId) override;
|
||||
void removeOverlay(int overlayId) override;
|
||||
|
||||
void onFilterAes();
|
||||
void onFilterSymbolAppearance();
|
||||
void onFilterCollapseExpand();
|
||||
void onFilterTypes();
|
||||
void onFilterBuildingComponent();
|
||||
|
||||
void updateZoomSlider() override;
|
||||
|
||||
void onInitDone() override;
|
||||
void emitPartitionTimeChanged(qint64 curTime) override;
|
||||
void onMgrsGrid();
|
||||
void onRotate(int degrees);
|
||||
|
||||
void onFileContentAvailable(const FileManagement::Database::FlmFileContent &data) override;
|
||||
private:
|
||||
QVector<QPair<QString, QString>> m_layerMapping;
|
||||
|
||||
SitMapPluginProvider *m_pluginProvider{nullptr};
|
||||
MySitMapIinit *m_situationMapInit{nullptr};
|
||||
SituatationFilterAes *m_filterAesDialog{nullptr};
|
||||
SituatationFilterSymbolAppearance *m_filterSymbolAppearanceDialog{nullptr};
|
||||
SituatationFilterCollapseExpand *m_filterCollapseExpandDialog{nullptr};
|
||||
SituatationFilterTypes *m_filterTypesDialog{nullptr};
|
||||
SituationFilterBuildingComponent *m_filterBuildingComponentDialog{nullptr};
|
||||
|
||||
std::shared_ptr<FilterManagement::AesDisplayFilter> m_aesDisplayFilter;
|
||||
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> m_symbolAppaearanceSettings;
|
||||
std::shared_ptr<FilterManagement::BuildingComponentSettings> m_buildingComponentSettings;
|
||||
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* A special slider for zooming
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "thp_zoom_slider.h"
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace THP
|
||||
{
|
||||
|
||||
ZoomSlider::ZoomSlider(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_InternalMin(0.1)
|
||||
, m_InternalMax(100)
|
||||
, m_LowerThreshold(1)
|
||||
, m_UpperThreshold(10)
|
||||
, m_MinRange(0)
|
||||
, m_MaxRange(280)
|
||||
, m_Slider(nullptr)
|
||||
, m_lbl(nullptr)
|
||||
, m_text(nullptr)
|
||||
, m_ZoomValue(-1)
|
||||
, m_curSliderVal(-1)
|
||||
{
|
||||
setShowDescriptionLabel(true);
|
||||
setShowValueLabel(true);
|
||||
m_Slider = new QSlider(this);
|
||||
|
||||
connect(m_Slider, &QSlider::valueChanged, this, &ZoomSlider::calcZoomFromSlider);
|
||||
connect(this, &ZoomSlider::valueChanged, this, &ZoomSlider::updateLabel);
|
||||
|
||||
m_Slider->setRange(m_MinRange, m_MaxRange);
|
||||
m_Slider->setSingleStep(1);
|
||||
m_Slider->setPageStep(1);
|
||||
|
||||
setOrientation(Qt::Horizontal);
|
||||
//Initial calculation
|
||||
calcZoomFromSlider(m_Slider->value());
|
||||
|
||||
}
|
||||
|
||||
void ZoomSlider::setZoomValue(double zoomValue)
|
||||
{
|
||||
if (qFuzzyCompare(m_ZoomValue, zoomValue))
|
||||
return;
|
||||
//ignore values outside Min/Max boundaries.
|
||||
if (zoomValue < m_InternalMin || zoomValue > m_InternalMax)
|
||||
return;
|
||||
m_ZoomValue = zoomValue;
|
||||
|
||||
if (zoomValue < m_LowerThreshold)
|
||||
{
|
||||
//Range is 0..50%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 2;
|
||||
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_LowerThreshold - m_InternalMin) * (zoomValue - m_InternalMin);
|
||||
//qDebug() << "Value1 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
else if (zoomValue < m_UpperThreshold)
|
||||
{
|
||||
//Range is 50%..75%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_UpperThreshold - m_LowerThreshold) * (zoomValue - m_LowerThreshold);
|
||||
l_ValToSet += l_Range * 2;
|
||||
//qDebug() << "Value2 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Range is 75%..100%
|
||||
double l_Range = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_ValToSet = l_Range / static_cast<double>(m_InternalMax - m_UpperThreshold) * (zoomValue - m_UpperThreshold);
|
||||
l_ValToSet += l_Range * 3;
|
||||
//qDebug() << "Value3 = " << l_ValToSet;
|
||||
m_curSliderVal = static_cast<int>(l_ValToSet);
|
||||
|
||||
}
|
||||
m_Slider->setValue(m_curSliderVal);
|
||||
updateLabel(m_ZoomValue);
|
||||
}
|
||||
|
||||
double ZoomSlider::getZoomValue() const
|
||||
{
|
||||
return m_ZoomValue;
|
||||
}
|
||||
|
||||
void ZoomSlider::setOrientation(Qt::Orientation a_orientation)
|
||||
{
|
||||
if (!m_Slider)
|
||||
return;
|
||||
|
||||
m_Slider->setOrientation(a_orientation);
|
||||
QBoxLayout *l_Layout;
|
||||
if (a_orientation == Qt::Horizontal)
|
||||
{
|
||||
m_Slider->setMinimumWidth(40);
|
||||
m_Slider->setMinimumHeight(0);
|
||||
l_Layout = new QHBoxLayout;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Slider->setMinimumWidth(0);
|
||||
m_Slider->setMinimumHeight(40);
|
||||
l_Layout = new QVBoxLayout;
|
||||
}
|
||||
l_Layout->setContentsMargins(0, 0, 0, 0);
|
||||
if (m_text)
|
||||
l_Layout->addWidget(m_text);
|
||||
if (m_Slider)
|
||||
l_Layout->addWidget(m_Slider);
|
||||
if (m_lbl)
|
||||
l_Layout->addWidget(m_lbl);
|
||||
delete layout();
|
||||
setLayout(l_Layout);
|
||||
}
|
||||
|
||||
Qt::Orientation ZoomSlider::getOrientation() const
|
||||
{
|
||||
if (m_Slider)
|
||||
return m_Slider->orientation();
|
||||
return Qt::Horizontal;
|
||||
}
|
||||
|
||||
bool ZoomSlider::getShowDescriptionLabel() const
|
||||
{
|
||||
return (m_text != nullptr);
|
||||
}
|
||||
|
||||
void ZoomSlider::setShowDescriptionLabel(bool bVisible)
|
||||
{
|
||||
if (getShowDescriptionLabel() == bVisible)
|
||||
return;
|
||||
if (bVisible)
|
||||
{
|
||||
m_text = new QLabel(this);
|
||||
m_text->setText(tr("Zoom:"));
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_text;
|
||||
m_text = nullptr;
|
||||
}
|
||||
setOrientation(getOrientation());
|
||||
}
|
||||
|
||||
bool ZoomSlider::getShowValueLabel() const
|
||||
{
|
||||
return (m_lbl != nullptr);
|
||||
}
|
||||
|
||||
void ZoomSlider::setShowValueLabel(bool bVisible)
|
||||
{
|
||||
if (getShowValueLabel() == bVisible)
|
||||
return;
|
||||
if (bVisible)
|
||||
m_lbl = new QLabel(this);
|
||||
else
|
||||
{
|
||||
delete m_lbl;
|
||||
m_lbl = nullptr;
|
||||
}
|
||||
setOrientation(getOrientation());
|
||||
updateLabel(m_ZoomValue);
|
||||
}
|
||||
|
||||
|
||||
void ZoomSlider::calcZoomFromSlider(int a_value)
|
||||
{
|
||||
if (m_curSliderVal == a_value)
|
||||
return;
|
||||
m_curSliderVal = a_value;
|
||||
|
||||
if (a_value < (m_MaxRange - m_MinRange) / 2)
|
||||
{
|
||||
//Range 0% - 50%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 2;
|
||||
double l_R2 = (m_LowerThreshold - m_InternalMin);
|
||||
double l_ValToSet = l_R2 / l_R1 * a_value;
|
||||
l_ValToSet += m_InternalMin;
|
||||
//qDebug() << "Value4 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
else if (a_value < 3 * (m_MaxRange - m_MinRange) / 4)
|
||||
{
|
||||
//Range 50% - 75%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_R2 = (m_UpperThreshold - m_LowerThreshold);
|
||||
double l_SliderVal = a_value - (m_MaxRange - m_MinRange) / 2;
|
||||
double l_ValToSet = l_R2 / l_R1 * l_SliderVal;
|
||||
l_ValToSet += static_cast<double>(m_LowerThreshold);
|
||||
//qDebug() << "Value5 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Range 75% - 100%
|
||||
double l_R1 = (m_MaxRange - m_MinRange) / 4;
|
||||
double l_R2 = (m_InternalMax - m_UpperThreshold);
|
||||
double l_SliderVal = a_value - (m_MaxRange - m_MinRange) / 4 * 3;
|
||||
double l_ValToSet = l_R2 / l_R1 * l_SliderVal;
|
||||
|
||||
l_ValToSet += static_cast<double>(m_UpperThreshold);
|
||||
//qDebug() << "Value6 = " << l_ValToSet;
|
||||
m_ZoomValue = l_ValToSet;
|
||||
}
|
||||
emit valueChanged(m_ZoomValue);
|
||||
}
|
||||
|
||||
void ZoomSlider::updateLabel(double newValue)
|
||||
{
|
||||
if (!m_lbl)
|
||||
return;
|
||||
m_lbl->setText(formatValue(newValue));
|
||||
}
|
||||
|
||||
QString ZoomSlider::formatValue(double value) const
|
||||
{
|
||||
if (value < m_LowerThreshold)
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 2);
|
||||
if (value < m_UpperThreshold)
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 1);
|
||||
|
||||
return QStringLiteral("%1x").arg(value, 4, 'f', 0);
|
||||
}
|
||||
|
||||
} // namespace THP
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* A special slider for zooming
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QSlider;
|
||||
|
||||
namespace THP
|
||||
{
|
||||
/**
|
||||
* An specialized QSlider
|
||||
* This slider has a special, fixed range from 0.1 - 100 which is mapped to
|
||||
* suitable map scales used in the GUEZ.
|
||||
* The scale is not linear - instead it has a model behind. in smaller scales -
|
||||
* slider's going to 0.1 - it's resolution is finer than on larger scales -
|
||||
* slider's going to 100.
|
||||
* The slider accpets only values within the range 0.1....100. Other values are ignored.
|
||||
*/
|
||||
class ZoomSlider : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Qt::Orientation Orientation READ getOrientation WRITE setOrientation)
|
||||
Q_PROPERTY(bool showDescriptionLabel READ getShowDescriptionLabel WRITE setShowDescriptionLabel)
|
||||
Q_PROPERTY(bool showValueLabel READ getShowValueLabel WRITE setShowValueLabel)
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
explicit ZoomSlider(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* get the actual Zoom value.
|
||||
* @return float with the zoom value
|
||||
*/
|
||||
double getZoomValue() const;
|
||||
|
||||
/**
|
||||
* Sets the Orientation.
|
||||
* @param a_orientation The slider's orientation.
|
||||
*/
|
||||
void setOrientation(Qt::Orientation a_orientation);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Qt::Orientation getOrientation() const;
|
||||
|
||||
bool getShowDescriptionLabel() const;
|
||||
void setShowDescriptionLabel(bool bVisible);
|
||||
|
||||
bool getShowValueLabel() const;
|
||||
void setShowValueLabel(bool bVisible);
|
||||
|
||||
/**
|
||||
* format the given value as it would be shown in the zoom label
|
||||
*/
|
||||
QString formatValue(double value) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* set the slider's actual zoom value. This is a QT-Slot.
|
||||
* The slider accpet only values within it's range 0.1...100.
|
||||
* Other values are ignored.
|
||||
* @param a_zoomValue the new zoom value.
|
||||
*/
|
||||
void setZoomValue(double zoomValue);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A QT-Signal which is emitted whenever the slider's value has changed.
|
||||
* The newly set zoom value is delivered as argument.
|
||||
*/
|
||||
void valueChanged(double a_value);
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* Update the label text
|
||||
*/
|
||||
void updateLabel(double newValue);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Contains the slider's minimum zoom value
|
||||
*/
|
||||
const double m_InternalMin;
|
||||
/**
|
||||
* Contains the slider's maximum zoom value
|
||||
*/
|
||||
const double m_InternalMax;
|
||||
/**
|
||||
* Contains the slider's lower threshold value.
|
||||
* The lower threshold is at 50% of the sliders range.
|
||||
*/
|
||||
const int m_LowerThreshold;
|
||||
/**
|
||||
* Contains the slider's upper threshold value.
|
||||
* The upper threshold is at 75% of the sliders range.
|
||||
*/
|
||||
const int m_UpperThreshold;
|
||||
/**
|
||||
* Contains the slider's range minimum value
|
||||
*/
|
||||
const int m_MinRange;
|
||||
/**
|
||||
* Contains the slider's range maximum value
|
||||
*/
|
||||
const int m_MaxRange;
|
||||
|
||||
/**
|
||||
* The QSlider
|
||||
*/
|
||||
QSlider *m_Slider;
|
||||
|
||||
/**
|
||||
* The label for showing the exact slider value.
|
||||
*/
|
||||
QLabel *m_lbl;
|
||||
|
||||
/**
|
||||
* The label for showing the 'zoom' text
|
||||
*/
|
||||
QLabel *m_text;
|
||||
|
||||
/**
|
||||
* contains the zoom value
|
||||
*/
|
||||
double m_ZoomValue;
|
||||
|
||||
/**
|
||||
* The current value of the slider to avoid loops
|
||||
*/
|
||||
int m_curSliderVal;
|
||||
|
||||
private slots :
|
||||
/**
|
||||
* Calculates the zoom value from the slider's position
|
||||
*/
|
||||
void calcZoomFromSlider(int a_value);
|
||||
|
||||
};
|
||||
} // namespace THP
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(DOXYGEN_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen_Lts)
|
||||
ADD_DOXYGEN_TARGET(Lts ${CMAKE_SOURCE_DIR}/doxygen/DoxyfileLts.in ${CMAKE_BINARY_DIR}/DoxyfileLts
|
||||
${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg
|
||||
${DOXYGEN_OUT_DIR})
|
||||
|
||||
ADD_SUBDIRECTORY(Tools)
|
||||
ADD_SUBDIRECTORY(Application)
|
||||
ADD_SUBDIRECTORY(Common)
|
||||
ADD_SUBDIRECTORY(DDS)
|
||||
ADD_SUBDIRECTORY(Plugins)
|
||||
ADD_SUBDIRECTORY(Projects)
|
||||
ADD_SUBDIRECTORY(Proxies)
|
||||
ADD_SUBDIRECTORY(Services)
|
||||
ADD_SUBDIRECTORY(Viewer)
|
||||
|
||||
IF (BUILD_TESTING)
|
||||
ADD_SUBDIRECTORY(Tests)
|
||||
ENDIF()
|
||||
|
||||
OPTION(BUILD_DOCS "Build documentation as html files from Lts/Documentation" OFF)
|
||||
IF (BUILD_DOCS)
|
||||
ADD_SUBDIRECTORY(Documentation)
|
||||
ENDIF()
|
||||
|
||||
CODEGEN_WRITE_SERVICEFILE_INFO()
|
||||
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(CodeGen)
|
||||
ADD_SUBDIRECTORY(httq)
|
||||
ADD_SUBDIRECTORY(LtsAppDescriptor)
|
||||
ADD_SUBDIRECTORY(LtsAppManager)
|
||||
ADD_SUBDIRECTORY(LtsCommandLineParser)
|
||||
ADD_SUBDIRECTORY(LtsCoordinate)
|
||||
ADD_SUBDIRECTORY(LtsCoordTrans)
|
||||
ADD_SUBDIRECTORY(LtsElevation)
|
||||
ADD_SUBDIRECTORY(LtsLicence)
|
||||
ADD_SUBDIRECTORY(LtsLogin)
|
||||
ADD_SUBDIRECTORY(LtsMultiMonitor)
|
||||
ADD_SUBDIRECTORY(LtsNotification)
|
||||
ADD_SUBDIRECTORY(LtsPluginManager)
|
||||
ADD_SUBDIRECTORY(LtsPrinting)
|
||||
ADD_SUBDIRECTORY(LtsProjectionWorkstation)
|
||||
ADD_SUBDIRECTORY(LtsRestClient)
|
||||
ADD_SUBDIRECTORY(LtsScriptTimeline)
|
||||
ADD_SUBDIRECTORY(LtsSerialPortQuerry)
|
||||
ADD_SUBDIRECTORY(LtsSession)
|
||||
ADD_SUBDIRECTORY(LtsTimeline)
|
||||
ADD_SUBDIRECTORY(LtsUtils)
|
||||
ADD_SUBDIRECTORY(LtsVirtualKeyboard)
|
||||
ADD_SUBDIRECTORY(LtsWebSocket)
|
||||
ADD_SUBDIRECTORY(LtsWidgets)
|
||||
ADD_SUBDIRECTORY(PluginInterfaces)
|
||||
ADD_SUBDIRECTORY(ProjectConfig)
|
||||
ADD_SUBDIRECTORY(TopicEditorBase)
|
||||
@@ -0,0 +1,128 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
FIND_PACKAGE(RTI REQUIRED)
|
||||
FIND_PACKAGE(Grantlee5 REQUIRED)
|
||||
|
||||
NGL_ADD_LIBRARY(ALL codegen_base SHARED
|
||||
codegen_export.h
|
||||
SqlGenerator.cpp
|
||||
SqlGenerator.h
|
||||
StructBuilder.cpp
|
||||
StructBuilder.h
|
||||
XmlReader.cpp
|
||||
XmlReader.h
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_base
|
||||
PRIVATE
|
||||
Qt5::Xml
|
||||
NGLLogger
|
||||
ngltools
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(codegen_base
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
$<TARGET_PROPERTY:RTI::nddscpp2,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(codegen_base
|
||||
PUBLIC
|
||||
$<TARGET_PROPERTY:RTI::nddscpp2,INTERFACE_COMPILE_DEFINITIONS>
|
||||
)
|
||||
NGL_INSTALL_TARGET(codegen_base)
|
||||
|
||||
NGL_ADD_LIBRARY(ALL codegen_grantlee STATIC
|
||||
CppTopicGeneratorGrantlee.cpp
|
||||
CppTopicGeneratorGrantlee.h
|
||||
DaoGeneratorGrantlee.cpp
|
||||
DaoGeneratorGrantlee.h
|
||||
DatabaseGeneratorGrantlee.cpp
|
||||
DatabaseGeneratorGrantlee.h
|
||||
GeneratorGrantleeBase.cpp
|
||||
GeneratorGrantleeBase.h
|
||||
GrantleeWrappers.cpp
|
||||
GrantleeWrappers.h
|
||||
|
||||
svc.idl.grantlee
|
||||
svc_enums.idl.grantlee
|
||||
|
||||
svc_translation.cpp.grantlee
|
||||
svc_translation.h.grantlee
|
||||
|
||||
svc_dao.cpp.grantlee
|
||||
svc_dao.h.grantlee
|
||||
|
||||
svc_db.h.grantlee
|
||||
svc_db_impl.h.grantlee
|
||||
svc_db_impl.cpp.grantlee
|
||||
|
||||
svc_dtc.h.grantlee
|
||||
svc_dtc_impl.cpp.grantlee
|
||||
svc_dtc_impl.h.grantlee
|
||||
|
||||
svc_dts.h.grantlee
|
||||
svc_dts_impl.cpp.grantlee
|
||||
svc_dts_impl.h.grantlee
|
||||
|
||||
svc_ftc.h.grantlee
|
||||
svc_ftc_impl.cpp.grantlee
|
||||
svc_ftc_impl.h.grantlee
|
||||
|
||||
svc_fts.h.grantlee
|
||||
svc_fts_impl.cpp.grantlee
|
||||
svc_fts_impl.h.grantlee
|
||||
|
||||
svc_json.cpp.grantlee
|
||||
svc_json.h.grantlee
|
||||
|
||||
svc_topic_type_plugin.cpp.grantlee
|
||||
svc_topic_type_plugin.h.grantlee
|
||||
|
||||
svc_record_replay_plugin.cpp.grantlee
|
||||
svc_record_replay_plugin.h.grantlee
|
||||
|
||||
codegen_simple.py
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_grantlee
|
||||
PRIVATE
|
||||
Grantlee5::Templates
|
||||
NGLLogger
|
||||
ProjectConfig
|
||||
PUBLIC
|
||||
codegen_base
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(codegen_grantlee
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
)
|
||||
|
||||
NGL_ADD_EXECUTABLE(ALL codegen
|
||||
main_grantlee.cpp
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen
|
||||
codegen_grantlee
|
||||
LtsCommandLineParser
|
||||
nglcoreapplication
|
||||
Qt5::Core
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(codegen_gui_uics
|
||||
main_grantlee_gui.ui
|
||||
)
|
||||
NGL_ADD_EXECUTABLE(WS AAR SV NO_TRANSLATION codegen_gui
|
||||
${codegen_gui_uics}
|
||||
main_grantlee_gui.cpp
|
||||
main_grantlee_gui.ui
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(codegen_gui
|
||||
codegen_grantlee
|
||||
LtsCommandLineParser
|
||||
nglapplication
|
||||
Qt5::Widgets
|
||||
Grantlee5::Templates
|
||||
)
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate an dtc/dts interface file from idl-struct defined in a xml-file
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-01-05
|
||||
*/
|
||||
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
#include "StructBuilder.h"
|
||||
#include <QCryptographicHash>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <grantlee/context.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
CppTopicGeneratorGrantlee::CppTopicGeneratorGrantlee()
|
||||
: GeneratorGrantleeBase("CodeGen.CppTopicGeneratorGrantlee")
|
||||
{}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::init(const XmlReader *reader, StructBuilder *structBuilder)
|
||||
{
|
||||
m_reader = reader;
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
addCustomFunctions(reader->getCustomFunctions());
|
||||
|
||||
return initDataTopics() && initFunctionTopics() && initIdlStructs();
|
||||
}
|
||||
|
||||
/*
|
||||
* DataTopics -> DataTopicWrapper
|
||||
*/
|
||||
bool CppTopicGeneratorGrantlee::initDataTopics()
|
||||
{
|
||||
DataTopicsWrapper *dataTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
||||
const auto dataTopics = m_reader->getIdlStructInformation();
|
||||
QVector<IdlData> keyColumns;
|
||||
QVector<IdlData> trColumns;
|
||||
for (const CodeGen::TopicTypeInformation &tti : dataTopics)
|
||||
{
|
||||
if (!tti.isDataObject)
|
||||
continue;
|
||||
|
||||
keyColumns.clear();
|
||||
trColumns.clear();
|
||||
const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(tti.name);
|
||||
if (!ctti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << tti.name;
|
||||
continue;
|
||||
}
|
||||
DataTopicWrapper *dtw = dataTopicsWrapper->addDataTopic(ctti);
|
||||
getSpecialColumns(ctti, keyColumns, trColumns);
|
||||
if (keyColumns.size() == 1)
|
||||
dtw->setKeyColumnData(keyColumns.first());
|
||||
dtw->setTrColumns(trColumns);
|
||||
if (ctti.recordTopic)
|
||||
{
|
||||
const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name));
|
||||
if (!cti.isEmpty())
|
||||
dtw->setRecordTableInformation(cti);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctti.isDataObject)
|
||||
m_structBuilder->buildJSonStructureInformationFromIdlData(ctti);
|
||||
}
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("dataTopics"), dataTopicsWrapper);
|
||||
|
||||
QSet<QString> exportedSubTopics;
|
||||
DataTopicsWrapper *subTopicsWrapper = new DataTopicsWrapper(QString(), this);
|
||||
const QVector<QSharedPointer<DataTypeInfo>> serializeTopics = m_structBuilder->getSerializeFromToJsonTopics();
|
||||
for (const QSharedPointer<DataTypeInfo> &dti : serializeTopics)
|
||||
{
|
||||
if (exportedSubTopics.contains(dti->idlType()))
|
||||
continue;
|
||||
if (dti->isStructure())
|
||||
{
|
||||
const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(dti->idlType());
|
||||
if (!ctti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType();
|
||||
continue;
|
||||
}
|
||||
const CompleteTableInformation cti(m_structBuilder->getRecordingTopicTable(ctti.name));
|
||||
if (cti.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "could not find informations for struct " << dti->idlType();
|
||||
continue;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Adding substruct topic " << ctti.name;
|
||||
DataTopicWrapper *dtw = subTopicsWrapper->addDataTopic(ctti);
|
||||
dtw->setRecordTableInformation(cti);
|
||||
exportedSubTopics += dti->idlType();
|
||||
}
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("serializeTopics"), subTopicsWrapper);
|
||||
|
||||
QVector<MemberInformationListWrapper *> jsonTopics;
|
||||
const QMap<QString, QVector<MemberInformation>> jsonExport = m_structBuilder->jsonStructureInformation();
|
||||
for (auto it = jsonExport.begin(); it != jsonExport.end(); ++it)
|
||||
{
|
||||
MemberInformationListWrapper *mil = new MemberInformationListWrapper(it.key(), it.value(), this);
|
||||
jsonTopics += mil;
|
||||
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("jsonTopics"), QVariant::fromValue(jsonTopics));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::getSpecialColumns(const CompleteTopicTypeInformation &tti,
|
||||
QVector<IdlData> &keyColumns,
|
||||
QVector<IdlData> &trColumns) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Get special columns for " << tti.name << " - base is " << tti.baseValueType;
|
||||
if (!tti.isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "tti is not valid ...";
|
||||
return false;
|
||||
}
|
||||
for (const IdlData &ci : tti.members)
|
||||
{
|
||||
if (ci.isKey)
|
||||
keyColumns += ci;
|
||||
if (ci.isTranslatable)
|
||||
trColumns += ci;
|
||||
}
|
||||
if (tti.baseValueType.isEmpty())
|
||||
return true;
|
||||
return getSpecialColumns(topicTypeInformationByDerivedTopic(tti), keyColumns, trColumns);
|
||||
}
|
||||
|
||||
/*
|
||||
* FunctionTopics -> FunctionTopicWrapper
|
||||
*/
|
||||
bool CppTopicGeneratorGrantlee::initFunctionTopics()
|
||||
{
|
||||
//INFO_LOG(m_logger) << "IN CppFunctionTopicInterfaceGenerator:init()";
|
||||
const QVector<FunctionTopic> functionTopics = m_reader->getFunctionTopics();
|
||||
FunctionTopicsWrapper *functionTopicsWrapper(new FunctionTopicsWrapper(QStringLiteral("functionTopics"), this));
|
||||
for (const FunctionTopic &ft : functionTopics)
|
||||
{
|
||||
if (!handleStruct(ft, functionTopicsWrapper))
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ctx->insert(QStringLiteral("functionTopics"), functionTopicsWrapper);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::handleStruct(const FunctionTopic &ft,
|
||||
FunctionTopicsWrapper *functionTopicsWrapper)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "handling FunctionTopic: " << ft.name;
|
||||
|
||||
const CompleteTopicTypeInformation siRequest = m_structBuilder->topicTypeInformationByStructType(ft.requestTopicType);
|
||||
if (!siRequest.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about request topic "
|
||||
<< ft.requestTopicName;
|
||||
return false;
|
||||
}
|
||||
|
||||
const CompleteTopicTypeInformation siReply = m_structBuilder->topicTypeInformationByStructType(ft.replyTopicType);
|
||||
if (!siReply.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about reply topic "
|
||||
<< ft.replyTopicType;
|
||||
return false;
|
||||
}
|
||||
|
||||
FunctionTopicWrapper *ftw = functionTopicsWrapper->addFunctionTopic(ft, siRequest, siReply);
|
||||
const QByteArray hash = QCryptographicHash::hash(ft.requestTopicName.toUtf8(), QCryptographicHash::Sha3_512).toHex().left(16);
|
||||
ftw->setReplyHandlerHash(QStringLiteral("0x") + QString::fromLatin1(hash) + QStringLiteral("LL"));
|
||||
if (!addRequesterRequestParams(ft.name, siRequest, ftw) ||
|
||||
!addRequesterReplyParams(ft.name, siReply, ftw))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::addRequesterRequestParams(const QString &request_name,
|
||||
const CompleteTopicTypeInformation &request,
|
||||
FunctionTopicWrapper *ftw)
|
||||
{
|
||||
if (request.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation siBase = m_structBuilder->topicTypeInformationByStructType(request.baseValueType);
|
||||
if (!siBase.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about base request topic "
|
||||
<< request.baseValueType;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addRequesterRequestParams(request_name, siBase, ftw))
|
||||
return false;
|
||||
}
|
||||
ftw->addRequestParams(request.members);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::addRequesterReplyParams(const QString &request_name,
|
||||
const CompleteTopicTypeInformation &reply,
|
||||
FunctionTopicWrapper *ftw)
|
||||
{
|
||||
if (reply.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation siBase = m_structBuilder->topicTypeInformationByStructType(reply.baseValueType);
|
||||
if (!siBase.isValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not get topic informations about base reply topic "
|
||||
<< reply.baseValueType;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addRequesterReplyParams(request_name, siBase, ftw))
|
||||
return false;
|
||||
}
|
||||
ftw->addReplyParams(reply.members);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* IDL / DDS -> IdlStructWrapper
|
||||
*/
|
||||
bool CppTopicGeneratorGrantlee::handleIdlStruct(const CompleteTopicTypeInformation &csi,
|
||||
QSet<QString> &idlStructNames,
|
||||
QVector<IdlStructWrapper *> &idlStructs)
|
||||
{
|
||||
if (!csi.isValid())
|
||||
return true;
|
||||
// Struct already exported?
|
||||
if (idlStructNames.contains(csi.name))
|
||||
return true;
|
||||
|
||||
//INFO_LOG(m_logger) << "handle idlStruct: " << csi.name << "\t : " << csi.baseValueType;
|
||||
|
||||
// Is the baseStruct already exported & part of the current idl file?
|
||||
if (csi.hasBaseValue())
|
||||
{
|
||||
const CompleteTopicTypeInformation ctti = m_structBuilder->topicTypeInformationByStructType(csi.baseValueType, false);
|
||||
if (ctti.isValid())
|
||||
{
|
||||
if (ctti.extensibility == dds::core::xtypes::ExtensibilityKind_def::FINAL)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Base struct (" << ctti.name
|
||||
<< ") has final extensibility - this is not allowed";
|
||||
return false;
|
||||
}
|
||||
if (!idlStructNames.contains(csi.baseValueType))
|
||||
{
|
||||
if (!handleIdlStruct(ctti, idlStructNames, idlStructs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int idx = csi.baseValueType.indexOf(QLatin1String("::"));
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "idlStruct '" << csi.baseValueType
|
||||
<< "' not found in idl-file";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Are parts of columns idlStructs?
|
||||
for (const IdlData &idlData : csi.members)
|
||||
{
|
||||
QString idlType;
|
||||
DEBUG_LOG(m_logger) << "member: " << idlData.type << " - " << idlData.name
|
||||
<< " " << idlData.dataTypeInfo->isStructure()
|
||||
<< " " << idlData.dataTypeInfo->isSequence();
|
||||
if (idlData.dataTypeInfo->isStructure())
|
||||
idlType = idlData.dataTypeInfo->idlType();
|
||||
else if (idlData.dataTypeInfo->isSequence())
|
||||
{
|
||||
if (idlData.dataTypeInfo->innerDataType()->isStructure())
|
||||
idlType = idlData.dataTypeInfo->innerDataType()->idlType();
|
||||
}
|
||||
if (idlType.isEmpty())
|
||||
continue;
|
||||
if (!handleIdlStruct(m_structBuilder->topicTypeInformationByStructType(idlType,
|
||||
false),
|
||||
idlStructNames,
|
||||
idlStructs))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle current struct
|
||||
DEBUG_LOG(m_logger) << "Current structName: " << csi.name;
|
||||
idlStructs += new IdlStructWrapper(csi, this);
|
||||
|
||||
// Add structName to list of exported idlStructs
|
||||
idlStructNames.insert(csi.name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CppTopicGeneratorGrantlee::initIdlStructs()
|
||||
{
|
||||
//INFO_LOG(m_logger) << "IN IdlGeneratorGrantlee:init()";
|
||||
const QVector<CompleteTopicTypeInformation> csiData = m_structBuilder->topicTypeInformations();
|
||||
|
||||
QSet<QString> idlStructNames;
|
||||
QVector<IdlStructWrapper *> idlStructs;
|
||||
idlStructs.reserve(csiData.size());
|
||||
for (const CompleteTopicTypeInformation &csi : csiData)
|
||||
{
|
||||
if (!handleIdlStruct(csi, idlStructNames, idlStructs))
|
||||
return false;
|
||||
}
|
||||
// (!) No sorting of idlStruct since dependencies of idlStructs
|
||||
m_ctx->insert(QStringLiteral("idl_structs"), QVariant::fromValue(idlStructs));
|
||||
|
||||
const QVector<EnumInformation> enumerations = m_structBuilder->enumInformations();
|
||||
QVector<IdlEnumWrapper *> idlEnumerations;
|
||||
idlEnumerations.reserve(enumerations.size());
|
||||
for (const EnumInformation &ei : enumerations)
|
||||
idlEnumerations += new IdlEnumWrapper(ei, this);
|
||||
m_ctx->insert(QStringLiteral("idl_enums"), QVariant::fromValue(idlEnumerations));
|
||||
|
||||
// export the used services with the corresponding idl files
|
||||
exportUsedServices(m_reader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Common
|
||||
CompleteTopicTypeInformation CppTopicGeneratorGrantlee::topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation &tti) const
|
||||
{
|
||||
if (tti.baseValueType.isEmpty())
|
||||
return CompleteTopicTypeInformation();
|
||||
QString baseValueType = tti.baseValueType;
|
||||
// if tti is from another service, baseValue is also from this other service
|
||||
// except it's from another service, then baseValue has '::' in it's name
|
||||
if (tti.name.contains(QLatin1String("::")) &&
|
||||
!tti.baseValueType.contains(QLatin1String("::")))
|
||||
{
|
||||
// Add Service name to baseValueType name
|
||||
const QVector<QStringRef> sl = tti.name.splitRef(QStringLiteral("::"));
|
||||
baseValueType = sl.at(0) + QLatin1String("::") + tti.baseValueType;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "topicTypeInformationByStructName(" << baseValueType << ")";
|
||||
return m_structBuilder->topicTypeInformationByStructType(baseValueType);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate an dtc/dts interface file from idl-struct defined in a xml-file
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2016-01-05
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
|
||||
class CppTopicGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CppTopicGeneratorGrantlee();
|
||||
|
||||
bool init(const XmlReader *reader, StructBuilder *structBuilder) override;
|
||||
|
||||
private:
|
||||
// DataTopics
|
||||
bool initDataTopics();
|
||||
bool getSpecialColumns(const CompleteTopicTypeInformation &tti,
|
||||
QVector<IdlData> &keyColumns,
|
||||
QVector<IdlData> &trColumns) const;
|
||||
// FunctionTopics
|
||||
bool initFunctionTopics();
|
||||
bool handleStruct(const FunctionTopic &ft,
|
||||
FunctionTopicsWrapper *functionTopicsWrapper);
|
||||
bool addRequesterRequestParams(const QString &request_name,
|
||||
const CompleteTopicTypeInformation &request,
|
||||
FunctionTopicWrapper *ftw);
|
||||
bool addRequesterReplyParams(const QString &request_name,
|
||||
const CompleteTopicTypeInformation &reply,
|
||||
FunctionTopicWrapper *ftw);
|
||||
// Idl
|
||||
bool handleIdlStruct(const CompleteTopicTypeInformation &csi,
|
||||
QSet<QString> &idlStructNames,
|
||||
QVector<IdlStructWrapper *> &idlStructs);
|
||||
bool initIdlStructs();
|
||||
// Common
|
||||
CompleteTopicTypeInformation topicTypeInformationByDerivedTopic(const CompleteTopicTypeInformation &tti) const;
|
||||
|
||||
const XmlReader *m_reader = nullptr;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id: DaoGeneratorGrantlee.cpp 50446 2020-03-18 10:29:57Z ehrlicher $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/DaoGeneratorGrantlee.cpp $
|
||||
* $Author: ehrlicher $
|
||||
*/
|
||||
|
||||
#include "DaoGeneratorGrantlee.h"
|
||||
#include "StructBuilder.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <grantlee/context.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
DaoGeneratorGrantlee::DaoGeneratorGrantlee()
|
||||
: GeneratorGrantleeBase("CodeGen.DaoGeneratorGrantlee")
|
||||
{}
|
||||
|
||||
bool DaoGeneratorGrantlee::init(const XmlReader *reader,
|
||||
StructBuilder *structBuilder)
|
||||
{
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
// Is Service exercise-independent?
|
||||
if (reader->isServiceExerciseIndependent())
|
||||
m_ctx->insert(QStringLiteral("isExerciseIndependent"), QLatin1String("1"));
|
||||
|
||||
bool bHasDbNotifications = false;
|
||||
QVector<DbStructWrapper *> vlServiceStructs;
|
||||
QVector<DbStructWrapper *> vlStaticDataStructs;
|
||||
const QVector<CompleteStructInformation> csiData = structBuilder->structInformations();
|
||||
vlServiceStructs.reserve(csiData.size());
|
||||
vlStaticDataStructs.reserve(csiData.size());
|
||||
for (const CompleteStructInformation &csi : csiData)
|
||||
{
|
||||
DbStructWrapper *dbStructWrapper(new DbStructWrapper(csi, this));
|
||||
|
||||
if (csi.hasStaticContent)
|
||||
vlStaticDataStructs += dbStructWrapper;
|
||||
else
|
||||
vlServiceStructs += dbStructWrapper;
|
||||
if (!csi.dbNotifications.isEmpty())
|
||||
bHasDbNotifications = true;
|
||||
}
|
||||
|
||||
if (structBuilder->needPoint3d())
|
||||
m_ctx->insert(QStringLiteral("need_point3d"), QLatin1String("1"));
|
||||
if (structBuilder->needPgArrayInclude())
|
||||
m_ctx->insert(QStringLiteral("need_pgarray"), QLatin1String("1"));
|
||||
m_ctx->insert(QStringLiteral("cpp_structs"), QVariant::fromValue(vlServiceStructs));
|
||||
m_ctx->insert(QStringLiteral("data_structs"), QVariant::fromValue(vlStaticDataStructs));
|
||||
if (bHasDbNotifications)
|
||||
m_ctx->insert(QStringLiteral("has_db_notifications"), QLatin1String("1"));
|
||||
|
||||
m_ctx->insert(QStringLiteral("library_target"), QStringLiteral("COMMON"));
|
||||
|
||||
exportUsedServices(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id: DaoGeneratorGrantlee.h 50446 2020-03-18 10:29:57Z ehrlicher $
|
||||
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/25_02_refactoring/Lts/Common/CodeGen/DaoGeneratorGrantlee.h $
|
||||
* $Author: ehrlicher $
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct CompleteStructInformation;
|
||||
class StructBuilder;
|
||||
class XmlReader;
|
||||
|
||||
|
||||
class DaoGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DaoGeneratorGrantlee();
|
||||
|
||||
bool init(const XmlReader *reader, StructBuilder *structBuilder) override;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
#include "StructBuilder.h"
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <grantlee/context.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
DatabaseGeneratorGrantlee::DatabaseGeneratorGrantlee(bool targetIsServer)
|
||||
: GeneratorGrantleeBase("CodeGen.CppStructGeneratorGrantlee")
|
||||
, m_targetIsServer(targetIsServer)
|
||||
{}
|
||||
|
||||
bool DatabaseGeneratorGrantlee::init(const XmlReader *reader,
|
||||
StructBuilder *structBuilder)
|
||||
{
|
||||
if (!GeneratorGrantleeBase::initInternal(reader, structBuilder))
|
||||
return false;
|
||||
|
||||
// Is Service exercise-independent?
|
||||
if (reader->isServiceExerciseIndependent())
|
||||
m_ctx->insert(QStringLiteral("isExerciseIndependent"), QLatin1String("1"));
|
||||
|
||||
bool bHasDbNotifications = false;
|
||||
QVector<DbStructWrapper *> vlServiceStructs;
|
||||
QVector<DbStructWrapper *> vlStaticDataStructs;
|
||||
const QVector<CompleteStructInformation> csiData = structBuilder->structInformations();
|
||||
vlServiceStructs.reserve(csiData.size());
|
||||
vlStaticDataStructs.reserve(csiData.size());
|
||||
for (const CompleteStructInformation &csi : csiData)
|
||||
{
|
||||
DbStructWrapper *dbStructWrapper(new DbStructWrapper(csi, this));
|
||||
|
||||
if (csi.hasStaticContent)
|
||||
vlStaticDataStructs += dbStructWrapper;
|
||||
else
|
||||
vlServiceStructs += dbStructWrapper;
|
||||
if (!csi.dbNotifications.isEmpty())
|
||||
bHasDbNotifications = true;
|
||||
}
|
||||
addCustomFunctions(reader->getCustomFunctions());
|
||||
|
||||
if (structBuilder->needPoint3d())
|
||||
m_ctx->insert(QStringLiteral("need_point3d"), QLatin1String("1"));
|
||||
if (structBuilder->needPgArrayInclude())
|
||||
m_ctx->insert(QStringLiteral("need_pgarray"), QLatin1String("1"));
|
||||
m_ctx->insert(QStringLiteral("cpp_structs"), QVariant::fromValue(vlServiceStructs));
|
||||
m_ctx->insert(QStringLiteral("data_structs"), QVariant::fromValue(vlStaticDataStructs));
|
||||
if (bHasDbNotifications)
|
||||
m_ctx->insert(QStringLiteral("has_db_notifications"), QLatin1String("1"));
|
||||
|
||||
m_ctx->insert(QStringLiteral("library_target"), m_targetIsServer ? QStringLiteral("SERVER") : QStringLiteral("COMMON"));
|
||||
|
||||
exportUsedServices(reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate cpp structs from xml
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct CompleteStructInformation;
|
||||
class StructBuilder;
|
||||
class XmlReader;
|
||||
|
||||
|
||||
class DatabaseGeneratorGrantlee final : public GeneratorGrantleeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DatabaseGeneratorGrantlee(bool targetIsServer);
|
||||
|
||||
bool init(const XmlReader *reader, StructBuilder *structBuilder) override;
|
||||
private:
|
||||
bool m_targetIsServer;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate enum access functions (static enums, values from xml-file)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "GeneratorGrantleeBase.h"
|
||||
#include "XmlReader.h"
|
||||
#include "GrantleeWrappers.h"
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
#include <QFile>
|
||||
#include <grantlee/context.h>
|
||||
#include <grantlee/engine.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
GeneratorGrantleeBase::GeneratorGrantleeBase(const char *loggerName)
|
||||
: m_engine(new Grantlee::Engine)
|
||||
, m_ctx(new Grantlee::Context)
|
||||
, m_structBuilder(nullptr)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
|
||||
{
|
||||
}
|
||||
|
||||
GeneratorGrantleeBase::~GeneratorGrantleeBase()
|
||||
{
|
||||
delete m_engine;
|
||||
delete m_ctx;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::initInternal(const XmlReader *reader, StructBuilder *structBuilder)
|
||||
{
|
||||
m_structBuilder = structBuilder;
|
||||
|
||||
if (reader)
|
||||
{
|
||||
m_ctx->insert(QStringLiteral("namespace"), reader->getServiceNamespace());
|
||||
m_ctx->insert(QStringLiteral("namespace_abbr"), reader->getServiceAbbr().toLower());
|
||||
m_ctx->insert(QStringLiteral("namespace_abbr_upper"), reader->getServiceAbbr().toUpper());
|
||||
if (reader->getServiceNamespace() == QLatin1String("Core"))
|
||||
m_ctx->insert(QStringLiteral("include_prefix"), QStringLiteral("DDS/%1").arg(reader->getServiceNamespace()));
|
||||
else
|
||||
m_ctx->insert(QStringLiteral("include_prefix"), reader->getServiceNamespace());
|
||||
m_ctx->insert(QStringLiteral("custom_record_replay"), reader->hasCustomRecordReplayPlugin());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::setTemplate(const QString &templateName, const QString &tmpl)
|
||||
{
|
||||
m_template = m_engine->newTemplate(tmpl, QStringLiteral("myTemplate"));
|
||||
if (m_template->error())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error parsing template '" << templateName
|
||||
<< "': " << m_template->errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString GeneratorGrantleeBase::render() const
|
||||
{
|
||||
QString out = m_template->render(m_ctx);
|
||||
QRegExp rx(QLatin1String(";\\n([ ]+\\n)*"));
|
||||
out = out.replace(rx, QStringLiteral(";\n"));
|
||||
return out;
|
||||
}
|
||||
|
||||
QString GeneratorGrantleeBase::errorString() const
|
||||
{
|
||||
return m_template->errorString();
|
||||
}
|
||||
|
||||
|
||||
bool GeneratorGrantleeBase::generateData(const QString &templateName,
|
||||
const QString &outDirectory)
|
||||
{
|
||||
QString content;
|
||||
if (!readFile(templateName, content))
|
||||
return false;
|
||||
if (!setTemplate(templateName, content))
|
||||
return false;
|
||||
|
||||
content = render();
|
||||
|
||||
QString outFilename;
|
||||
if (!getFilenameFromData(content, outFilename))
|
||||
return false;
|
||||
//INFO_LOG(m_logger) << "outfilename: " << outFilename;
|
||||
|
||||
QFile f(outDirectory + QLatin1Char('/') + outFilename);
|
||||
if (!f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << f.fileName() << "' for writing: "
|
||||
<< f.errorString() << "(" << f.error() << ")";
|
||||
return false;
|
||||
}
|
||||
const QByteArray outData = content.toUtf8();
|
||||
f.write(outData);
|
||||
f.close();
|
||||
|
||||
DEBUG_LOG(m_logger) << "Written data to " << f.fileName();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::readFile(const QString &filename, QString &data) const
|
||||
{
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file " << filename
|
||||
<< " - error: " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
data = QString::fromUtf8(f.readAll());
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneratorGrantleeBase::getFilenameFromData(const QString &dataToParse, QString &filename) const
|
||||
{
|
||||
// scan for '// filename:
|
||||
const QString filenameMarker(QStringLiteral("// filename:"));
|
||||
int idx = dataToParse.indexOf(filenameMarker);
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find marker '" << filenameMarker
|
||||
<< "' in data!";
|
||||
return false;
|
||||
}
|
||||
idx += filenameMarker.length() + 1;
|
||||
int endIdx = dataToParse.indexOf(QLatin1Char('\n'), idx);
|
||||
if (endIdx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find end marker '\\n' in data!";
|
||||
return false;
|
||||
}
|
||||
filename = dataToParse.midRef(idx, endIdx - idx).trimmed().toString();
|
||||
//INFO_LOG(m_logger) << "found filename: '" << filename << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeneratorGrantleeBase::addCustomFunctions(const QVector<CustomServiceFunctionInformation> &customFunctions)
|
||||
{
|
||||
// QVector<CustomFunctionWrapper*> - Abnfrage mittels {% if custom_dtc_procs %} geht dann nicht... ?
|
||||
QVariantList vlCustomDbFunctions;
|
||||
QVariantList vlCustomDtcFunctions;
|
||||
vlCustomDbFunctions.reserve(customFunctions.size());
|
||||
vlCustomDtcFunctions.reserve(customFunctions.size());
|
||||
for (const CustomServiceFunctionInformation &csfi : customFunctions)
|
||||
{
|
||||
const QString signature(csfi.returnValue + QLatin1Char(' ') +
|
||||
csfi.methodName + QLatin1Char('(') + csfi.signature + QLatin1Char(')') +
|
||||
(csfi.isConst ? QStringLiteral(" const") : QString()));
|
||||
CustomFunctionWrapper *customFunctionWrapper(new CustomFunctionWrapper(signature, this));
|
||||
switch (csfi.type)
|
||||
{
|
||||
case CustomServiceFunctionInformation::Type::Db:
|
||||
vlCustomDbFunctions += QVariant::fromValue(customFunctionWrapper);
|
||||
break;
|
||||
case CustomServiceFunctionInformation::Type::Dtc:
|
||||
vlCustomDtcFunctions += QVariant::fromValue(customFunctionWrapper);
|
||||
break;
|
||||
case CustomServiceFunctionInformation::Type::DbNotify:
|
||||
// should not occour here - handled in addDbNotifications()
|
||||
WARNING_LOG(m_logger) << "Internal error - Trying to handle DbNotify in addCustomFunctions(): "
|
||||
<< csfi.methodName;
|
||||
delete customFunctionWrapper;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Added custom db function " << csfi.methodName;
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("custom_dtc_procs"), vlCustomDtcFunctions);
|
||||
m_ctx->insert(QStringLiteral("custom_db_procs"), vlCustomDbFunctions);
|
||||
}
|
||||
|
||||
void GeneratorGrantleeBase::exportUsedServices(const XmlReader *reader)
|
||||
{
|
||||
IdlServicesWrapper *idlServicesWrapper(new IdlServicesWrapper(QString(), this));
|
||||
const QMap<QString, bool> usedServices = reader->usedServices();
|
||||
for (auto it = usedServices.begin(); it != usedServices.end(); ++it)
|
||||
{
|
||||
// loaded, but not used
|
||||
if (!it.value())
|
||||
continue;
|
||||
const QString &svc = it.key();
|
||||
const QString fullPath = reader->idlFileForService(svc);
|
||||
const int idx = fullPath.lastIndexOf(QLatin1Char('.'));
|
||||
if (idx < 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not parse file path: " << fullPath;
|
||||
continue;
|
||||
}
|
||||
const QString idlFile = fullPath.left(idx);
|
||||
if (idlFile.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find idl file for service " << svc;
|
||||
continue;
|
||||
}
|
||||
idlServicesWrapper->addService(svc, idlFile);
|
||||
DEBUG_LOG(m_logger) << "Added service " << svc;
|
||||
}
|
||||
m_ctx->insert(QStringLiteral("ext_services"), idlServicesWrapper);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate enum access functions (static enums, values from xml-file)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "codegen_export.h"
|
||||
#include "XmlReader.h"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace Grantlee
|
||||
{
|
||||
class Context;
|
||||
class Engine;
|
||||
class TemplateImpl;
|
||||
using Template = QSharedPointer<TemplateImpl>;
|
||||
}
|
||||
namespace CodeGen
|
||||
{
|
||||
class StructBuilder;
|
||||
|
||||
class GeneratorGrantleeBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~GeneratorGrantleeBase();
|
||||
virtual bool init(const XmlReader *reader, StructBuilder *structBuilder) = 0;
|
||||
bool setTemplate(const QString &templateName, const QString &tmpl);
|
||||
QString render() const;
|
||||
QString errorString() const;
|
||||
bool generateData(const QString &templateName,
|
||||
const QString &outDirectory);
|
||||
|
||||
protected:
|
||||
explicit GeneratorGrantleeBase(const char *loggerName);
|
||||
|
||||
bool initInternal(const XmlReader *reader, StructBuilder *structBuilder);
|
||||
bool readFile(const QString &filename, QString &data) const;
|
||||
bool getFilenameFromData(const QString &dataToParse, QString &filename) const;
|
||||
void addCustomFunctions(const QVector<CustomServiceFunctionInformation> &customFunctions);
|
||||
void exportUsedServices(const XmlReader *reader);
|
||||
protected:
|
||||
Grantlee::Engine *m_engine;
|
||||
Grantlee::Context *m_ctx;
|
||||
Grantlee::Template m_template;
|
||||
StructBuilder *m_structBuilder;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Wrapper-Objects for Grantlee engine
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-04
|
||||
*/
|
||||
|
||||
#include "GrantleeWrappers.h"
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
QString IdlStructWrapper::extensibility2String(dds::core::xtypes::ExtensibilityKind extensiblity)
|
||||
{
|
||||
switch (extensiblity.underlying())
|
||||
{
|
||||
case dds::core::xtypes::ExtensibilityKind_def::FINAL:
|
||||
return QStringLiteral("FINAL_EXTENSIBILITY");
|
||||
case dds::core::xtypes::ExtensibilityKind_def::MUTABLE:
|
||||
return QStringLiteral("MUTABLE_EXTENSIBILITY");
|
||||
case dds::core::xtypes::ExtensibilityKind_def::EXTENSIBLE:
|
||||
return QStringLiteral("EXTENSIBLE_EXTENSIBILITY");
|
||||
}
|
||||
Q_ASSERT_X(false, "IdlStructWrapper::extensibility2String", "Unknown extensiblity kind");
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString DataTopicWrapper::typeFq() const
|
||||
{
|
||||
const QString &t = type();
|
||||
const QString &s = serviceName();
|
||||
if (s.isEmpty())
|
||||
return t;
|
||||
if (t.startsWith(s))
|
||||
return t;
|
||||
return s + QStringLiteral("::") + t;
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::ddsToQVariant() const
|
||||
{
|
||||
return QStringLiteral("toQVariant(data.") + cppMemberName() + QStringLiteral("())");
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::qVariantToDds() const
|
||||
{
|
||||
const QString ddsType = isOptional() ?
|
||||
(QStringLiteral("dds::core::optional<") + cppDdsType() + QLatin1Char('>')) :
|
||||
(cppDdsType());
|
||||
|
||||
return QStringLiteral("data.") + cppMemberName() +
|
||||
QStringLiteral("() = fromQVariant<") + ddsType + QStringLiteral(">(q.value(i++))");
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::ddsToJsonElement() const
|
||||
{
|
||||
// POD
|
||||
// obj[QStringLiteral("inner")] = element;
|
||||
|
||||
// mandatory
|
||||
// obj[QStringLiteral("vulnerabilityState")] = element.vulnerabilityState().underlying();
|
||||
|
||||
// optional
|
||||
// if (element.chargeTypeId().is_set()) obj[QStringLiteral("chargeTypeId")] = element.chargeTypeId().get();
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppType() + QStringLiteral("\")] = element;");
|
||||
|
||||
if (!isOptional())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") +
|
||||
cppToJsonPre() + QStringLiteral("element.") + cppMemberName() + QStringLiteral("()") + cppToJsonPost();
|
||||
|
||||
return QStringLiteral("if (element.") + cppMemberName() + QStringLiteral("().is_set()) ") +
|
||||
QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") +
|
||||
cppToJsonPre() + QStringLiteral("element.") + cppMemberName() + QStringLiteral("().get()") + cppToJsonPost();
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::jsonElementToDds() const
|
||||
{
|
||||
// POD
|
||||
// element = objElement.value(QStringLiteral("inner")).toInt();
|
||||
|
||||
// common (mandatory and optional)
|
||||
// const QJsonValue chargeTypeId(objElement.value(QStringLiteral("chargeTypeId")));
|
||||
|
||||
// mandatory
|
||||
// element.vulnerabilityId(vulnerabilityId.toInt());
|
||||
|
||||
// optional
|
||||
// if (!chargeTypeId.isNull()) element.chargeTypeId(chargeTypeId.toInt());
|
||||
|
||||
// POD?
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("element = ") +
|
||||
cppFromQvPre2() + QStringLiteral("objElement.value(QStringLiteral(\"") + cppType() + QStringLiteral("\"))") + cppFromJsonPost();
|
||||
|
||||
QString ret(QStringLiteral("const QJsonValue val(objElement.value(QStringLiteral(\"") + cppMemberName() + QStringLiteral("\"))); "));
|
||||
if (isOptional())
|
||||
ret += QStringLiteral("if (!val.isNull()) ");
|
||||
|
||||
ret += QStringLiteral("element.") + cppMemberName() + QStringLiteral("(") +
|
||||
cppFromJsonPre2() + QStringLiteral("val") + cppFromJsonPost() + QStringLiteral(")");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::dbToJsonElement() const
|
||||
{
|
||||
// POD
|
||||
// obj[QStringLiteral("inner")] = element;
|
||||
|
||||
// mandatory
|
||||
// obj[QStringLiteral("vulnerabilityId")] = element.vulnerabilityId.toInt());
|
||||
|
||||
// optional
|
||||
// if (!element.chargeTypeId.isNull()) obj[QStringLiteral("chargeTypeId")] = element.chargeTypeId().toInt();
|
||||
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppType() + QStringLiteral("\")] = element;");
|
||||
|
||||
if (isOptional() || cppType() == QStringLiteral("QDateTime"))
|
||||
{
|
||||
QString ret = QStringLiteral("if (") + ((cppType() == QStringLiteral("QDateTime")) ? QString() : QStringLiteral("!")) +
|
||||
QStringLiteral("element.") + cppMemberName() +
|
||||
((cppType() == QStringLiteral("QDateTime")) ? QStringLiteral(".isValid()) ") : QStringLiteral(".isNull()) ")) +
|
||||
QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ");
|
||||
if (isOptional())
|
||||
return ret += cppFromQvPre2() + QStringLiteral("element.") + cppMemberName() + cppFromQvPost();
|
||||
}
|
||||
|
||||
return QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") +
|
||||
cppToJsonPre() + QStringLiteral("element.") + cppMemberName() + cppToJsonPost();
|
||||
}
|
||||
|
||||
QString MemberInformationWrapper::jsonElementToDb() const
|
||||
{
|
||||
// POD
|
||||
// element = objElement.value(QStringLiteral("inner")).toInt();
|
||||
|
||||
// common (mandatory and optional)
|
||||
// const QJsonValue val(objElement.value(QStringLiteral("chargeTypeId")));
|
||||
|
||||
// mandatory
|
||||
// element.vulnerabilityId = (val.toInt());
|
||||
|
||||
// optional
|
||||
// if (!chargeTypeId.isNull()) element.chargeTypeId(chargeTypeId.toInt());
|
||||
|
||||
// POD?
|
||||
if (cppMemberName().isEmpty())
|
||||
return QStringLiteral("element = ") +
|
||||
cppFromQvPre2() + QStringLiteral("objElement.value(QStringLiteral(\"") + cppType() + QStringLiteral("\"))") + cppFromJsonPost();
|
||||
|
||||
QString ret(QStringLiteral("const QJsonValue val(objElement.value(QStringLiteral(\"") + cppMemberName() + QStringLiteral("\"))); "));
|
||||
if (isOptional())
|
||||
ret += QStringLiteral("if (!val.isUndefined()) ");
|
||||
|
||||
ret += QStringLiteral("element.") + cppMemberName() + QStringLiteral(" = ") +
|
||||
cppFromJsonPre2() + QStringLiteral("val") + cppFromJsonPost();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantList DbStructWrapper::insertStructures()
|
||||
{
|
||||
// todo: only buildup once
|
||||
QStringList tableNames; // must be sorted
|
||||
QMap<QString, QVector<MemberInformationWrapper *>> structures;
|
||||
QMap<QString, MemberInformationWrapper *> primaryKeys;
|
||||
QMap<QString, MemberInformationWrapper *> fkComplexTableKeys;
|
||||
// silce clazy...
|
||||
tableNames.reserve(5);
|
||||
for (const QVariant &v : qAsConst(m_member))
|
||||
{
|
||||
MemberInformationWrapper *mi = v.value<MemberInformationWrapper *>();
|
||||
const QString &tableName = mi->info().db.table;
|
||||
if (mi->info().db.usedForInsert)
|
||||
{
|
||||
auto &tnStructure = structures[tableName];
|
||||
tnStructure.append(mi);
|
||||
if (!tableNames.contains(tableName))
|
||||
tableNames.push_back(tableName);
|
||||
}
|
||||
if (mi->info().fk)
|
||||
fkComplexTableKeys[mi->info().fk->destination.tableName] = mi;
|
||||
if (mi->info().db.isPrimaryKey)
|
||||
{
|
||||
if (!primaryKeys.contains(tableName))
|
||||
primaryKeys[tableName] = mi;
|
||||
}
|
||||
if (mi->info().db.isAssignmentForPrimaryTablePk)
|
||||
fkComplexTableKeys[mi->info().db.table] = mi;
|
||||
}
|
||||
/*
|
||||
* When a dbstruct is built from more than one table, we need to propagate
|
||||
* the sequence ids from the base to the derived class:
|
||||
* ppm_aggregate_entity : ppm_participant : ppm_entity
|
||||
* ppm_participant.entity_id = ppm_entity.id
|
||||
* ppm_aggregate_entity.participant_id = ppm_participant.id
|
||||
* In the resulting structure we've 4 members:
|
||||
* id -> ppm_entity.id
|
||||
* entity_id -> ppm_entity.id
|
||||
* participant_id -> ppm_participant.id
|
||||
* aggregate_entity_id -> ppm_aggregate_entity.id
|
||||
* Therefore we have to know the pk and corresponding fk in the single tables
|
||||
*/
|
||||
QVariantList vl;
|
||||
vl.reserve(tableNames.size());
|
||||
for (int i = 0; i < tableNames.size(); ++i)
|
||||
{
|
||||
const QString &tn = tableNames.at(i);
|
||||
MemberInformationWrapper *serialMember = fkComplexTableKeys.value(tn);
|
||||
MemberInformationWrapper *baseId = nullptr;
|
||||
MemberInformationWrapper *primaryKey = primaryKeys.value(tn);
|
||||
if (i == 0 && tableNames.size() > 1)
|
||||
baseId = primaryKeys.value(tn);
|
||||
|
||||
// for structs with one table, all three MemberInformationWrapper - ptr
|
||||
// are equal
|
||||
if (tableNames.size() == 1)
|
||||
{
|
||||
baseId = nullptr; // should be null - otherwise we generate two assignments with the same values which is superfluous
|
||||
// there are also primary keys without a serial on it
|
||||
if (!primaryKey)
|
||||
{
|
||||
NGL::INGLLogger &logger = NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("DbStructWrapper");
|
||||
WARNING_LOG(logger) << "Table " << tn << " has no primary key!";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (primaryKey->dbHasSequence())
|
||||
serialMember = primaryKey;
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<MemberInformationWrapper *> members = structures.value(tn);
|
||||
TableWrapper *tw = new TableWrapper(tn, members, serialMember, baseId, primaryKey, this);
|
||||
vl += QVariant::fromValue(tw);
|
||||
}
|
||||
|
||||
return vl;
|
||||
}
|
||||
@@ -0,0 +1,649 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Wrapper-Objects for Grantlee engine
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-04
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include "StructBuilder.h"
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class NameWrapper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ name)
|
||||
Q_PROPERTY(QString nameCc READ nameCc)
|
||||
Q_PROPERTY(QString nameFlc READ nameFlc)
|
||||
public:
|
||||
NameWrapper(const QString &name, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_name(name)
|
||||
{}
|
||||
|
||||
QString name() const { return m_name; }
|
||||
QString nameCc() const { return StructBuilder::camelCaseString(name(), true); }
|
||||
QString nameFlc() const { return StructBuilder::firstCharLowercase(nameCc()); }
|
||||
private:
|
||||
const QString m_name;
|
||||
};
|
||||
|
||||
class VariantListWrapper : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList member READ member)
|
||||
public:
|
||||
|
||||
using NameWrapper::NameWrapper;
|
||||
~VariantListWrapper()
|
||||
{
|
||||
for (const QVariant &v : qAsConst(m_member))
|
||||
{
|
||||
auto ptr = v.value<QObject *>();
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList member() const { return m_member; }
|
||||
protected:
|
||||
QVariantList m_member;
|
||||
};
|
||||
|
||||
// DB specific wrapper
|
||||
class MemberInformationWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString cppMemberName READ cppMemberName)
|
||||
Q_PROPERTY(QString cppMemberNameCc READ cppMemberNameCc)
|
||||
Q_PROPERTY(QString cppStructName READ cppStructName)
|
||||
Q_PROPERTY(QString cppType READ cppType)
|
||||
Q_PROPERTY(QString cppToQvPre READ cppToQvPre)
|
||||
Q_PROPERTY(QString cppToQvPost READ cppToQvPost)
|
||||
Q_PROPERTY(QString cppFromQvPre1 READ cppFromQvPre1)
|
||||
Q_PROPERTY(QString cppFromQvPre2 READ cppFromQvPre2)
|
||||
Q_PROPERTY(QString cppFromQvPost READ cppFromQvPost)
|
||||
Q_PROPERTY(QString cppDefault READ cppDefault)
|
||||
Q_PROPERTY(QString dbTableName READ dbTableName)
|
||||
Q_PROPERTY(QString dbColumnName READ dbColumnName)
|
||||
Q_PROPERTY(QString dbColumnNameView READ dbColumnNameView)
|
||||
Q_PROPERTY(QString ddsToQVariant READ ddsToQVariant)
|
||||
Q_PROPERTY(QString qVariantToDds READ qVariantToDds)
|
||||
Q_PROPERTY(QString ddsToJsonElement READ ddsToJsonElement)
|
||||
Q_PROPERTY(QString jsonElementToDds READ jsonElementToDds)
|
||||
Q_PROPERTY(QString dbToJsonElement READ dbToJsonElement)
|
||||
Q_PROPERTY(QString jsonElementToDb READ jsonElementToDb)
|
||||
Q_PROPERTY(bool dbHasSequence READ dbHasSequence)
|
||||
Q_PROPERTY(bool isOptional READ isOptional)
|
||||
public:
|
||||
MemberInformationWrapper(const MemberInformation &mi, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mi(mi)
|
||||
{}
|
||||
|
||||
QString cppMemberName() const { return m_mi.cpp.memberName; }
|
||||
QString cppMemberNameCc() const { return StructBuilder::camelCaseString(m_mi.cpp.memberName, true); }
|
||||
QString cppStructName() const { return m_mi.cpp.structName; }
|
||||
QString cppType() const { return m_mi.cpp.type; }
|
||||
QString cppToQvPre() const { return m_mi.cpp.toVariantPre; }
|
||||
QString cppToQvPost() const { return m_mi.cpp.toVariantPost; }
|
||||
QString cppFromQvPre1() const { return m_mi.cpp.fromVariantPre1; }
|
||||
QString cppFromQvPre2() const { return m_mi.cpp.fromVariantPre2; }
|
||||
QString cppFromQvPost() const { return m_mi.cpp.fromVariantPost; }
|
||||
QString cppDefault() const { return m_mi.cpp.defaultValue; }
|
||||
QString dbTableName() const { return m_mi.db.table; }
|
||||
QString dbColumnName() const { return m_mi.db.columnName; }
|
||||
QString dbColumnNameView() const { return m_mi.db.getColumnNameView(); }
|
||||
QString cppDdsType() const { return m_mi.cpp.ddsType.isEmpty() ? cppType() : m_mi.cpp.ddsType; }
|
||||
QString ddsToQVariant() const; // dds type to QVariant (used vars: data)
|
||||
QString qVariantToDds() const; // QVariant to dds type (used vars: data, q, i)
|
||||
QString ddsToJsonElement() const; // dds type to json (used vars: obj, element)
|
||||
QString jsonElementToDds() const; // json to dds type (used vars: objElement, element)
|
||||
QString dbToJsonElement() const; // db struct to json (used vars: dbStruct, element)
|
||||
QString jsonElementToDb() const; // json to db struct (used vars: objElement, element)
|
||||
bool dbHasSequence() const { return m_mi.db.hasSequence; }
|
||||
bool isOptional() const { return m_mi.cpp.isOptional; }
|
||||
|
||||
// only internally used
|
||||
QString cppToJsonPre() const { return m_mi.cpp.toJsonPre.isNull() ? m_mi.cpp.toVariantPre : m_mi.cpp.toJsonPre; }
|
||||
QString cppToJsonPost() const { return m_mi.cpp.toJsonPost.isNull() ? m_mi.cpp.toVariantPost : m_mi.cpp.toJsonPost; }
|
||||
QString cppFromJsonPre2() const { return m_mi.cpp.fromJsonPre2.isNull() ? m_mi.cpp.fromVariantPre2: m_mi.cpp.fromJsonPre2; }
|
||||
QString cppFromJsonPost() const { return m_mi.cpp.fromJsonPost.isNull() ? m_mi.cpp.fromVariantPost : m_mi.cpp.fromJsonPost; }
|
||||
|
||||
MemberInformation info() const
|
||||
{
|
||||
return m_mi;
|
||||
}
|
||||
private:
|
||||
const MemberInformation m_mi;
|
||||
};
|
||||
|
||||
class MemberInformationListWrapper : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList cppMember READ cppMember)
|
||||
Q_PROPERTY(QVariantList jsonMember READ jsonMember)
|
||||
Q_PROPERTY(QVariantList fkMember READ fkMember)
|
||||
Q_PROPERTY(QVariantList selectRemoveMember READ selectRemoveMember)
|
||||
Q_PROPERTY(QVariantList viewMember READ viewMember)
|
||||
Q_PROPERTY(MemberInformationWrapper *ddsKey READ ddsKey)
|
||||
Q_PROPERTY(MemberInformationWrapper *primaryKey READ primaryKey)
|
||||
public:
|
||||
explicit MemberInformationListWrapper(const QString &name, const QVector<MemberInformation> &member, QObject *parent)
|
||||
: VariantListWrapper(name, parent)
|
||||
{
|
||||
for (const MemberInformation &mi : member)
|
||||
m_member += QVariant::fromValue(new MemberInformationWrapper(mi, this));
|
||||
}
|
||||
// getters
|
||||
QVariantList memberByFilter(const std::function<bool(const MemberInformation &mi)> &acceptFilter) const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
MemberInformationWrapper *mi = v.value<MemberInformationWrapper *>();
|
||||
if (mi && acceptFilter(mi->info()))
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
|
||||
QVariantList cppMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation &mi) { return mi.cpp.usedForCppStruct; });
|
||||
}
|
||||
QVariantList jsonMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation &mi) { return mi.cpp.usedForJson; });
|
||||
}
|
||||
QVariantList fkMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation &mi) { return mi.db.isForeignKey; });
|
||||
}
|
||||
QVariantList selectRemoveMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation &mi) { return mi.db.generateSelectRemove; });
|
||||
}
|
||||
QVariantList viewMember() const
|
||||
{
|
||||
return memberByFilter([](const MemberInformation &mi) { return mi.db.usedForView; });
|
||||
}
|
||||
MemberInformationWrapper *ddsKey() const
|
||||
{
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
MemberInformationWrapper *mi = v.value<MemberInformationWrapper *>();
|
||||
if (mi->info().isDdsKey)
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
MemberInformationWrapper *primaryKey() const
|
||||
{
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
MemberInformationWrapper *mi = v.value<MemberInformationWrapper *>();
|
||||
if (mi->info().db.isPrimaryKey)
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TableWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVector<MemberInformationWrapper *> member READ member)
|
||||
// for insert: data.fooId = m_query->lastInsertId().toFoo();
|
||||
Q_PROPERTY(MemberInformationWrapper *serialMember READ serialMember)
|
||||
// for insert: data.id = m_query->lastInsertId().toFoo();
|
||||
// -> may be different to serialMember when more than one table is involved
|
||||
Q_PROPERTY(MemberInformationWrapper *baseId READ baseId)
|
||||
// for update: m_query->bindValue(QLatin1String(":id"), data.fooId)
|
||||
Q_PROPERTY(MemberInformationWrapper *primaryKey READ primaryKey)
|
||||
public:
|
||||
// does not take ownership!
|
||||
explicit TableWrapper(const QString &name,
|
||||
const QVector<MemberInformationWrapper *> &member,
|
||||
MemberInformationWrapper *serialMember,
|
||||
MemberInformationWrapper *baseId,
|
||||
MemberInformationWrapper *primaryKey,
|
||||
QObject *parent)
|
||||
: NameWrapper(name, parent)
|
||||
, m_member(member)
|
||||
, m_serialMember(serialMember)
|
||||
, m_baseId(baseId)
|
||||
, m_primaryKey(primaryKey)
|
||||
{}
|
||||
|
||||
QVector<MemberInformationWrapper *> member() const { return m_member; }
|
||||
MemberInformationWrapper *serialMember() const { return m_serialMember; }
|
||||
MemberInformationWrapper *baseId() const { return m_baseId; }
|
||||
MemberInformationWrapper *primaryKey() const { return m_primaryKey; }
|
||||
|
||||
private:
|
||||
QVector<MemberInformationWrapper *> m_member;
|
||||
MemberInformationWrapper *m_serialMember;
|
||||
MemberInformationWrapper *m_baseId;
|
||||
MemberInformationWrapper *m_primaryKey;
|
||||
};
|
||||
|
||||
class DbStructWrapper final : public MemberInformationListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantList insertStructures READ insertStructures)
|
||||
Q_PROPERTY(QString viewTableName READ viewTableName)
|
||||
Q_PROPERTY(bool deleteWithoutPkAllowed READ deleteWithoutPkAllowed)
|
||||
Q_PROPERTY(MemberInformationWrapper *primaryKey READ primaryKey)
|
||||
Q_PROPERTY(QVariantList dbNotifications READ dbNotifications)
|
||||
|
||||
public:
|
||||
explicit DbStructWrapper(const CompleteStructInformation &csi, QObject *parent)
|
||||
: MemberInformationListWrapper(csi.structName, csi.member, parent)
|
||||
, m_csi(csi)
|
||||
{
|
||||
m_dbNotifications.reserve(m_csi.dbNotifications.size());
|
||||
for (const auto ¬ification : qAsConst(m_csi.dbNotifications))
|
||||
m_dbNotifications += QVariant(notification.methodName);
|
||||
}
|
||||
|
||||
MemberInformationWrapper *primaryKey() const
|
||||
{
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
MemberInformationWrapper *mi = v.value<MemberInformationWrapper *>();
|
||||
if (mi->info().db.isPrimaryKey && mi->info().db.table == primaryTableName())
|
||||
return mi;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
QVariantList insertStructures();
|
||||
|
||||
bool deleteWithoutPkAllowed() const { return m_csi.tables.size() == 1; }
|
||||
QVariantList dbNotifications() const { return m_dbNotifications; }
|
||||
QString primaryTableName() const { return m_csi.primaryTable->name; }
|
||||
QString viewTableName() const { return (m_csi.tables.size() == 1) ? primaryTableName() : m_csi.viewName; }
|
||||
private:
|
||||
const CompleteStructInformation m_csi;
|
||||
QVariantList m_dbNotifications;
|
||||
};
|
||||
|
||||
class CustomFunctionWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString signature READ signature)
|
||||
public:
|
||||
explicit CustomFunctionWrapper(const QString &signature, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_signature(signature)
|
||||
{}
|
||||
QString signature() const { return m_signature; }
|
||||
private:
|
||||
const QString m_signature;
|
||||
};
|
||||
|
||||
// IDL / DDS specific wrapper
|
||||
class IdlEnumKeyValueWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString key READ key)
|
||||
Q_PROPERTY(int value READ value)
|
||||
public:
|
||||
explicit IdlEnumKeyValueWrapper(const EnumKeyValuePair &ekvp, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_ekvp(ekvp)
|
||||
{}
|
||||
|
||||
QString key() const { return m_ekvp.key; }
|
||||
int value() const { return m_ekvp.value; }
|
||||
|
||||
private:
|
||||
const EnumKeyValuePair m_ekvp;
|
||||
};
|
||||
|
||||
class IdlDataWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString type READ type)
|
||||
Q_PROPERTY(QString comment READ comment)
|
||||
Q_PROPERTY(QString isKey READ isKey)
|
||||
Q_PROPERTY(QString isOptional READ isOptional)
|
||||
Q_PROPERTY(QString cppType READ cppType)
|
||||
Q_PROPERTY(QString cppTypeCr READ cppTypeCr)
|
||||
Q_PROPERTY(QString nameGetter READ nameGetter)
|
||||
public:
|
||||
IdlDataWrapper(const IdlData &data,
|
||||
QObject *parent)
|
||||
: NameWrapper(data.name, parent)
|
||||
, m_data(data)
|
||||
{}
|
||||
|
||||
QString type() const { return m_data.dataTypeInfo->idlType(); }
|
||||
QString comment() const { return m_data.comment; }
|
||||
QString isKey() const { return m_data.isKey ? QStringLiteral(" \t //@key") : QString(); }
|
||||
QString isOptional() const { return m_data.isOptional ? QStringLiteral(" \t //@Optional") : QString(); }
|
||||
QString cppType() const { return m_data.dataTypeInfo->cppType(); }
|
||||
QString cppTypeCr() const { return m_data.dataTypeInfo->cppTypeConstRef(); }
|
||||
QString nameGetter() const { return m_data.name + (m_data.isOptional ? QStringLiteral("().get") : QString()); }
|
||||
private:
|
||||
const IdlData m_data;
|
||||
};
|
||||
|
||||
class IdlEnumWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IdlEnumWrapper(const EnumInformation &ei, QObject *parent)
|
||||
: VariantListWrapper(ei.enumName, parent)
|
||||
{
|
||||
m_member.reserve(ei.values.size());
|
||||
for (const auto &val : ei.values)
|
||||
m_member += QVariant::fromValue(new IdlEnumKeyValueWrapper(val, this));
|
||||
}
|
||||
};
|
||||
|
||||
class IdlStructWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString comment READ comment)
|
||||
Q_PROPERTY(QString baseValueType READ baseValueType)
|
||||
Q_PROPERTY(QString extensibility READ extensibility)
|
||||
public:
|
||||
explicit IdlStructWrapper(const CompleteTopicTypeInformation &ctti, QObject *parent)
|
||||
: VariantListWrapper(ctti.name, parent)
|
||||
, m_ctti(ctti)
|
||||
{
|
||||
m_member.reserve(m_ctti.members.size());
|
||||
for (const auto &val : qAsConst(m_ctti.members))
|
||||
m_member += QVariant::fromValue(new IdlDataWrapper(val, this));
|
||||
}
|
||||
|
||||
QString comment() const { return m_ctti.comment; }
|
||||
QString baseValueType() const { return m_ctti.baseValueType; }
|
||||
QString extensibility() const { return extensibility2String(m_ctti.extensibility); }
|
||||
|
||||
private:
|
||||
const CompleteTopicTypeInformation m_ctti;
|
||||
static QString extensibility2String(dds::core::xtypes::ExtensibilityKind extensiblity);
|
||||
};
|
||||
|
||||
class IdlServiceWrapper final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString svcName READ svcName)
|
||||
Q_PROPERTY(QString baseFilePath READ baseFilePath)
|
||||
public:
|
||||
IdlServiceWrapper(const QString &svcName, const QString &baseFilePath)
|
||||
: m_svcName(svcName)
|
||||
, m_baseFilePath(baseFilePath)
|
||||
{}
|
||||
QString svcName() const { return m_svcName; }
|
||||
QString baseFilePath() const { return m_baseFilePath; }
|
||||
private:
|
||||
const QString m_svcName;
|
||||
const QString m_baseFilePath;
|
||||
};
|
||||
|
||||
class FunctionTopicWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString onReply READ onReply)
|
||||
Q_PROPERTY(QString onRequest READ onRequest)
|
||||
Q_PROPERTY(QString onError READ onError)
|
||||
Q_PROPERTY(bool isCoreFt READ isCoreFt)
|
||||
Q_PROPERTY(bool routeInReplay READ routeInReplay)
|
||||
|
||||
Q_PROPERTY(QString reply READ reply)
|
||||
Q_PROPERTY(QString replyFlc READ replyFlc)
|
||||
Q_PROPERTY(QString replyHandler READ replyHandler)
|
||||
Q_PROPERTY(QString replyHandlerFlc READ replyHandlerFlc)
|
||||
Q_PROPERTY(QString replyType READ replyType)
|
||||
Q_PROPERTY(QString replyTypeFro READ replyTypeFro)
|
||||
Q_PROPERTY(QVariantList replyParams READ replyParams)
|
||||
Q_PROPERTY(QString replyHandlerHash READ replyHandlerHash WRITE setReplyHandlerHash)
|
||||
|
||||
Q_PROPERTY(QString request READ request)
|
||||
Q_PROPERTY(QString requestFlc READ requestFlc)
|
||||
Q_PROPERTY(QString requestHandler READ requestHandler)
|
||||
Q_PROPERTY(QString requestHandlerFlc READ requestHandlerFlc)
|
||||
Q_PROPERTY(QString requestType READ requestType)
|
||||
Q_PROPERTY(QVariantList requestParams READ requestParams)
|
||||
|
||||
public:
|
||||
FunctionTopicWrapper(const FunctionTopic &ft,
|
||||
const CompleteTopicTypeInformation &siRequest,
|
||||
const CompleteTopicTypeInformation &siReply,
|
||||
QObject *parent)
|
||||
: NameWrapper(ft.name, parent)
|
||||
, m_ft(ft)
|
||||
, m_request(siRequest)
|
||||
, m_reply(siReply)
|
||||
{}
|
||||
QString onReply() const { return QLatin1String("on") + m_ft.replyTopicName; }
|
||||
QString onRequest() const { return QLatin1String("on") + m_ft.requestTopicName; }
|
||||
QString onError() const { return QLatin1String("on") + m_ft.name + QLatin1String("Error"); }
|
||||
bool isCoreFt() const { return (m_ft.replyTopicType == QStringLiteral("Core::FunctionReply") || m_ft.replyTopicType == QStringLiteral("FunctionReply")); }
|
||||
bool routeInReplay() const { return m_ft.routeInReplay; }
|
||||
|
||||
QString reply() const { return m_ft.replyTopicName; }
|
||||
QString replyFlc() const { return StructBuilder::firstCharLowercase(reply()); }
|
||||
QString replyHandler() const { return m_ft.replyTopicName + QLatin1String("Handler"); }
|
||||
QString replyHandlerFlc() const { return StructBuilder::firstCharLowercase(replyHandler()); }
|
||||
QString replyType() const { return m_reply.name; }
|
||||
QString replyTypeFro() const { return isCoreFt() ? QStringLiteral("Core::FunctionReplyObject") : m_reply.name; }
|
||||
|
||||
QString request() const { return m_ft.requestTopicName; }
|
||||
QString requestFlc() const { return StructBuilder::firstCharLowercase(request()); }
|
||||
QString requestHandler() const { return m_ft.requestTopicName + QLatin1String("Handler"); }
|
||||
QString requestHandlerFlc() const { return StructBuilder::firstCharLowercase(requestHandler()); }
|
||||
QString requestType() const { return m_request.name; }
|
||||
|
||||
void addRequestParams(const QVector<IdlData> ¶ms)
|
||||
{
|
||||
for (const auto ¶m : params)
|
||||
m_requestParams.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
QVariantList requestParams() const
|
||||
{
|
||||
return m_requestParams;
|
||||
}
|
||||
void addReplyParams(const QVector<IdlData> ¶ms)
|
||||
{
|
||||
for (const auto ¶m : params)
|
||||
m_replyParams.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
QVariantList replyParams() const
|
||||
{
|
||||
return m_replyParams;
|
||||
}
|
||||
|
||||
QString replyHandlerHash() const
|
||||
{
|
||||
return m_replyHandlerHash;
|
||||
}
|
||||
void setReplyHandlerHash(const QString &hash)
|
||||
{
|
||||
m_replyHandlerHash = hash;
|
||||
}
|
||||
|
||||
private:
|
||||
const FunctionTopic m_ft;
|
||||
const CompleteTopicTypeInformation m_request;
|
||||
const CompleteTopicTypeInformation m_reply;
|
||||
QVariantList m_requestParams;
|
||||
QVariantList m_replyParams;
|
||||
QString m_replyHandlerHash;
|
||||
};
|
||||
|
||||
class FunctionTopicsWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QVariantList topicsToRouteInReplay READ topicsToRouteInReplay)
|
||||
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
FunctionTopicWrapper *addFunctionTopic(const FunctionTopic &ft,
|
||||
const CompleteTopicTypeInformation &siRequest,
|
||||
const CompleteTopicTypeInformation &siReply)
|
||||
{
|
||||
FunctionTopicWrapper *ret = new FunctionTopicWrapper(ft, siRequest, siReply, this);
|
||||
m_member += QVariant::fromValue(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// getters
|
||||
QVariantList topicsToRouteInReplay() const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
FunctionTopicWrapper *ft = v.value<FunctionTopicWrapper *>();
|
||||
if (ft->routeInReplay())
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
};
|
||||
|
||||
class DataTopicWrapper final : public NameWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString serviceName READ serviceName)
|
||||
Q_PROPERTY(QString type READ type)
|
||||
Q_PROPERTY(QString typeFq READ typeFq)
|
||||
Q_PROPERTY(QVariant key READ key)
|
||||
Q_PROPERTY(bool dtcImpl READ dtcImpl)
|
||||
Q_PROPERTY(bool dtsImpl READ dtsImpl)
|
||||
Q_PROPERTY(bool recordTopic READ recordTopic)
|
||||
Q_PROPERTY(QVariant recTable READ recTable)
|
||||
Q_PROPERTY(QVariantList trColumns READ trColumns)
|
||||
Q_PROPERTY(bool hasTrColumns READ hasTrColumns)
|
||||
Q_PROPERTY(bool routeToClient READ routeToClient)
|
||||
Q_PROPERTY(bool routeToServer READ routeToServer)
|
||||
Q_PROPERTY(bool routeInReplay READ routeInReplay)
|
||||
Q_PROPERTY(bool autosubscribe READ isAutoSubscribe)
|
||||
|
||||
public:
|
||||
DataTopicWrapper(const CompleteTopicTypeInformation &ctti, QObject *parent)
|
||||
: NameWrapper(ctti.name, parent)
|
||||
, m_ctti(ctti)
|
||||
, m_keyData(nullptr)
|
||||
, m_recordData(nullptr)
|
||||
{}
|
||||
|
||||
void setKeyColumnData(const IdlData &data)
|
||||
{
|
||||
delete m_keyData;
|
||||
m_keyData = new IdlDataWrapper(data, this);
|
||||
}
|
||||
|
||||
void setTrColumns(const QVector<IdlData> ¶ms)
|
||||
{
|
||||
for (const auto ¶m : params)
|
||||
m_trColumns.push_back(QVariant::fromValue(new IdlDataWrapper(param, this)));
|
||||
}
|
||||
|
||||
QVariantList trColumns() const
|
||||
{
|
||||
return m_trColumns;
|
||||
}
|
||||
|
||||
bool hasTrColumns() const
|
||||
{
|
||||
return !m_trColumns.empty();
|
||||
}
|
||||
|
||||
void setRecordTableInformation(const CompleteTableInformation &cti)
|
||||
{
|
||||
delete m_recordData;
|
||||
m_recordData = new MemberInformationListWrapper(cti.name, cti.columns, this);
|
||||
m_ctti.recordTopic = true; // mhhh
|
||||
}
|
||||
|
||||
QString serviceName() const { return m_ctti.serviceName; }
|
||||
QString type() const { return m_ctti.name; }
|
||||
QString typeFq() const;
|
||||
QVariant key() const { return m_keyData ? QVariant::fromValue(m_keyData) : QVariant(); }
|
||||
bool dtsImpl() const { return m_ctti.dtsAutogen; }
|
||||
bool dtcImpl() const { return m_ctti.dtcAutogen; }
|
||||
bool recordTopic() const { return m_ctti.recordTopic && m_recordData; }
|
||||
bool routeToClient() const { return m_ctti.routeToClient; }
|
||||
bool routeToServer() const { return m_ctti.routeToServer; }
|
||||
bool routeInReplay() const { return m_ctti.routeInReplay; }
|
||||
bool isAutoSubscribe() const { return m_ctti.autosubscribe; }
|
||||
QVariant recTable() const { return recordTopic() ? QVariant::fromValue(m_recordData) : QVariant(); }
|
||||
private:
|
||||
CompleteTopicTypeInformation m_ctti;
|
||||
IdlDataWrapper *m_keyData;
|
||||
MemberInformationListWrapper *m_recordData;
|
||||
QVariantList m_trColumns;
|
||||
};
|
||||
|
||||
class DataTopicsWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QVariantList topicsToRouteInReplay READ topicsToRouteInReplay)
|
||||
Q_PROPERTY(QVariantList topicsToRouteToClient READ topicsToRouteToClient)
|
||||
Q_PROPERTY(QVariantList topicsToRouteToServer READ topicsToRouteToServer)
|
||||
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
DataTopicWrapper *addDataTopic(const CompleteTopicTypeInformation &ctti)
|
||||
{
|
||||
DataTopicWrapper *ret = new DataTopicWrapper(ctti, this);
|
||||
m_member += QVariant::fromValue(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// getters
|
||||
QVariantList memberByFilter(const std::function<bool(const DataTopicWrapper *dtw)> &acceptFilter) const
|
||||
{
|
||||
QVariantList vl;
|
||||
vl.reserve(m_member.size());
|
||||
for (const QVariant &v : m_member)
|
||||
{
|
||||
DataTopicWrapper *dtw = v.value<DataTopicWrapper *>();
|
||||
if (dtw && acceptFilter(dtw))
|
||||
vl += v;
|
||||
}
|
||||
return vl;
|
||||
}
|
||||
|
||||
QVariantList topicsToRouteInReplay() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper *dtw) { return dtw->routeInReplay(); });
|
||||
}
|
||||
QVariantList topicsToRouteToClient() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper *dtw) { return dtw->routeToClient(); });
|
||||
}
|
||||
QVariantList topicsToRouteToServer() const
|
||||
{
|
||||
return memberByFilter([](const DataTopicWrapper *dtw) { return dtw->routeToServer(); });
|
||||
}
|
||||
};
|
||||
|
||||
class IdlServicesWrapper final : public VariantListWrapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using VariantListWrapper::VariantListWrapper;
|
||||
|
||||
void addService(const QString &svcName, const QString &baseFilePath)
|
||||
{
|
||||
m_member += QVariant::fromValue(new IdlServiceWrapper(svcName, baseFilePath));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# Hinweise für den CodeGen
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
Erstellt: Mai 2022, Norbert Thoden
|
||||
|
||||
Der Aufruf des CodeGen kann z.B. so aussehen:
|
||||
|
||||
codegen -s /tmp/ppm_serviceORG.xml -i /shd/CTC/TOOLS/TDS/TDS-build/service_idl_files.txt -a dds_topics -o /tmp /shd/CTC/TOOLS/TDS/TDS-source/Lts/Common/CodeGen/svc_record_replay_plugin.cpp.grantlee
|
||||
Edit Juni 2023, Niklas Schmidt
|
||||
|
||||
Ebenso ist es nicht möglich einen Struct aus einem anderen Service(Service B) zu verwenden,
|
||||
der in sich widerum einen anderen Struct aus dem anderen Service (Service B) beinhaltet.
|
||||
|
||||
Bsp:
|
||||
|
||||
Service A = Struct1{ int id,
|
||||
Struct2 test
|
||||
}
|
||||
|
||||
Service B = Struct2{
|
||||
int id2,
|
||||
Struct3 test
|
||||
}
|
||||
|
||||
Service B = Struct3{
|
||||
std::string test
|
||||
}
|
||||
|
||||
Mögliche Diagnose:
|
||||
|
||||
Wenn Struct3 aus Service A aufgerufen wird, ist wahrscheinlich nicht mehr gekennzeichnet dass der Struct3 aus Service B kommt. Dieser kann somit nicht
|
||||
aufgelöst werden
|
||||
@@ -0,0 +1,948 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate SQL statements from Xml service files
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "SqlGenerator.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QStringList>
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
// to avoid dependency to ngldb
|
||||
static QString getExerciseSchemaName(int exerciseId)
|
||||
{
|
||||
return QStringLiteral("ex_") + QString::number(exerciseId);
|
||||
}
|
||||
|
||||
SqlGenerator::SqlGenerator(XmlReader *xmlReader, StructBuilder *structBuilder)
|
||||
: m_xmlReader(xmlReader)
|
||||
, m_structBuilder(structBuilder)
|
||||
, m_createdByXmlFile(false)
|
||||
, m_isValid(true)
|
||||
, m_exerciseId(0)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.SqlGenerator"))
|
||||
{}
|
||||
|
||||
SqlGenerator::SqlGenerator(const QString &xmlFile)
|
||||
: m_xmlReader(new XmlReader)
|
||||
, m_structBuilder(new StructBuilder(m_xmlReader))
|
||||
, m_createdByXmlFile(true)
|
||||
, m_isValid(false)
|
||||
, m_exerciseId(0)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.SqlGenerator"))
|
||||
{
|
||||
m_isValid = m_xmlReader->readServiceFile(xmlFile, QString()) && m_structBuilder->buildStructures();
|
||||
}
|
||||
|
||||
SqlGenerator::~SqlGenerator()
|
||||
{
|
||||
if (m_createdByXmlFile)
|
||||
{
|
||||
delete m_xmlReader;
|
||||
delete m_structBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SqlGenerator::generateData(int exerciseId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Generating SQL data for service " << getServiceAbbr() << " in exercise " << exerciseId << ", this: " << this;
|
||||
|
||||
m_exerciseId = exerciseId;
|
||||
m_sqlGlobal = SqlStatements();
|
||||
m_sqlExercise = SqlStatements();
|
||||
m_sqlItemsGlobal = SqlItems();
|
||||
m_sqlItemsExercise = SqlItems();
|
||||
m_referencedSevices.clear();
|
||||
|
||||
if (!handleTables())
|
||||
return false;
|
||||
|
||||
if (!handleViews())
|
||||
return false;
|
||||
|
||||
if (!handleEnumerations())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::createStatementsForTable(const QString &tableName, const QString &tableNameOut)
|
||||
{
|
||||
const QMap<QString, CompleteTableInformation> tables = m_structBuilder->getDbTables();
|
||||
for (const CompleteTableInformation &cti : tables)
|
||||
{
|
||||
if (cti.name != tableName)
|
||||
continue;
|
||||
CompleteTableInformation ctiOut = cti;
|
||||
ctiOut.name = tableNameOut;
|
||||
return handleTable(ctiOut);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleTables()
|
||||
{
|
||||
const QMap<QString, CompleteTableInformation> tables = m_structBuilder->getDbTables();
|
||||
for (const CompleteTableInformation &cti : tables)
|
||||
{
|
||||
if (!handleTable(cti))
|
||||
return false;
|
||||
}
|
||||
|
||||
const QMap<QString, CompleteTableInformation> recTables = m_structBuilder->getRecordingTopicTables();
|
||||
MemberInformation miColumnIsValid;
|
||||
miColumnIsValid.db.columnName = QStringLiteral("dds_is_alive");
|
||||
miColumnIsValid.db.datatype = QStringLiteral("boolean");
|
||||
miColumnIsValid.db.defaultValue = QStringLiteral("true");
|
||||
MemberInformation miInsertionTime;
|
||||
miInsertionTime.cpp.type = QStringLiteral("timestamp");
|
||||
miInsertionTime.db.columnName = QStringLiteral("insert_time");
|
||||
miInsertionTime.db.defaultValue = QStringLiteral("now()");
|
||||
miInsertionTime.db.usedForInsert = false;
|
||||
m_structBuilder->fixupQVariantConversions(miInsertionTime);
|
||||
ConstraintInformation ci;
|
||||
ci.name = QStringLiteral("IDX_sample_time");
|
||||
ci.affectedColumns = QStringList({QStringLiteral("sample_time")});
|
||||
ci.type = ConstraintInformation::Type::index;
|
||||
for (const CompleteTableInformation &cti : recTables)
|
||||
{
|
||||
CompleteTableInformation ctiTmp(cti);
|
||||
ctiTmp.columns.push_back(miColumnIsValid);
|
||||
ctiTmp.columns.push_back(miInsertionTime);
|
||||
ctiTmp.constraints.push_back(ci);
|
||||
if (!handleTable(ctiTmp))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleViews()
|
||||
{
|
||||
const QMap<QString, ViewInformation> views = m_structBuilder->getDbViews();
|
||||
for (const ViewInformation &vi : views)
|
||||
{
|
||||
if (!handleView(vi))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleView(const ViewInformation &vi)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle view " << vi.name;
|
||||
|
||||
const QString parent = vi.baseTable;
|
||||
|
||||
DEBUG_LOG(m_logger) << "Parent = " << parent;
|
||||
|
||||
if (!parent.isEmpty())
|
||||
{
|
||||
const CompleteStructInformation csi = m_structBuilder->structInformationByTableName(parent);
|
||||
const QString createViewStmt(QStringLiteral("CREATE OR REPLACE VIEW %1 AS SELECT %2\nFROM %3\nWHERE %4;\n"));
|
||||
const QString dropViewStmt(QStringLiteral("DROP VIEW IF EXISTS %1;"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "csi.primaryTable = " << csi.primaryTable.data()->name;
|
||||
|
||||
if (!csi.primaryTable.isNull())
|
||||
{
|
||||
QStringList fromTables;
|
||||
fromTables += vi.baseSchema+QLatin1Char('.')+vi.baseTable;
|
||||
|
||||
QStringList whereConditions;
|
||||
if (vi.filter.contains(QLatin1String("exercise_id")))
|
||||
whereConditions += QLatin1String("exercise_id=")+QString::number(m_exerciseId);
|
||||
|
||||
QStringList fqColumnNames;
|
||||
// fqColumnNames += QLatin1String("*");
|
||||
// buildup view create statement
|
||||
for (const MemberInformation &mi : csi.member)
|
||||
{
|
||||
if (mi.db.usedForView)
|
||||
fqColumnNames += mi.db.table + QLatin1Char('.') + mi.db.columnName + QLatin1String(" AS ") + mi.db.getColumnNameView();
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "fqColumnNames = " << fqColumnNames.join(QStringLiteral(", "));
|
||||
|
||||
|
||||
if (!whereConditions.isEmpty())
|
||||
addToCreateViews(createViewStmt.arg(csi.viewName,
|
||||
fqColumnNames.join(QStringLiteral(", ")),
|
||||
fromTables.join(QStringLiteral(", ")),
|
||||
whereConditions.join(QStringLiteral(" AND\n"))),
|
||||
vi.exerciseDependency);
|
||||
addToDropViews(dropViewStmt.arg(csi.viewName), vi.exerciseDependency);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleTable(const CompleteTableInformation &cti)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle table " << cti.name;
|
||||
|
||||
if (cti.columns.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Table " << cti.name
|
||||
<< " has no DatabaseServiceStruct - not generating anything for this!";
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString dropTableStmt(QStringLiteral("DROP TABLE IF EXISTS %1 CASCADE;"));
|
||||
const QString createTableStmt(QStringLiteral("CREATE TABLE IF NOT EXISTS %1 (%2\n);"));
|
||||
const QString commentTableStmt(QStringLiteral("COMMENT ON TABLE %1 IS '%2';"));
|
||||
|
||||
QStringList tableComments;
|
||||
addToDropTables(dropTableStmt.arg(cti.name), cti.exerciseDependency);
|
||||
|
||||
if ((cti.exerciseDependency & Global) == Global)
|
||||
{
|
||||
addToCreateTables(createTableStmt.arg(cti.name,
|
||||
getTableColumnCreateStatements(cti.name,
|
||||
cti.columns,
|
||||
&tableComments,
|
||||
Global)),
|
||||
Global);
|
||||
}
|
||||
if ((cti.exerciseDependency & Exercise) == Exercise)
|
||||
{
|
||||
addToCreateTables(createTableStmt.arg(cti.name,
|
||||
getTableColumnCreateStatements(cti.name,
|
||||
cti.columns,
|
||||
&tableComments,
|
||||
Exercise)),
|
||||
Exercise);
|
||||
}
|
||||
addToTables(cti.name, cti.exerciseDependency);
|
||||
|
||||
if (!cti.comment.isEmpty())
|
||||
addToCreateTables(commentTableStmt.arg(cti.name, fixupComment(cti.comment)), cti.exerciseDependency);
|
||||
addToCreateTables(tableComments, cti.exerciseDependency);
|
||||
|
||||
const QString parent = m_xmlReader->getStruct2BaseClassRelations().value(cti.name);
|
||||
const CompleteStructInformation csi = m_structBuilder->structInformationByTableName(cti.name);
|
||||
if (!parent.isEmpty())
|
||||
{
|
||||
const QString createViewStmt(QStringLiteral("CREATE OR REPLACE VIEW %1 AS SELECT %2\nFROM %3\nWHERE %4;\n"));
|
||||
const QString dropViewStmt(QStringLiteral("DROP VIEW IF EXISTS %1;"));
|
||||
if (!csi.primaryTable.isNull())
|
||||
{
|
||||
QStringList fqColumnNames;
|
||||
QStringList fromTables;
|
||||
QStringList whereConditions;
|
||||
fromTables += cti.name;
|
||||
|
||||
// buildup view create statement
|
||||
for (const MemberInformation &mi : csi.member)
|
||||
{
|
||||
if (mi.db.usedForView)
|
||||
fqColumnNames += mi.db.table + QLatin1Char('.') + mi.db.columnName + QLatin1String(" AS ") + mi.db.getColumnNameView();
|
||||
if (mi.cpp.isReadOnly && mi.db.isForeignKey)
|
||||
{
|
||||
// readOnly -> FK
|
||||
// get FK Informations
|
||||
// get correct TableInformation
|
||||
for (const QSharedPointer<TableInformation> &tiPtr : csi.tables)
|
||||
{
|
||||
if (tiPtr->name == mi.db.table)
|
||||
{
|
||||
const QSharedPointer<ForeignKeyInformation> fki = tiPtr->fkInformationForColumn(mi.db.table, mi.db.columnName);
|
||||
if (!fki.isNull())
|
||||
{
|
||||
// IO 26.05.2016: ignore second foreign key on same tables, the create view sql is more complicated in this case (see ppm_sensor_view)
|
||||
if (!fromTables.contains(fki->destination.tableName))
|
||||
{
|
||||
whereConditions += fki->destination.tableName + QLatin1Char('.') + fki->destination.columnName +
|
||||
QLatin1String(" = ") +
|
||||
fki->source.tableName + QLatin1Char('.') + fki->source.columnName;
|
||||
fromTables += fki->destination.tableName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!whereConditions.isEmpty())
|
||||
{
|
||||
addToCreateViews(createViewStmt.arg(csi.viewName,
|
||||
fqColumnNames.join(QStringLiteral(", ")),
|
||||
fromTables.join(QStringLiteral(", ")),
|
||||
whereConditions.join(QStringLiteral(" AND\n"))),
|
||||
cti.exerciseDependency);
|
||||
}
|
||||
addToDropViews(dropViewStmt.arg(csi.viewName), cti.exerciseDependency);
|
||||
}
|
||||
}
|
||||
|
||||
if (!generateDbNotifications(cti.name, csi.dbNotifications, cti.exerciseDependency))
|
||||
return false;
|
||||
|
||||
generateForeignKeys(cti.foreignKeys, cti.exerciseDependency);
|
||||
|
||||
generateConstraints(cti.name, cti.constraints, cti.exerciseDependency);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// must not be called with ExerciseDependency::Undefined or Exercisedependency::GlobalAndExercise !!
|
||||
QString SqlGenerator::getTableColumnCreateStatements(const QString &tableName,
|
||||
const QVector<MemberInformation> &columns,
|
||||
QStringList *tableComments,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
Q_ASSERT(ed == Global || ed == Exercise);
|
||||
|
||||
const QString commentColumnStmt(QStringLiteral("COMMENT ON COLUMN %1 IS '%2';"));
|
||||
|
||||
// only for beautification of the output
|
||||
int maxLength = 1;
|
||||
for (const MemberInformation &mi : columns)
|
||||
maxLength = std::max(maxLength, mi.db.columnName.length());
|
||||
maxLength += 1;
|
||||
|
||||
QStringList retCols;
|
||||
retCols.reserve(columns.size() + 1);
|
||||
retCols += QString();
|
||||
for (int i = 0; i < columns.size(); ++i)
|
||||
{
|
||||
const MemberInformation &mi = columns.at(i);
|
||||
const FullQualifiedColumnInformation &ci = mi.db;
|
||||
const QString spaces(maxLength - ci.columnName.length(), QLatin1Char(' '));
|
||||
QString column = ci.columnName + spaces + ci.datatype;
|
||||
if (ci.hasSequence)
|
||||
{
|
||||
// TODO: dbSchema needs added to sequence
|
||||
const QString seqDescr = generateSequence(tableName, ci, ed);
|
||||
QString schema;
|
||||
if (ed == Global)
|
||||
schema = m_xmlReader->getServiceAbbr();
|
||||
else
|
||||
schema = getExerciseSchemaName(m_exerciseId);
|
||||
|
||||
column += QLatin1String(" DEFAULT nextval(( '") +
|
||||
schema + QLatin1Char('.') + seqDescr +
|
||||
QLatin1String("'::text)::regclass)");
|
||||
}
|
||||
if (!ci.canBeNull)
|
||||
column += QLatin1String(" NOT NULL");
|
||||
if (!ci.hasSequence && !ci.defaultValue.isEmpty())
|
||||
column += QLatin1String(" DEFAULT ") + ci.defaultValue;
|
||||
if (i < columns.size() - 1)
|
||||
column += QLatin1Char(',');
|
||||
if (!ci.comment.isEmpty())
|
||||
{
|
||||
const QString comment(fixupComment(ci.comment));
|
||||
const QString fqn = ci.table + QLatin1Char('.') + ci.columnName;
|
||||
*tableComments += commentColumnStmt.arg(fqn, comment);
|
||||
column += QLatin1String(" -- ") + comment;
|
||||
}
|
||||
|
||||
retCols += column;
|
||||
|
||||
if (ci.isPrimaryKey)
|
||||
generatePrimaryKey(tableName, ci, ed);
|
||||
}
|
||||
return retCols.join(QStringLiteral("\n "));
|
||||
}
|
||||
|
||||
QString SqlGenerator::generateSequence(const QString &tableName,
|
||||
const FullQualifiedColumnInformation &ci,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
const QString sequenceName = tableName + QLatin1Char('_') + ci.columnName + QLatin1String("_seq");
|
||||
|
||||
// "IF NOT EXISTS" for sequences possible now from 9.5 on
|
||||
// http://www.postgresql.org/docs/9.5/static/sql-createsequence.html
|
||||
const QString createSequenceStmt(QLatin1String("CREATE SEQUENCE IF NOT EXISTS %1 INCREMENT %2 START %3 MINVALUE %4;"));
|
||||
|
||||
const int minValue = ci.sequenceStart < 1 ? ci.sequenceStart : 1;
|
||||
|
||||
addToCreateSequences(createSequenceStmt.arg(sequenceName).arg(ci.sequenceIncrement).arg(ci.sequenceStart).arg(minValue), ed);
|
||||
addToSequences(sequenceName, ed);
|
||||
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
void SqlGenerator::generatePrimaryKey(const QString &tableName,
|
||||
const FullQualifiedColumnInformation &ci,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
QString pkName = QLatin1String("PK_") + tableName + QLatin1Char('_') + ci.columnName;
|
||||
// truncate long names to 63
|
||||
if (pkName.size() > 63) pkName.resize(63);
|
||||
|
||||
addToPks(pkName, ed);
|
||||
|
||||
// ADD IF NOT EXISTS => Postgresql 9.6
|
||||
// Using stored procedure 'exists_constraint' for now (14.03.16) (HR)
|
||||
const QString pkConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 ADD CONSTRAINT %2 PRIMARY KEY (%3);"));
|
||||
addToCreatePks(pkConstraint.arg(tableName, pkName, ci.columnName), ed);
|
||||
|
||||
const QString pkDropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
addToDropConstraints(pkDropConstraint.arg(tableName, pkName), ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateForeignKeys(const QVector<QSharedPointer<ForeignKeyInformation> > &foreignKeys,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const QSharedPointer<ForeignKeyInformation> &fk : foreignKeys)
|
||||
generateForeignKey(fk, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateForeignKey(const QSharedPointer<ForeignKeyInformation> &foreignKey,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
QString fkName = QLatin1String("FK_") + foreignKey->source.tableName +
|
||||
QLatin1Char('_') + foreignKey->source.columnName +
|
||||
QLatin1Char('_') + foreignKey->destination.tableName +
|
||||
QLatin1Char('_') + foreignKey->destination.columnName;
|
||||
|
||||
// truncate long names to 64
|
||||
//if (fkName.size() > 63) fkName.resize(63);
|
||||
if (fkName.size() > 63) fkName = foreignKey->name;
|
||||
|
||||
addToFks(fkName, ed);
|
||||
|
||||
QString fkConstraint(QStringLiteral("ALTER TABLE %1 ADD CONSTRAINT %2 FOREIGN KEY (%3) REFERENCES %4 (%5)"));
|
||||
switch (foreignKey->deleteAction)
|
||||
{
|
||||
case ForeignKeyInformation::OnDeleteAction::NoAction: // no deletion possible at all
|
||||
fkConstraint += QStringLiteral(" ON DELETE NO ACTION");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::Cascade:
|
||||
fkConstraint += QStringLiteral(" ON DELETE CASCADE ON UPDATE CASCADE");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::Restrict: // no deletion until childs are deleted
|
||||
fkConstraint += QStringLiteral(" ON DELETE RESTRICT");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::SetNull:
|
||||
fkConstraint += QStringLiteral(" ON DELETE SET NULL");
|
||||
break;
|
||||
case ForeignKeyInformation::OnDeleteAction::SetDefault:
|
||||
fkConstraint += QStringLiteral(" ON DELETE SET DEFAULT");
|
||||
break;
|
||||
}
|
||||
|
||||
fkConstraint += QLatin1Char(';');
|
||||
|
||||
// the work if the fk points to a global or local schema is already done in the EA export script (ExportExternalFk())
|
||||
// if foreignKey->destination.schema is set, then we've to use it ... :)
|
||||
QString destination;
|
||||
if (!foreignKey->destination.schema.isEmpty())
|
||||
{
|
||||
const QString &extSchema = foreignKey->destination.schema;
|
||||
destination = extSchema + QLatin1Char('.') + foreignKey->destination.tableName;
|
||||
}
|
||||
else
|
||||
destination = foreignKey->destination.tableName;
|
||||
|
||||
const QString &extSvcAbbr = foreignKey->destination.serviceAbbr;
|
||||
// depends on another service .. remember depedency
|
||||
if (!extSvcAbbr.isEmpty() && !m_referencedSevices.contains(extSvcAbbr))
|
||||
m_referencedSevices += extSvcAbbr;
|
||||
|
||||
addToCreateFks(fkConstraint.arg(foreignKey->source.tableName, fkName, foreignKey->source.columnName,
|
||||
destination, foreignKey->destination.columnName), ed);
|
||||
|
||||
const QString fkDropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
addToDropConstraints(fkDropConstraint.arg(foreignKey->source.tableName, fkName), ed);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SqlGenerator::generateConstraints(const QString &tableName,
|
||||
const QVector<ConstraintInformation> &constraints,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const ConstraintInformation &constraint : constraints)
|
||||
generateConstraint(tableName, constraint, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::generateConstraint(const QString &tableName,
|
||||
const ConstraintInformation &constraint,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
const QString dropConstraint(QStringLiteral("ALTER TABLE IF EXISTS %1 DROP CONSTRAINT IF EXISTS %2 CASCADE;"));
|
||||
switch (constraint.type)
|
||||
{
|
||||
case ConstraintInformation::Type::index:
|
||||
{
|
||||
QString constraintName = QLatin1String("IDX_") + tableName + QLatin1Char('_') +
|
||||
constraint.affectedColumns.join(QStringLiteral("_"));
|
||||
// truncate long names to 63
|
||||
if (constraintName.size() > 63) constraintName.resize(63);
|
||||
|
||||
const QString index(QStringLiteral("CREATE INDEX %1 ON %2 (%3);"));
|
||||
|
||||
addToCreateConstraints(index.arg(constraintName, tableName, constraint.affectedColumns.join(QStringLiteral(", "))), ed);
|
||||
addToConstraints(constraintName, ed);
|
||||
|
||||
addToDropConstraints(dropConstraint.arg(tableName, constraintName), ed);
|
||||
|
||||
break;
|
||||
}
|
||||
case ConstraintInformation::Type::unique:
|
||||
{
|
||||
QString constraintName = QLatin1String("UQ_") + tableName + QLatin1Char('_') +
|
||||
constraint.affectedColumns.join(QStringLiteral("_"));
|
||||
// truncate long names to 63
|
||||
if (constraintName.size() > 63) constraintName.resize(63);
|
||||
const QString unique(QStringLiteral("ALTER TABLE %1 ADD CONSTRAINT %2 UNIQUE (%3);"));
|
||||
|
||||
addToCreateConstraints(unique.arg(tableName, constraintName, constraint.affectedColumns.join(QStringLiteral(", "))), ed);
|
||||
addToConstraints(constraintName, ed);
|
||||
|
||||
addToDropConstraints(dropConstraint.arg(tableName, constraintName), ed);
|
||||
|
||||
break;
|
||||
}
|
||||
case ConstraintInformation::Type::unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleEnumerations()
|
||||
{
|
||||
const QVector<EnumInformation> enumerations = m_xmlReader->getEnumerations();
|
||||
for (const EnumInformation &ei : enumerations)
|
||||
{
|
||||
if (!handleEnumeration(ei))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SqlGenerator::handleEnumeration(const EnumInformation &ei)
|
||||
{
|
||||
const QStringList sql = handleEnumeration(ei, QString());
|
||||
if (m_sqlItemsGlobal.tables.contains(ei.tableName))
|
||||
m_sqlGlobal.enumerationValues += sql;
|
||||
if (m_sqlItemsExercise.tables.contains(ei.tableName))
|
||||
m_sqlExercise.enumerationValues += sql;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::handleEnumeration(const EnumInformation &ei, const QString &dbSchema) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Handle enumeration " << ei.enumName;
|
||||
|
||||
if (ei.tableName.isEmpty())
|
||||
{
|
||||
INFO_LOG(m_logger) << "No table for enumeration " << ei.enumName << " - not creating inserts for this enum";
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
const QString insertEnum(QStringLiteral("INSERT INTO %1 (%2) VALUES (%3);"));
|
||||
const QString columnNames(QStringLiteral("id, name"));
|
||||
const QString tablename = dbSchema.isEmpty() ? ei.tableName : dbSchema + QLatin1Char('.') + ei.tableName;
|
||||
|
||||
// Festlegung: id - name = key - value
|
||||
QStringList enumerationValues;
|
||||
for (const EnumKeyValuePair &evp : ei.values)
|
||||
{
|
||||
const QString values(QString::number(evp.value) + QLatin1String(", '") +
|
||||
fixupComment(evp.key) + QLatin1Char('\''));
|
||||
enumerationValues += insertEnum.arg(tablename, columnNames, values);
|
||||
}
|
||||
|
||||
return enumerationValues;
|
||||
}
|
||||
|
||||
bool SqlGenerator::generateDbNotifications(const QString &tableName,
|
||||
const QVector<DbNotifcationInformation> ¬ifications,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
for (const DbNotifcationInformation ¬ification : notifications)
|
||||
{
|
||||
if (notification.paramNames.isEmpty() ||
|
||||
notification.paramNames.size() > 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not handle more than one parameter";
|
||||
continue;
|
||||
}
|
||||
generateDbNotification(notification, ed);
|
||||
if (!generateDbNotificationTrigger(tableName, notification, ed))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SqlGenerator::generateDbNotification(const DbNotifcationInformation ¬ification,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
const QString func(QStringLiteral("CREATE OR REPLACE FUNCTION public.%1()\n"
|
||||
"RETURNS TRIGGER AS $$\n"
|
||||
"DECLARE\n"
|
||||
" toNotify RECORD;\n"
|
||||
" toReturn RECORD;\n"
|
||||
"BEGIN\n"
|
||||
" IF (TG_OP = 'INSERT') THEN\n"
|
||||
" toNotify = NEW;\n"
|
||||
" toReturn = NEW;\n"
|
||||
" ELSIF (TG_OP = 'UPDATE') THEN\n"
|
||||
" toNotify = OLD;\n"
|
||||
" toReturn = NEW;\n"
|
||||
" ELSIF (TG_OP = 'DELETE') THEN\n"
|
||||
" toNotify = OLD;\n"
|
||||
" toReturn = OLD;\n"
|
||||
" END IF;\n"
|
||||
" \n"
|
||||
" PERFORM pg_notify('%2', CAST(toNotify.%3 AS text));\n"
|
||||
" RETURN toReturn;\n"
|
||||
"END;\n"
|
||||
"$$ LANGUAGE plpgsql;"));
|
||||
|
||||
const QString triggerFuncName(getNotificationFunctionName(notification));
|
||||
addToDbFunctions(func.arg(triggerFuncName, notification.methodName, notification.paramNames.first()), ed);
|
||||
}
|
||||
|
||||
bool SqlGenerator::generateDbNotificationTrigger(const QString &tableName,
|
||||
const DbNotifcationInformation ¬ification,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
// CREATE TRIGGER uebung_1ins_tln_zuordn BEFORE INSERT ON tln_zuordnung FOR EACH ROW EXECUTE PROCEDURE public.ins_zuordnung();
|
||||
const QString drop(QStringLiteral("DROP TRIGGER IF EXISTS %1 ON %2;"));
|
||||
const QString func(QStringLiteral("CREATE TRIGGER %1\n") +
|
||||
QStringLiteral("%2 ON %3 FOR EACH ROW EXECUTE PROCEDURE public.%4();"));
|
||||
|
||||
for (DbNotifcationInformation::NotificationType notifyType : notification.notificationType)
|
||||
{
|
||||
QString when;
|
||||
QString triggerNameShortcut;
|
||||
switch (notifyType)
|
||||
{
|
||||
case DbNotifcationInformation::NotificationType::BeforeInsert:
|
||||
when = QStringLiteral("BEFORE INSERT");
|
||||
triggerNameShortcut = QStringLiteral("bi");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterInsert:
|
||||
when = QStringLiteral("AFTER INSERT");
|
||||
triggerNameShortcut = QStringLiteral("ai");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::BeforeUpdate:
|
||||
when = QStringLiteral("BEFORE UPDATE");
|
||||
triggerNameShortcut = QStringLiteral("bu");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterUpdate:
|
||||
when = QStringLiteral("AFTER UPDATE");
|
||||
triggerNameShortcut = QStringLiteral("au");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::BeforeDelete:
|
||||
when = QStringLiteral("BEFORE DELETE");
|
||||
triggerNameShortcut = QStringLiteral("bd");
|
||||
break;
|
||||
case DbNotifcationInformation::NotificationType::AfterDelete:
|
||||
when = QStringLiteral("AFTER DELETE");
|
||||
triggerNameShortcut = QStringLiteral("ad");
|
||||
break;
|
||||
}
|
||||
const QString triggerName(QLatin1String("trg_") + triggerNameShortcut + QLatin1Char('_') + notification.methodName);
|
||||
const QString triggerFuncName(getNotificationFunctionName(notification));
|
||||
addToDbFunctionTrigger(drop.arg(triggerName, tableName), ed);
|
||||
addToDbFunctionTrigger(func.arg(triggerName, when, tableName, triggerFuncName), ed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SqlGenerator::getNotificationFunctionName(const DbNotifcationInformation ¬ification) const
|
||||
{
|
||||
return getServiceAbbr() + QLatin1Char('_') + notification.methodName;
|
||||
}
|
||||
|
||||
|
||||
QString SqlGenerator::fixupComment(const QString &comment)
|
||||
{
|
||||
// fixup chars
|
||||
QString ret = comment;
|
||||
ret = ret.remove(QLatin1Char('\''));
|
||||
ret = ret.replace(QLatin1Char(';'), QLatin1Char(','));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getDbSettings(const QString &dbSchema) const
|
||||
{
|
||||
QStringList data;
|
||||
|
||||
// see svc_db_impl.cpp.grantlee - DatabaseInterfaceImpl::dbUser()
|
||||
QString dbUser(QStringLiteral("ets_"));
|
||||
if (m_exerciseId > 0)
|
||||
dbUser += QStringLiteral("ex_00"); //getExerciseSchemaName(m_exerciseId);
|
||||
else
|
||||
dbUser += m_xmlReader->getServiceAbbr().toLower();
|
||||
|
||||
// Grant table privileges
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT SELECT,INSERT,UPDATE,DELETE,TRUNCATE ON TABLES TO ") + dbUser + QLatin1Char(';'));
|
||||
|
||||
// Grant select to all users in <product>_ro
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT SELECT, REFERENCES ON TABLES TO ets_ro;"));
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT EXECUTE ON FUNCTIONS TO ") + dbUser + QLatin1Char(';'));
|
||||
|
||||
data.append(QLatin1String("ALTER DEFAULT PRIVILEGES IN SCHEMA ") + dbSchema + QLatin1Char('\n') +
|
||||
QLatin1String(" GRANT ALL ON SEQUENCES TO ") + dbUser + QLatin1Char(';'));
|
||||
|
||||
// Set search path
|
||||
data.append(QLatin1String("SET SEARCH_PATH TO ") + dbSchema + QLatin1String(", PUBLIC;"));
|
||||
|
||||
QStringList deps;
|
||||
deps.reserve(m_referencedSevices.size());
|
||||
for(const QString &svc : m_referencedSevices)
|
||||
deps += QStringLiteral("-- DEPENDS: ") + svc;
|
||||
|
||||
return deps + data;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getAllSqlStmts(const QString &dbSchema, ExerciseDependency ed) const
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Creating statements for service " << getServiceAbbr() << " in exercise " << m_exerciseId << ", this: " << this;
|
||||
|
||||
QStringList data;
|
||||
|
||||
const SqlStatements &sql = getStatements(ed);
|
||||
if (sql.isEmpty())
|
||||
return data;
|
||||
|
||||
if (!dbSchema.isEmpty())
|
||||
data << getDbSettings(dbSchema);
|
||||
|
||||
// Write drop-stmts
|
||||
data.append(QStringLiteral("\n-- Drop tables/views/sequences/constraints"));
|
||||
data.append(sql.dropViews);
|
||||
data.append(sql.dropConstraints);
|
||||
data.append(sql.dropTables);
|
||||
data.append(sql.dropSequences);
|
||||
|
||||
// Write create-stmts (tables)
|
||||
data.append(QStringLiteral("\n-- Create tables"));
|
||||
data.append(sql.createTables);
|
||||
|
||||
// Create sequence(s)
|
||||
data.append(QStringLiteral("\n-- Create sequence(s)"));
|
||||
data.append(sql.createSequences);
|
||||
|
||||
// Write primary key(s)
|
||||
data.append(QStringLiteral("\n-- Create primary keys"));
|
||||
data.append(sql.createPrimaryKeys);
|
||||
|
||||
// Write foreign key(s)
|
||||
data.append(QStringLiteral("\n-- Create foreign keys"));
|
||||
data.append(sql.createForeignKeys);
|
||||
|
||||
// Write create-stmts (views)
|
||||
data.append(QStringLiteral("\n-- Create views"));
|
||||
data.append(sql.createViews);
|
||||
|
||||
// Write inserts for enums
|
||||
data.append(QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Inserts for static data i.e. enums\n"));
|
||||
data.append(sql.enumerationValues);
|
||||
|
||||
// Write notify functions
|
||||
data.append(QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Notify functions for callbacks (signals in db interface)\n"));
|
||||
data.append(sql.dbFunctions);
|
||||
|
||||
// Write notify functions
|
||||
data.append(QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Notify function trigger for callbacks (signals in db interface)\n"));
|
||||
data.append(sql.dbFunctionTrigger);
|
||||
|
||||
// Write constraints
|
||||
data.append(QStringLiteral("\n-- --------------------------------------------------------------------------------"));
|
||||
data.append(QStringLiteral("\n-- Indexes \n"));
|
||||
data.append(sql.createConstraints);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
QStringList SqlGenerator::getEnumerationInsertValues(const QString &table, const QString &dbSchema) const
|
||||
{
|
||||
const QVector<EnumInformation> enumerations = m_xmlReader->getEnumerations();
|
||||
|
||||
for (const EnumInformation &ei : enumerations)
|
||||
{
|
||||
if (ei.tableName == table)
|
||||
return handleEnumeration(ei, dbSchema);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeSqlToFile(const QString &dbSchema, const QString &sqlFile, ExerciseDependency ed) const
|
||||
{
|
||||
return writeFile(sqlFile, getAllSqlStmts(dbSchema, ed).join(QLatin1Char('\n')));
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeSql(const QString &filePath, ExerciseDependency ed)
|
||||
{
|
||||
Q_ASSERT(ed == Global || ed == Exercise);
|
||||
|
||||
// ExerciseDependency == Global -> write exercise independent sql statements -> <svc>.sql
|
||||
QString sqlFile = filePath + getServiceAbbr();
|
||||
if (ed == ExerciseDependency::Exercise)
|
||||
sqlFile += QLatin1Char('_') + getExerciseSchemaName(m_exerciseId);
|
||||
sqlFile += QLatin1String(".sql");
|
||||
|
||||
const SqlStatements &sql = getStatements(ed);
|
||||
if (sql.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Sql file is emtpy: " << sqlFile;
|
||||
return writeFile(sqlFile, QString());
|
||||
}
|
||||
|
||||
// exerciseId > 0 -> write exercise dependent sql statements -> <svc>_ex_<exerciseId>.sql
|
||||
|
||||
const QString dbSchema = (ed == ExerciseDependency::Exercise ?
|
||||
getExerciseSchemaName(m_exerciseId) :
|
||||
getServiceAbbr());
|
||||
|
||||
INFO_LOG(m_logger) << "Creating sql-stmt for schema (" << dbSchema << ")";
|
||||
return writeSqlToFile(dbSchema, sqlFile, ed);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static void addInternal(QStringList &global,
|
||||
QStringList &exercise,
|
||||
const T &stmt,
|
||||
ExerciseDependency ed)
|
||||
{
|
||||
switch (ed)
|
||||
{
|
||||
case ExerciseDependency::Global:
|
||||
global += stmt;
|
||||
break;
|
||||
case ExerciseDependency::Exercise:
|
||||
exercise += stmt;
|
||||
break;
|
||||
case ExerciseDependency::GlobalAndExercise:
|
||||
global += stmt;
|
||||
exercise += stmt;
|
||||
break;
|
||||
case ExerciseDependency::Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropSequences(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropSequences, m_sqlExercise.dropSequences, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropTables(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropTables, m_sqlExercise.dropTables, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropViews(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropViews, m_sqlExercise.dropViews, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateConstraints(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createConstraints, m_sqlExercise.createConstraints, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDropConstraints(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dropConstraints, m_sqlExercise.dropConstraints, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateFks(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createForeignKeys, m_sqlExercise.createForeignKeys, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreatePks(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createPrimaryKeys, m_sqlExercise.createPrimaryKeys, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateSequences(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createSequences, m_sqlExercise.createSequences, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateTables(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createTables, m_sqlExercise.createTables, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateTables(const QStringList &stmts, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createTables, m_sqlExercise.createTables, stmts, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToCreateViews(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.createViews, m_sqlExercise.createViews, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDbFunctions(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dbFunctions, m_sqlExercise.dbFunctions, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToDbFunctionTrigger(const QString &stmt, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlGlobal.dbFunctionTrigger, m_sqlExercise.dbFunctionTrigger, stmt, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToConstraints(const QString &name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.constraints, m_sqlItemsExercise.constraints, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToFks(const QString &name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.foreignKeys, m_sqlItemsExercise.foreignKeys, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToPks(const QString &name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.primaryKeys, m_sqlItemsExercise.primaryKeys, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToSequences(const QString &name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.sequences, m_sqlItemsExercise.sequences, name, ed);
|
||||
}
|
||||
|
||||
void SqlGenerator::addToTables(const QString &name, ExerciseDependency ed)
|
||||
{
|
||||
addInternal(m_sqlItemsGlobal.tables, m_sqlItemsExercise.tables, name, ed);
|
||||
}
|
||||
|
||||
bool SqlGenerator::writeFile(const QString &fn, const QString &content) const
|
||||
{
|
||||
QFile f(fn);
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening file '" << f.fileName() << "' for writing: "
|
||||
<< f.errorString();
|
||||
return false;
|
||||
}
|
||||
f.write(content.toUtf8());
|
||||
if (!content.isEmpty())
|
||||
f.write("\n");
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Generate SQL statements from Xml service files
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QStringList>
|
||||
#include <QSharedPointer>
|
||||
#include "StructBuilder.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
struct ColumnInformation;
|
||||
struct ConstraintInformation;
|
||||
struct EnumInformation;
|
||||
struct ForeignKeyInformation;
|
||||
struct TableInformation;
|
||||
class XmlReader;
|
||||
|
||||
class CODEGEN_BASE_EXPORT SqlGenerator final
|
||||
{
|
||||
public:
|
||||
struct SqlStatements
|
||||
{
|
||||
QStringList dropViews;
|
||||
QStringList dropTables;
|
||||
QStringList dropSequences;
|
||||
QStringList dropConstraints;
|
||||
|
||||
QStringList createTables;
|
||||
QStringList createSequences;
|
||||
QStringList createPrimaryKeys;
|
||||
QStringList createForeignKeys;
|
||||
QStringList createViews;
|
||||
QStringList createConstraints;
|
||||
|
||||
QStringList enumerationValues; // tables are created within createTables
|
||||
QStringList dbFunctions;
|
||||
QStringList dbFunctionTrigger;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return dropViews.isEmpty() && dropTables.isEmpty() && dropSequences.isEmpty() && dropConstraints.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct SqlItems
|
||||
{
|
||||
QStringList tables; // all tables (just names)
|
||||
QStringList sequences; // all sequences (just names)
|
||||
QStringList primaryKeys;
|
||||
QStringList foreignKeys;
|
||||
QStringList constraints;
|
||||
};
|
||||
|
||||
public:
|
||||
Q_DISABLE_COPY(SqlGenerator)
|
||||
|
||||
explicit SqlGenerator(XmlReader *xmlReader, StructBuilder *structBuilder);
|
||||
explicit SqlGenerator(const QString &xmlFile);
|
||||
|
||||
~SqlGenerator();
|
||||
|
||||
bool isValid() const { return m_isValid; }
|
||||
// exerciseId -> use exerciseId if ExerciseDependent tables are found
|
||||
bool generateData(int exerciseId);
|
||||
|
||||
bool createStatementsForTable(const QString &tableName, const QString &tableNameOut);
|
||||
|
||||
SqlStatements getStatements(ExerciseDependency ed) const
|
||||
{
|
||||
return (ed == ExerciseDependency::Exercise ? m_sqlExercise : m_sqlGlobal);
|
||||
}
|
||||
|
||||
SqlItems getSqlItems(ExerciseDependency ed) const
|
||||
{
|
||||
return (ed == ExerciseDependency::Exercise ? m_sqlItemsExercise : m_sqlItemsGlobal);
|
||||
}
|
||||
|
||||
QStringList getEnumerationInsertValues(const QString &table, const QString &dbSchema) const;
|
||||
QStringList getReferencedServices() const // returns the abbreviations
|
||||
{
|
||||
return m_referencedSevices;
|
||||
}
|
||||
|
||||
QStringList getDbSettings(const QString &dbSchema) const;
|
||||
|
||||
// Writes
|
||||
bool writeSql(const QString &filePath, ExerciseDependency ed);
|
||||
|
||||
bool writeSqlToFile(const QString &dbSchema, const QString &sqlFile, ExerciseDependency ed) const;
|
||||
|
||||
// Methods from XmlReader
|
||||
QString getServiceAbbr() const { return m_xmlReader->getServiceAbbr(); }
|
||||
bool isServiceExerciseIndependent() const { return m_xmlReader->isServiceExerciseIndependent(); }
|
||||
bool isServiceGlobal() const { return (m_xmlReader->defaultExerciseDependency() == CodeGen::ExerciseDependency::Global || m_xmlReader->defaultExerciseDependency() == CodeGen::ExerciseDependency::GlobalAndExercise); }
|
||||
CodeGen::ExerciseDependency getExerciseDependency() const { return m_xmlReader->defaultExerciseDependency();}
|
||||
QStringList getGroupNames() const { return m_xmlReader->getGroupNames(); }
|
||||
|
||||
QStringList getAllSqlStmts(const QString &dbSchema, ExerciseDependency ed) const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
bool handleTables();
|
||||
bool handleViews();
|
||||
bool handleTable(const CompleteTableInformation &cti);
|
||||
bool handleView(const ViewInformation &vi);
|
||||
QString getTableColumnCreateStatements(const QString &tableName,
|
||||
const QVector<MemberInformation> &columns,
|
||||
QStringList *tableComments, ExerciseDependency ed);
|
||||
QString generateSequence(const QString &tableName, const FullQualifiedColumnInformation &ci, ExerciseDependency ed);
|
||||
void generatePrimaryKey(const QString &tableName, const FullQualifiedColumnInformation &ci, ExerciseDependency ed);
|
||||
void generateForeignKeys(const QVector<QSharedPointer<ForeignKeyInformation> > &foreignKeys, ExerciseDependency ed);
|
||||
void generateForeignKey(const QSharedPointer<ForeignKeyInformation> &foreignKey, ExerciseDependency ed);
|
||||
void generateConstraints(const QString &tableName, const QVector<ConstraintInformation> &constraints, ExerciseDependency ed);
|
||||
void generateConstraint(const QString &tableName, const ConstraintInformation &constraint, ExerciseDependency ed);
|
||||
bool handleEnumerations();
|
||||
bool handleEnumeration(const EnumInformation &ei);
|
||||
QStringList handleEnumeration(const EnumInformation &ei, const QString &dbSchema) const;
|
||||
bool generateDbNotifications(const QString &tableName, const QVector<DbNotifcationInformation> ¬ifications, ExerciseDependency ed);
|
||||
void generateDbNotification(const DbNotifcationInformation ¬ification, ExerciseDependency ed);
|
||||
bool generateDbNotificationTrigger(const QString &tableName, const DbNotifcationInformation ¬ification, ExerciseDependency ed);
|
||||
QString getNotificationFunctionName(const DbNotifcationInformation ¬ification) const;
|
||||
static QString fixupComment(const QString &comment);
|
||||
|
||||
private:
|
||||
XmlReader *m_xmlReader;
|
||||
StructBuilder *m_structBuilder;
|
||||
bool m_createdByXmlFile;
|
||||
|
||||
void addToDropSequences(const QString &stmt, ExerciseDependency ed);
|
||||
void addToDropTables(const QString &stmt, ExerciseDependency ed);
|
||||
void addToDropViews(const QString &stmt, ExerciseDependency ed);
|
||||
void addToDropConstraints(const QString &stmt, ExerciseDependency ed);
|
||||
|
||||
void addToCreateConstraints(const QString &stmt, ExerciseDependency ed);
|
||||
void addToCreateFks(const QString &stmt, ExerciseDependency ed);
|
||||
void addToCreatePks(const QString &stmt, ExerciseDependency ed);
|
||||
void addToCreateSequences(const QString &stmt, ExerciseDependency ed);
|
||||
void addToCreateTables(const QString &stmt, ExerciseDependency ed);
|
||||
void addToCreateTables(const QStringList &stmts, ExerciseDependency ed);
|
||||
void addToCreateViews(const QString &stmt, ExerciseDependency ed);
|
||||
|
||||
void addToDbFunctions(const QString &stmt, ExerciseDependency ed);
|
||||
void addToDbFunctionTrigger(const QString &stmt, ExerciseDependency ed);
|
||||
|
||||
void addToConstraints(const QString &name, ExerciseDependency ed);
|
||||
void addToFks(const QString &name, ExerciseDependency ed);
|
||||
void addToPks(const QString &name, ExerciseDependency ed);
|
||||
void addToSequences(const QString &name, ExerciseDependency ed);
|
||||
void addToTables(const QString &name, ExerciseDependency ed);
|
||||
|
||||
bool writeFile(const QString &fn, const QString &content) const;
|
||||
|
||||
SqlStatements m_sqlGlobal;
|
||||
SqlStatements m_sqlExercise;
|
||||
|
||||
SqlItems m_sqlItemsGlobal;
|
||||
SqlItems m_sqlItemsExercise;
|
||||
|
||||
QStringList m_referencedSevices;
|
||||
|
||||
bool m_isValid;
|
||||
int m_exerciseId;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Build up struct informations for the generators
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include "XmlReader.h"
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
class StructBuilder;
|
||||
|
||||
struct EaData
|
||||
{
|
||||
QString table;
|
||||
QString column;
|
||||
QString type;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return table +
|
||||
QLatin1Char(';') + column +
|
||||
QLatin1Char(';') + type;
|
||||
}
|
||||
};
|
||||
|
||||
struct FullQualifiedColumnInformation : public ColumnInformation
|
||||
{
|
||||
QString table;
|
||||
bool usedForInsert = false;
|
||||
bool usedForView = false;
|
||||
QString columnNameView;
|
||||
|
||||
QString getColumnNameView() const { return columnNameView.isEmpty() ? columnName : columnNameView; }
|
||||
|
||||
FullQualifiedColumnInformation() = default;
|
||||
FullQualifiedColumnInformation(const ColumnInformation &ci, const QString &tableName)
|
||||
: ColumnInformation(ci)
|
||||
, table(tableName)
|
||||
{}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return table +
|
||||
QLatin1Char(';') + columnName +
|
||||
QLatin1Char(';') + datatype +
|
||||
// QLatin1Char(';') + comment +
|
||||
QLatin1Char(';') + (isPrimaryKey ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + (isForeignKey ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + (usedForInsert ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + (usedForView ? QLatin1String("true") : QLatin1String("false"));
|
||||
}
|
||||
};
|
||||
|
||||
class DataTypeInfo
|
||||
{
|
||||
public:
|
||||
DataTypeInfo(const QString &name, bool isPod)
|
||||
: m_name(name)
|
||||
, m_isPod(isPod)
|
||||
{}
|
||||
virtual ~DataTypeInfo() = default;
|
||||
virtual QString name() const { return m_name; }
|
||||
virtual QString idlType() const = 0; // used in .idl file
|
||||
virtual QString ddsType() const = 0; // used in generated code from rtiddsgen
|
||||
virtual QString sqlType() const = 0; // used in sql statements
|
||||
virtual QString cppType() const = 0; // used in our code
|
||||
virtual QString cppTypeConstRef() const { return isPod() ? cppType() : QLatin1String("const ") + cppType() + QLatin1String(" &"); }
|
||||
virtual bool isPod() const { return m_isPod; }
|
||||
virtual bool isSequence() const { return false; }
|
||||
virtual bool isStructure() const { return false; }
|
||||
virtual QVector<QSharedPointer<DataTypeInfo>> member() const { return QVector<QSharedPointer<DataTypeInfo>>(); }
|
||||
virtual QSharedPointer<DataTypeInfo> innerDataType() const { return QSharedPointer<DataTypeInfo>(); }
|
||||
|
||||
static QSharedPointer<DataTypeInfo> fromIdlDataType(const QString &name,
|
||||
const QString &idlType,
|
||||
StructBuilder *structBuilder,
|
||||
const QString &svcName = QString());
|
||||
protected:
|
||||
const QString m_name;
|
||||
const bool m_isPod;
|
||||
};
|
||||
|
||||
struct IdlData : public IdlColumnInformation
|
||||
{
|
||||
QSharedPointer<DataTypeInfo> dataTypeInfo;
|
||||
|
||||
IdlData() = default;
|
||||
explicit IdlData(const IdlColumnInformation &ci)
|
||||
: IdlColumnInformation(ci)
|
||||
{}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return name +
|
||||
QLatin1Char(';') + type +
|
||||
// QLatin1Char(';') + comment +
|
||||
QLatin1Char(';') + (isKey ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + (isOptional ? QLatin1String("true") : QLatin1String("false"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct CppData
|
||||
{
|
||||
QString structName;
|
||||
QString memberName;
|
||||
QString defaultValue;
|
||||
bool usedForCppStruct = false;
|
||||
bool usedForJson = false;
|
||||
bool isReadOnly = false;
|
||||
bool isOptional = false;
|
||||
QString type;
|
||||
QString ddsType; // = type, except for e.g. QByteArray
|
||||
QString toVariantPre; // e.g. static_cast<int>(
|
||||
QString toVariantPost; // e.g. .x())
|
||||
QString fromVariantPre1; // before ' = '
|
||||
QString fromVariantPre2; // after ' = '
|
||||
QString fromVariantPost;
|
||||
|
||||
QString toJsonPre;
|
||||
QString toJsonPost;
|
||||
QString fromJsonPre2;
|
||||
QString fromJsonPost;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return structName +
|
||||
QLatin1Char(';') + memberName +
|
||||
QLatin1Char(';') + (usedForCppStruct ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + (isReadOnly ? QLatin1String("true") : QLatin1String("false")) +
|
||||
QLatin1Char(';') + type +
|
||||
QLatin1Char(';') + toVariantPre +
|
||||
QLatin1Char(';') + toVariantPost +
|
||||
QLatin1Char(';') + fromVariantPre1 +
|
||||
QLatin1Char(';') + fromVariantPre2 +
|
||||
QLatin1Char(';') + fromVariantPost;
|
||||
}
|
||||
};
|
||||
|
||||
struct MemberInformation
|
||||
{
|
||||
EaData ea;
|
||||
FullQualifiedColumnInformation db;
|
||||
CppData cpp;
|
||||
bool isDdsKey = false;
|
||||
QSharedPointer<ForeignKeyInformation> fk;
|
||||
QSharedPointer<EnumInformation> enumeration;
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return ea.toString() + QLatin1Char(';') +
|
||||
db.toString() + QLatin1Char(';') +
|
||||
cpp.toString();
|
||||
}
|
||||
bool isEmpty() const
|
||||
{
|
||||
return ea.column.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompleteStructInformation
|
||||
{
|
||||
QString structName;
|
||||
QString viewName;
|
||||
QSet<QSharedPointer<TableInformation> > tables;
|
||||
QSharedPointer<TableInformation> primaryTable;
|
||||
QVector<MemberInformation> member;
|
||||
QVector<DbNotifcationInformation> dbNotifications;
|
||||
bool hasStaticContent = false;
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return primaryTable.isNull();
|
||||
}
|
||||
};
|
||||
|
||||
struct CompleteTopicTypeInformation final : public TopicTypeInformationBase
|
||||
{
|
||||
QString serviceName;
|
||||
|
||||
QVector<IdlData> members;
|
||||
|
||||
CompleteTopicTypeInformation() = default;
|
||||
explicit CompleteTopicTypeInformation(const TopicTypeInformationBase &s)
|
||||
: TopicTypeInformationBase(s)
|
||||
{}
|
||||
|
||||
bool hasBaseValue() const { return !baseValueType.isEmpty(); }
|
||||
bool isValid() const { return TopicTypeInformationBase::isValid() && !members.isEmpty(); }
|
||||
};
|
||||
|
||||
|
||||
struct CompleteTableInformation : public TableInformation
|
||||
{
|
||||
QVector<MemberInformation> columns;
|
||||
explicit CompleteTableInformation(const TableInformation &o)
|
||||
: TableInformation(o)
|
||||
{}
|
||||
CompleteTableInformation() = default;
|
||||
bool isEmpty() const { return columns.isEmpty(); }
|
||||
};
|
||||
|
||||
class CODEGEN_BASE_EXPORT StructBuilder
|
||||
{
|
||||
struct ColumnInformationEx : public ColumnInformation
|
||||
{
|
||||
QSharedPointer<TableInformation> table;
|
||||
|
||||
ColumnInformationEx() = default;
|
||||
ColumnInformationEx(const ColumnInformation &o,
|
||||
const QSharedPointer<TableInformation> &ti)
|
||||
: ColumnInformation(o)
|
||||
, table(ti)
|
||||
{}
|
||||
};
|
||||
|
||||
public:
|
||||
struct ServiceTypeStruct
|
||||
{
|
||||
QString service;
|
||||
QString type;
|
||||
bool bIsSequence = false;
|
||||
bool isExternalType() const { return !service.isEmpty(); }
|
||||
bool isSequence() const { return bIsSequence; }
|
||||
QString fqType() const { return service + QStringLiteral("::") + type; }
|
||||
};
|
||||
|
||||
explicit StructBuilder(XmlReader *xmlReader);
|
||||
~StructBuilder() = default;
|
||||
|
||||
bool buildStructures();
|
||||
QVector<CompleteStructInformation> structInformations() const
|
||||
{
|
||||
return m_structInfos;
|
||||
}
|
||||
QVector<CompleteTopicTypeInformation> topicTypeInformations() const
|
||||
{
|
||||
return m_topicTypeInfos;
|
||||
}
|
||||
|
||||
CompleteStructInformation structInformationByTableName(const QString &tableName) const;
|
||||
|
||||
EnumInformation enumInformationByType(const QString &type, bool checkExternals = true, bool verbose = true);
|
||||
|
||||
CompleteTopicTypeInformation topicTypeInformationByStructType(const QString &type, bool checkExternals = true);
|
||||
CompleteTopicTypeInformation externalTopicTypeByStructType(const ServiceTypeStruct &sts);
|
||||
|
||||
QVector<EnumInformation> enumInformations() const
|
||||
{
|
||||
return m_enumInfos;
|
||||
}
|
||||
|
||||
QMap<QString, CompleteTableInformation> getDbTables() const
|
||||
{
|
||||
return m_sqlTableInformations;
|
||||
}
|
||||
|
||||
QMap<QString, ViewInformation> getDbViews() const
|
||||
{
|
||||
return m_sqlViewInformations;
|
||||
}
|
||||
|
||||
bool needPoint3d() const
|
||||
{
|
||||
return m_needPoint3d;
|
||||
}
|
||||
|
||||
bool needPgArrayInclude() const
|
||||
{
|
||||
return m_needPgArrayInclude;
|
||||
}
|
||||
|
||||
CompleteTableInformation completeTableInformation(const CompleteTopicTypeInformation &ctti);
|
||||
CompleteTableInformation getRecordingTopicTable(const QString &structName);
|
||||
QMap<QString, CompleteTableInformation> getRecordingTopicTables();
|
||||
QVector<QSharedPointer<DataTypeInfo> > getSerializeFromToJsonTopics() const;
|
||||
bool fixupQVariantConversions(MemberInformation &mi) const;
|
||||
|
||||
Q_REQUIRED_RESULT static QString firstCharLowercase(const QString &txt);
|
||||
Q_REQUIRED_RESULT static QString camelCaseString(const QString &in, bool bFirstUppercase = false);
|
||||
Q_REQUIRED_RESULT static QString camelCaseToUnderline(const QString &in);
|
||||
|
||||
bool buildJSonStructureInformationFromIdlData(const CompleteTopicTypeInformation &ctti);
|
||||
QMap<QString, QVector<MemberInformation>> jsonStructureInformation() const { return m_jsonStructureInformation; }
|
||||
|
||||
private:
|
||||
bool handleEnum(const EnumInformation &ei);
|
||||
bool handleTable(const ServiceStructInformation &ssi);
|
||||
bool handleIdlStructInfo(const TopicTypeInformation &tti,
|
||||
QVector<CompleteTopicTypeInformation> &destination,
|
||||
const QString &svcName = QString());
|
||||
bool loadExternalTopicType(const ServiceTypeStruct &sts);
|
||||
|
||||
bool getColumnsFromTable(const QString &tableName,
|
||||
QVector<ColumnInformationEx> &columns,
|
||||
QVector<QString> &tableNames) const;
|
||||
|
||||
bool fixupCustomDbDatatypes(MemberInformation &memberInfo, QVector<MemberInformation> &members);
|
||||
bool fixupDatatypePoint2d(MemberInformation &memberInfo, QVector<MemberInformation> &members);
|
||||
bool fixupDatatypePoint3d(MemberInformation &memberInfo, QVector<MemberInformation> &members);
|
||||
bool fixupDatatypeIntegerArray(MemberInformation &memberInfo);
|
||||
|
||||
QVector<MemberInformation> buildDbTableInformationFromIdlData(const CompleteTopicTypeInformation &ctti,
|
||||
const QString &tableName,
|
||||
const QString &columnNamePrefix,
|
||||
const QString &cppStructure);
|
||||
void addToSerializeFromToJsonTopics(const QSharedPointer<DataTypeInfo> &toAdd);
|
||||
CompleteTableInformation getRecordingTopicTable(const CompleteTopicTypeInformation &ctti,
|
||||
const MemberInformation &miPrimaryKey);
|
||||
MemberInformation getRecordPrimaryKey() const;
|
||||
|
||||
ServiceTypeStruct extractServiceAndTypeFromTypename(const QString &type);
|
||||
|
||||
void addToSqlTableInformation(const MemberInformation &mi);
|
||||
private:
|
||||
QVector<CompleteStructInformation> m_structInfos;
|
||||
QVector<CompleteTopicTypeInformation> m_topicTypeInfos;
|
||||
mutable QVector<CompleteTopicTypeInformation> m_externalTopicTypes;
|
||||
QVector<EnumInformation> m_enumInfos;
|
||||
QMap<QString, CompleteTableInformation> m_sqlTableInformations;
|
||||
QMap<QString, ViewInformation> m_sqlViewInformations;
|
||||
QSet<QString> m_sqlTableInformationsAlreadyAvailable;
|
||||
QVector<QSharedPointer<DataTypeInfo>> m_serializeFromToJsonTopics;
|
||||
|
||||
QMap<QString, QVector<MemberInformation>> m_jsonStructureInformation;
|
||||
|
||||
bool m_needPoint3d; // need include of 'qpoint3d.h'
|
||||
bool m_needPgArrayInclude; // need include of 'LtsUtilsCore/pgarray.h'
|
||||
|
||||
XmlReader *m_xmlReader;
|
||||
NGL::INGLLogger &m_logger;
|
||||
NGL::INGLLogger &m_loggerCSV;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,941 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Read Xml service files
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#include "XmlReader.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QDomDocument>
|
||||
#include <QXmlStreamReader>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
using namespace CodeGen;
|
||||
|
||||
|
||||
class XmlReaderException : public std::exception
|
||||
{
|
||||
public:
|
||||
explicit XmlReaderException(const QString &msg) noexcept
|
||||
: m_msg(msg.toUtf8())
|
||||
{}
|
||||
|
||||
~XmlReaderException() = default;
|
||||
|
||||
virtual const char *what() const noexcept
|
||||
{
|
||||
return m_msg.data();
|
||||
}
|
||||
private:
|
||||
const QByteArray m_msg;
|
||||
};
|
||||
|
||||
XmlReader::XmlReader()
|
||||
: m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.XmlReader"))
|
||||
{}
|
||||
|
||||
bool XmlReader::readServiceFile(const QString &svcFile,
|
||||
const QString &idlServiceInfoFile,
|
||||
const XmlReader *parent)
|
||||
{
|
||||
m_externalXmlInformations.clear();
|
||||
m_idlFiles.clear();
|
||||
m_xmlFiles.clear();
|
||||
m_usedServices.clear();
|
||||
m_fullServiceName2Abbreviation.clear();
|
||||
// clean up
|
||||
m_svcNamespace.clear();
|
||||
m_svcAbbr.clear();
|
||||
m_svcProcNames.clear();
|
||||
m_customRecordReplay = false;
|
||||
m_exerciseDependency = ExerciseDependency::Exercise;
|
||||
m_dbClassTables.clear();
|
||||
m_struct2BaseClass.clear();
|
||||
m_structsToGenerate.clear();
|
||||
m_idlStructsToGenerate.clear();
|
||||
m_tables.clear();
|
||||
m_views.clear();
|
||||
m_enumerations.clear();
|
||||
m_functionTopics.clear();
|
||||
m_externalTopicTypes.clear();
|
||||
m_customFunctions.clear();
|
||||
m_prio = 0;
|
||||
m_svcDevMode = false;
|
||||
|
||||
// avoid parsing unneeded files
|
||||
if (parent)
|
||||
{
|
||||
m_idlFiles = parent->m_idlFiles;
|
||||
m_xmlFiles = parent->m_xmlFiles;
|
||||
m_fullServiceName2Abbreviation = parent->m_fullServiceName2Abbreviation;
|
||||
m_externalXmlInformations = parent->m_externalXmlInformations;
|
||||
}
|
||||
|
||||
|
||||
// load informations about the location of all idl files
|
||||
loadIdlInfofile(idlServiceInfoFile);
|
||||
|
||||
// try to open the service file
|
||||
QFile f(svcFile);
|
||||
if (!f.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Service file '" << svcFile << "' not found!";
|
||||
return false;
|
||||
}
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
m_errorString = QLatin1String("Can not open service file '") + svcFile +
|
||||
QLatin1String("' for reading: ") + f.errorString();
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "SvcFile: " << svcFile;
|
||||
|
||||
// read content
|
||||
QString errMsg;
|
||||
int errLine = 0;
|
||||
int errColumn = 0;
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(&f, &errMsg, &errLine, &errColumn))
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing service file '") + svcFile + QLatin1String("': ") +
|
||||
errMsg + QLatin1String(" at ") + QString::number(errLine) +
|
||||
QLatin1Char(':') + QString::number(errColumn);
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
// now finally read the data
|
||||
// what do we expect?
|
||||
// - a service name ( plus service abbreviation i.e. AES)
|
||||
// - service classes to generate (dbServiceStructs)
|
||||
// - database tables to generate (tables)
|
||||
// - static enumerations to generate (enumerations)
|
||||
// - idl structures for topicTypes (idlStructs)
|
||||
// - a devMode attribute which is optional
|
||||
QDomElement domRoot = doc.documentElement();
|
||||
if (!domRoot.hasAttribute(QStringLiteral("namespace")))
|
||||
{
|
||||
m_errorString = QLatin1String("Xml file '") + svcFile +
|
||||
QLatin1String("' is not a valid service file: service name/namespace is missing");
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
m_svcNamespace = getAttribute(domRoot, QStringLiteral("namespace"));
|
||||
m_svcAbbr = getAttribute(domRoot, QStringLiteral("abbreviation")).toLower();
|
||||
m_svcProcNames = getAttribute(domRoot, QStringLiteral("procNames")).split(QLatin1Char(','));
|
||||
m_customRecordReplay = getAttributeBool(domRoot, QStringLiteral("customRecordReplay"), true, false);
|
||||
|
||||
QString devModeStr = getAttribute(domRoot, QStringLiteral("devMode"), true);
|
||||
m_svcDevMode = devModeStr == QStringLiteral("1") ||
|
||||
devModeStr == QStringLiteral("true");
|
||||
INFO_LOG(m_logger) << "devMode: " << m_svcDevMode;
|
||||
|
||||
const QString groupNamesString = getAttribute(domRoot, QStringLiteral("groups"), true);
|
||||
if (!groupNamesString.isEmpty())
|
||||
{
|
||||
m_groupNames = groupNamesString.split(QLatin1Char(','), QString::SkipEmptyParts);
|
||||
INFO_LOG(m_logger) << "groups: " << groupNamesString;
|
||||
}
|
||||
else
|
||||
m_groupNames.clear();
|
||||
|
||||
m_exerciseDependency = string2ExerciseDependency(getAttribute(domRoot, QStringLiteral("exerciseDependency"), true));
|
||||
// exerciseIndepenent only if in core/master group AND no other groups
|
||||
// core + other groups => one instance of service is svc_0
|
||||
// other instances are svc_<exerciseId>
|
||||
if (m_groupNames.contains(QStringLiteral("Core")) ||
|
||||
m_groupNames.contains(QStringLiteral("Master")))
|
||||
{
|
||||
if (m_exerciseDependency != ExerciseDependency::Global &&
|
||||
m_exerciseDependency != ExerciseDependency::GlobalAndExercise)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Service " << getServiceNamespace()
|
||||
<< " is not marked as exercise independent but should be started in group Core/Master";
|
||||
}
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "exerciseDependency: " << (int)m_exerciseDependency;
|
||||
if ( domRoot.hasAttribute(QStringLiteral("prio")))
|
||||
{
|
||||
m_prio = getAttribute(domRoot, QStringLiteral("prio"), 0).toInt();
|
||||
}
|
||||
try
|
||||
{
|
||||
parseDBSserviceStructs(domRoot.firstChildElement(QStringLiteral("dbServiceStructs")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbServiceStructs: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseDBTables(domRoot.firstChildElement(QStringLiteral("tables")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbtables: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseDBViews(domRoot.firstChildElement(QStringLiteral("views")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing dbviews: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseEnumerations(domRoot.firstChildElement(QStringLiteral("enumerations")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing enumerations: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseCustomDtcFunctions(domRoot.firstChildElement(QStringLiteral("customDtcFunctions")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing custom dtc functions: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseTopicTypes(domRoot.firstChildElement(QStringLiteral("topicTypes")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing idl strucs: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parseFunctionTopics(domRoot.firstChildElement(QStringLiteral("functionTopics")));
|
||||
}
|
||||
catch (const XmlReaderException &ex)
|
||||
{
|
||||
m_errorString = QLatin1String("Error parsing function topics: ") + QLatin1String(ex.what());
|
||||
ERROR_LOG(m_logger) << m_errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString XmlReader::getAttribute(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional)
|
||||
{
|
||||
if (!element.hasAttribute(attributeName))
|
||||
{
|
||||
if (bOptional)
|
||||
return QString();
|
||||
throw XmlReaderException(QLatin1String("Element ") + element.tagName() +
|
||||
QLatin1String(" has no attribute ") + attributeName);
|
||||
}
|
||||
return element.attribute(attributeName);
|
||||
}
|
||||
|
||||
bool XmlReader::getAttributeBool(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional, bool defaultValue)
|
||||
{
|
||||
QString str = getAttribute(element, attributeName, bOptional);
|
||||
if (str.isEmpty())
|
||||
return defaultValue;
|
||||
bool bOk;
|
||||
bool ret = (str.toInt(&bOk) != 0);
|
||||
if (!bOk)
|
||||
throw XmlReaderException(QLatin1String("Can not parse boolean value: ") + str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int XmlReader::getAttributeInt(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional, int defaultValue)
|
||||
{
|
||||
QString str = getAttribute(element, attributeName, bOptional);
|
||||
if (str.isEmpty())
|
||||
return defaultValue;
|
||||
bool bOk;
|
||||
int ret = str.toInt(&bOk);
|
||||
if (!bOk)
|
||||
{
|
||||
//try from base16
|
||||
ret = str.toUInt(&bOk,16);
|
||||
if(!bOk)
|
||||
throw XmlReaderException(QLatin1String("Can not parse int value: ") + str);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void XmlReader::parseDBSserviceStructs(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
// service struct -> table relations
|
||||
QDomElement domDbStruct = rootElement.firstChildElement(QStringLiteral("serviceStruct"));
|
||||
while (!domDbStruct.isNull())
|
||||
{
|
||||
ServiceStructInformation ssi;
|
||||
ssi.name = getAttribute(domDbStruct, QStringLiteral("name"));
|
||||
ssi.primaryTable = getAttribute(domDbStruct, QStringLiteral("table"));
|
||||
ssi.hasStaticContent = getAttributeBool(domDbStruct, QStringLiteral("static"), true, false);
|
||||
|
||||
QDomElement domFunc = domDbStruct.firstChildElement(QStringLiteral("function"));
|
||||
while (!domFunc.isNull())
|
||||
{
|
||||
m_customFunctions += parseCustomFunction(domFunc, CustomServiceFunctionInformation::Type::Db);
|
||||
domFunc = domFunc.nextSiblingElement(domFunc.tagName());
|
||||
}
|
||||
|
||||
QDomElement domNotify = domDbStruct.firstChildElement(QStringLiteral("notification"));
|
||||
while (!domNotify.isNull())
|
||||
{
|
||||
ssi.dbNotifications.append(parseDbNotification(domNotify));
|
||||
domNotify = domNotify.nextSiblingElement(domNotify.tagName());
|
||||
}
|
||||
|
||||
m_structsToGenerate.push_back(ssi);
|
||||
|
||||
domDbStruct = domDbStruct.nextSiblingElement(domDbStruct.tagName());
|
||||
}
|
||||
std::sort(m_structsToGenerate.begin(), m_structsToGenerate.end());
|
||||
|
||||
// table -> parent table relations
|
||||
domDbStruct = rootElement.firstChildElement(QStringLiteral("table"));
|
||||
while (!domDbStruct.isNull())
|
||||
{
|
||||
const QString table = getAttribute(domDbStruct, QStringLiteral("name"));
|
||||
const QString parentTable = getAttribute(domDbStruct, QStringLiteral("base"), true);
|
||||
m_struct2BaseClass[table] = parentTable;
|
||||
|
||||
domDbStruct = domDbStruct.nextSiblingElement(domDbStruct.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_structsToGenerate.size() << " database service struct(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseDBTables(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domDbTable = rootElement.firstChildElement(QStringLiteral("table"));
|
||||
while (!domDbTable.isNull())
|
||||
{
|
||||
QSharedPointer<TableInformation> ti(new TableInformation);
|
||||
ti->name = getAttribute(domDbTable, QStringLiteral("name"));
|
||||
ti->structName = QLatin1String("t_") + ti->name;
|
||||
ti->comment = getAttribute(domDbTable, QStringLiteral("comment"), true);
|
||||
ti->exerciseDependency = string2ExerciseDependency(getAttribute(domDbTable, QStringLiteral("exerciseDependency"), true));
|
||||
|
||||
QDomElement domColumn = domDbTable.firstChildElement(QStringLiteral("column"));
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
ti->plainColumns.append(parseTableColumn(domColumn, ti->name));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
|
||||
QDomElement domForeignKey = domDbTable.firstChildElement(QStringLiteral("foreignKey"));
|
||||
while (!domForeignKey.isNull())
|
||||
{
|
||||
ti->foreignKeys.append(parseForeignKey(domForeignKey));
|
||||
domForeignKey = domForeignKey.nextSiblingElement(domForeignKey.tagName());
|
||||
}
|
||||
QDomElement domConstraint = domDbTable.firstChildElement(QStringLiteral("constraint"));
|
||||
while (!domConstraint.isNull())
|
||||
{
|
||||
ti->constraints.append(parseConstraint(domConstraint));
|
||||
domConstraint = domConstraint.nextSiblingElement(domConstraint.tagName());
|
||||
}
|
||||
|
||||
m_tables.insert(ti->name, ti);
|
||||
|
||||
domDbTable = domDbTable.nextSiblingElement(domDbTable.tagName());
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_tables.size() << " database table(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseDBViews(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domDbView = rootElement.firstChildElement(QStringLiteral("view"));
|
||||
while (!domDbView.isNull())
|
||||
{
|
||||
QSharedPointer<ViewInformation> vi(new ViewInformation);
|
||||
vi->name = getAttribute(domDbView, QStringLiteral("name"));
|
||||
vi->structName = QLatin1String("v_") + vi->name;
|
||||
vi->baseSchema = m_svcAbbr;
|
||||
vi->baseTable = getAttribute(domDbView, QStringLiteral("base"));
|
||||
vi->comment = getAttribute(domDbView, QStringLiteral("comment"), true);
|
||||
vi->filter = getAttribute(domDbView, QStringLiteral("filter"));
|
||||
vi->exerciseDependency = string2ExerciseDependency(getAttribute(domDbView, QStringLiteral("exerciseDependency"), true));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Base table = " << vi->baseTable;
|
||||
/*
|
||||
QDomElement domConstraint = domDbView.firstChildElement(QStringLiteral("constraint"));
|
||||
while (!domConstraint.isNull())
|
||||
{
|
||||
vi->constraints.append(parseConstraint(domConstraint));
|
||||
domConstraint = domConstraint.nextSiblingElement(domConstraint.tagName());
|
||||
}
|
||||
*/
|
||||
m_views.insert(vi->name, vi);
|
||||
|
||||
domDbView = domDbView.nextSiblingElement(domDbView.tagName());
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_views.size() << " database view(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseEnumerations(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domEnum = rootElement.firstChildElement(QStringLiteral("enumeration"));
|
||||
while (!domEnum.isNull())
|
||||
{
|
||||
EnumInformation enumeration;
|
||||
enumeration.serviceName = getServiceNamespace();
|
||||
enumeration.enumName = getAttribute(domEnum, QStringLiteral("name"));
|
||||
enumeration.tableName = getAttribute(domEnum, QStringLiteral("table"), true);
|
||||
|
||||
QDomElement enumVal = domEnum.firstChildElement(QStringLiteral("attribute"));
|
||||
while (!enumVal.isNull())
|
||||
{
|
||||
EnumKeyValuePair evp;
|
||||
evp.key = getAttribute(enumVal, QStringLiteral("key"));
|
||||
evp.value = getAttributeInt(enumVal, QStringLiteral("value"));
|
||||
enumeration.values.append(evp);
|
||||
|
||||
enumVal = enumVal.nextSiblingElement(enumVal.tagName());
|
||||
}
|
||||
|
||||
m_enumerations.push_back(enumeration);
|
||||
|
||||
domEnum = domEnum.nextSiblingElement(domEnum.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_enumerations.size() << " enumeration(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseCustomDtcFunctions(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
QDomElement domElement = rootElement.firstChildElement(QStringLiteral("customDtcFunction"));
|
||||
while (!domElement.isNull())
|
||||
{
|
||||
|
||||
QDomElement domFunc = domElement.firstChildElement(QStringLiteral("function"));
|
||||
while (!domFunc.isNull())
|
||||
{
|
||||
m_customFunctions += parseCustomFunction(domFunc, CustomServiceFunctionInformation::Type::Dtc);
|
||||
domFunc = domFunc.nextSiblingElement(domFunc.tagName());
|
||||
}
|
||||
domElement = domElement.nextSiblingElement(domElement.tagName());
|
||||
}
|
||||
INFO_LOG(m_logger) << "Read " << m_enumerations.size() << " customDtcFunction(s)";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse idl structure (TopicType Information)
|
||||
* (IDL = Interface Definition Language)
|
||||
* @param rootElement
|
||||
*/
|
||||
void XmlReader::parseTopicTypes(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
// idl struct
|
||||
QDomElement domIdlStruct = rootElement.firstChildElement(QStringLiteral("topicType"));
|
||||
while (!domIdlStruct.isNull())
|
||||
{
|
||||
TopicTypeInformation isi;
|
||||
isi.name = getAttribute(domIdlStruct, QStringLiteral("name"));
|
||||
isi.baseValueType = getAttribute(domIdlStruct, QStringLiteral("baseValueType"), true);
|
||||
|
||||
// preload some external topics to be able to know which external services we're using
|
||||
const QVector<QStringRef> sl = isi.baseValueType.splitRef(QStringLiteral("::"));
|
||||
if (sl.size() == 2)
|
||||
loadExternalTopicType(sl.at(0).toString(), sl.at(1).toString());
|
||||
|
||||
const QString tmp = getAttribute(domIdlStruct, QStringLiteral("extensibility"), true);
|
||||
|
||||
if (tmp.compare(QLatin1String("FINAL"), Qt::CaseInsensitive) == 0) isi.extensibility = dds::core::xtypes::ExtensibilityKind::FINAL;
|
||||
if (tmp.compare(QLatin1String("MUTABLE"), Qt::CaseInsensitive) == 0) isi.extensibility = dds::core::xtypes::ExtensibilityKind::MUTABLE;
|
||||
if (tmp.compare(QLatin1String("EXTENSIBLE"), Qt::CaseInsensitive) == 0) isi.extensibility = dds::core::xtypes::ExtensibilityKind::EXTENSIBLE;
|
||||
|
||||
isi.comment = getAttribute(domIdlStruct, QStringLiteral("comment"), true);
|
||||
isi.isDataObject = getAttributeBool(domIdlStruct, QStringLiteral("isDataObject"), true, false);
|
||||
isi.dtsAutogen = getAttributeBool(domIdlStruct, QStringLiteral("autogenDTS"), true, true);
|
||||
isi.dtcAutogen = getAttributeBool(domIdlStruct, QStringLiteral("autogenDTC"), true, true);
|
||||
isi.recordTopic = getAttributeBool(domIdlStruct, QStringLiteral("recordTopic"), true, false);
|
||||
isi.routeToClient = getAttributeBool(domIdlStruct, QStringLiteral("routeToClient"), true, true);
|
||||
isi.routeToServer = getAttributeBool(domIdlStruct, QStringLiteral("routeToServer"), true, false);
|
||||
isi.routeInReplay = getAttributeBool(domIdlStruct, QStringLiteral("routeInReplay"), true, false);
|
||||
isi.autosubscribe = getAttributeBool(domIdlStruct, QStringLiteral("autosubscribe"), true, true);
|
||||
|
||||
QDomElement domColumn = domIdlStruct.firstChildElement(QStringLiteral("column"));
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
isi.columns.append(parseIdlStructColumn(domColumn));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
|
||||
//INFO_LOG(m_logger) << "# TopicType: " << isi.name;
|
||||
m_idlStructsToGenerate.insert(isi.name, isi);
|
||||
|
||||
domIdlStruct = domIdlStruct.nextSiblingElement(domIdlStruct.tagName());
|
||||
}
|
||||
|
||||
|
||||
INFO_LOG(m_logger) << "Read " << m_idlStructsToGenerate.size() << " idl struct(s)";
|
||||
}
|
||||
|
||||
void XmlReader::parseFunctionTopics(const QDomElement &rootElement)
|
||||
{
|
||||
if (rootElement.isNull())
|
||||
return;
|
||||
|
||||
// idl struct
|
||||
QDomElement domFunctionTopic = rootElement.firstChildElement(QStringLiteral("functionTopic"));
|
||||
while (!domFunctionTopic.isNull())
|
||||
{
|
||||
FunctionTopic ft;
|
||||
ft.name = getAttribute(domFunctionTopic, QStringLiteral("name"));
|
||||
ft.requestTopicType = getAttribute(domFunctionTopic, QStringLiteral("requestTopicType"));
|
||||
ft.replyTopicType = getAttribute(domFunctionTopic, QStringLiteral("replyTopicType"));
|
||||
ft.requestTopicName = getAttribute(domFunctionTopic, QStringLiteral("requestTopicName"));
|
||||
ft.replyTopicName = getAttribute(domFunctionTopic, QStringLiteral("replyTopicName"));
|
||||
ft.routeInReplay = getAttributeBool(domFunctionTopic, QStringLiteral("routeInReplay"), true, false);
|
||||
|
||||
m_functionTopics.append(ft);
|
||||
|
||||
domFunctionTopic = domFunctionTopic.nextSiblingElement(domFunctionTopic.tagName());
|
||||
}
|
||||
|
||||
for (const FunctionTopic &ft : qAsConst(m_functionTopics))
|
||||
{
|
||||
const QVector<QStringRef> sl1 = ft.requestTopicType.splitRef(QStringLiteral("::"));
|
||||
if (sl1.size() == 2)
|
||||
loadExternalTopicType(sl1.at(0).toString(), sl1.at(1).toString());
|
||||
const QVector<QStringRef> sl2 = ft.replyTopicType.splitRef(QStringLiteral("::"));
|
||||
if (sl2.size() == 2)
|
||||
loadExternalTopicType(sl2.at(0).toString(), sl2.at(1).toString());
|
||||
}
|
||||
}
|
||||
|
||||
ColumnInformation XmlReader::parseTableColumn(const QDomElement &column, const QString &tableName) const
|
||||
{
|
||||
ColumnInformation ci;
|
||||
|
||||
ci.columnName = getAttribute(column, QStringLiteral("name"));
|
||||
ci.datatype = getAttribute(column, QStringLiteral("datatype"));
|
||||
ci.defaultValue = getAttribute(column, QStringLiteral("default"), true);
|
||||
ci.comment = getAttribute(column, QStringLiteral("comment"), true);
|
||||
ci.isPrimaryKey = getAttributeBool(column, QStringLiteral("isPrimaryKey"), true, false);
|
||||
ci.isForeignKey = getAttributeBool(column, QStringLiteral("isForeignKey"), true, false);
|
||||
ci.isOptional = getAttributeBool(column, QStringLiteral("isOptional"), true, false);
|
||||
const QDomElement seq = column.firstChildElement(QStringLiteral("sequence"));
|
||||
if (!seq.isNull())
|
||||
{
|
||||
ci.sequenceStart = getAttributeInt(seq, QStringLiteral("start"), true, -1);
|
||||
ci.sequenceIncrement = getAttributeInt(seq, QStringLiteral("increment"), true, -1);
|
||||
ci.hasSequence = ci.sequenceStart >= 0 && ci.sequenceIncrement > 0;
|
||||
}
|
||||
|
||||
if (ci.columnName.toLower() != ci.columnName)
|
||||
WARNING_LOG(m_logger) << "Column " << ci.columnName << " in Table "
|
||||
<< tableName << " has has upper-case chars which is not allowed!";
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
IdlColumnInformation XmlReader::parseIdlStructColumn(const QDomElement &column) const
|
||||
{
|
||||
IdlColumnInformation ci;
|
||||
|
||||
ci.name = getAttribute(column, QStringLiteral("name"));
|
||||
ci.type = getAttribute(column, QStringLiteral("idlType"));
|
||||
ci.comment = getAttribute(column, QStringLiteral("comment"), true);
|
||||
ci.isKey = getAttributeBool(column, QStringLiteral("isKey"), true, false);
|
||||
ci.isOptional = getAttributeBool(column, QStringLiteral("isOptional"), true, false);
|
||||
ci.isTranslatable = getAttributeBool(column, QStringLiteral("isTranslatable"), true, false);
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> XmlReader::parseForeignKey(const QDomElement &foreignKey) const
|
||||
{
|
||||
QSharedPointer<ForeignKeyInformation> fk(new ForeignKeyInformation);
|
||||
|
||||
fk->name = getAttribute(foreignKey, QStringLiteral("name"));
|
||||
// Default-Value of isOnDeleteCascade => true
|
||||
const QString deleteAction = getAttribute(foreignKey, QStringLiteral("referential_integrity"), true);
|
||||
if (deleteAction == QLatin1String("DeleteNoAction"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::NoAction;
|
||||
else if (deleteAction == QLatin1String("DeleteCascade"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Cascade;
|
||||
else if (deleteAction == QLatin1String("DeleteRestrict"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Restrict;
|
||||
else if (deleteAction == QLatin1String("DeleteSetNull"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::SetNull;
|
||||
else if (deleteAction == QLatin1String("DeleteSetDefault"))
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::SetDefault;
|
||||
else
|
||||
fk->deleteAction = ForeignKeyInformation::OnDeleteAction::Cascade; // default
|
||||
|
||||
fk->source = parseForeignKeyEndpoint(fk->name, foreignKey.firstChildElement(QStringLiteral("source")));
|
||||
fk->destination = parseForeignKeyEndpoint(fk->name, foreignKey.firstChildElement(QStringLiteral("destination")));
|
||||
|
||||
return fk;
|
||||
}
|
||||
|
||||
ForeignKeyInformation::Endpoint XmlReader::parseForeignKeyEndpoint(const QString &foreignKeyName,
|
||||
const QDomElement &endpoint) const
|
||||
{
|
||||
if (endpoint.isNull())
|
||||
throw XmlReaderException(QLatin1String("No endpoint for foreign key ") + foreignKeyName);
|
||||
|
||||
ForeignKeyInformation::Endpoint fkEndpoint;
|
||||
|
||||
fkEndpoint.service = getAttribute(endpoint, QStringLiteral("service"), true);
|
||||
fkEndpoint.serviceAbbr= getAttribute(endpoint, QStringLiteral("serviceAbbr"), true);
|
||||
fkEndpoint.schema = getAttribute(endpoint, QStringLiteral("schema"), true);
|
||||
fkEndpoint.tableName = getAttribute(endpoint, QStringLiteral("table"));
|
||||
fkEndpoint.columnName = getAttribute(endpoint, QStringLiteral("column"));
|
||||
|
||||
return fkEndpoint;
|
||||
}
|
||||
|
||||
ConstraintInformation XmlReader::parseConstraint(const QDomElement &constraint) const
|
||||
{
|
||||
ConstraintInformation ret;
|
||||
|
||||
ret.name = getAttribute(constraint, QStringLiteral("name"), true);
|
||||
const QString type = getAttribute(constraint, QStringLiteral("type")).toLower();
|
||||
if (type == QLatin1String("unique"))
|
||||
ret.type = ConstraintInformation::Type::unique;
|
||||
else if (type == QLatin1String("index"))
|
||||
ret.type = ConstraintInformation::Type::index;
|
||||
|
||||
QDomElement domColumn = constraint.firstChildElement(QStringLiteral("column"));
|
||||
if (domColumn.isNull())
|
||||
throw XmlReaderException(QLatin1String("No column for constraint") + ret.name);
|
||||
while (!domColumn.isNull())
|
||||
{
|
||||
ret.affectedColumns += getAttribute(domColumn, QStringLiteral("name"));
|
||||
domColumn = domColumn.nextSiblingElement(domColumn.tagName());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CustomServiceFunctionInformation XmlReader::parseCustomFunction(const QDomElement &customFunc,
|
||||
CustomServiceFunctionInformation::Type funcType) const
|
||||
{
|
||||
CustomServiceFunctionInformation ret;
|
||||
ret.methodName = getAttribute(customFunc, QStringLiteral("name"));
|
||||
ret.returnValue = getAttribute(customFunc, QStringLiteral("returns"), true);
|
||||
ret.isConst = getAttributeBool(customFunc, QStringLiteral("isConst"), true, false);
|
||||
if (ret.returnValue.isEmpty())
|
||||
ret.returnValue = QStringLiteral("bool");
|
||||
QMap<int, QPair<QString, QString>> paramHelper;
|
||||
QDomElement domParam = customFunc.firstChildElement(QStringLiteral("parameter"));
|
||||
while (!domParam.isNull())
|
||||
{
|
||||
int pos = getAttributeInt(domParam, QStringLiteral("pos"));
|
||||
if (paramHelper.contains(pos))
|
||||
throw XmlReaderException(QLatin1String("Doubled position entry for custom function ") + ret.methodName);
|
||||
QString paramName = getAttribute(domParam, QStringLiteral("name"));
|
||||
const QString paramType = getAttribute(domParam, QStringLiteral("type"));
|
||||
const QString paramDefault = getAttribute(domParam, QStringLiteral("default"), true);
|
||||
if (!paramDefault.isEmpty())
|
||||
paramName.append(QLatin1String(" = ") + paramDefault);
|
||||
paramHelper[pos] = qMakePair(paramName, paramType);
|
||||
domParam = domParam.nextSiblingElement(domParam.tagName());
|
||||
|
||||
}
|
||||
ret.paramNames.reserve(paramHelper.size());
|
||||
ret.paramTypes.reserve(paramHelper.size());
|
||||
ret.type = funcType;
|
||||
QStringList signature;
|
||||
for (auto it = paramHelper.constBegin(); it != paramHelper.constEnd(); ++it)
|
||||
{
|
||||
ret.paramNames += it.value().first;
|
||||
ret.paramTypes += it.value().second;
|
||||
QString tmp = it.value().second;
|
||||
if (!it.value().second.endsWith(QLatin1Char('&')))
|
||||
tmp += QLatin1Char(' ');
|
||||
tmp += it.value().first;
|
||||
signature += tmp;
|
||||
}
|
||||
ret.signature += signature.join(QStringLiteral(", "));
|
||||
return ret;
|
||||
}
|
||||
|
||||
DbNotifcationInformation XmlReader::parseDbNotification(const QDomElement &customFunc) const
|
||||
{
|
||||
DbNotifcationInformation ret(parseCustomFunction(customFunc, CustomServiceFunctionInformation::Type::DbNotify));
|
||||
|
||||
const QString attribute(getAttribute(customFunc, QStringLiteral("notificationTypes")).toLower());
|
||||
const QStringList nfTypes = attribute.split(QLatin1Char(','));
|
||||
static const QMap<QString, DbNotifcationInformation::NotificationType> s_nfTypeMap =
|
||||
{
|
||||
{ QLatin1String("beforeinsert"), DbNotifcationInformation::NotificationType::BeforeInsert },
|
||||
{ QLatin1String("afterinsert"), DbNotifcationInformation::NotificationType::AfterInsert },
|
||||
{ QLatin1String("beforeupdate"), DbNotifcationInformation::NotificationType::BeforeUpdate },
|
||||
{ QLatin1String("afterupdate"), DbNotifcationInformation::NotificationType::AfterUpdate },
|
||||
{ QLatin1String("beforedelete"), DbNotifcationInformation::NotificationType::BeforeDelete },
|
||||
{ QLatin1String("afterdelete"), DbNotifcationInformation::NotificationType::AfterDelete }
|
||||
};
|
||||
for (const QString &nfType : nfTypes)
|
||||
{
|
||||
const auto it = s_nfTypeMap.find(nfType);
|
||||
if (it == s_nfTypeMap.end())
|
||||
throw XmlReaderException(QStringLiteral("Can not find notification type %2 in type map for function %1").arg(ret.methodName, nfType));
|
||||
ret.notificationType += it.value();
|
||||
}
|
||||
if (ret.notificationType.isEmpty())
|
||||
throw XmlReaderException(QStringLiteral("Notification function '%1' without a valid notification type").arg(ret.methodName));
|
||||
if (ret.paramTypes.size() != 1)
|
||||
throw XmlReaderException(QStringLiteral("Notification function '%1' must have exactly one parameter").arg(ret.methodName));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TopicTypeInformation XmlReader::loadExternalTopicType(const QString &externalServiceName, const QString &topicTypeName)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "externalServiceName: " << externalServiceName << ", topicTypeName: " << topicTypeName;
|
||||
|
||||
if (!loadExternalService(externalServiceName))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find service " << externalServiceName
|
||||
<< " referenced by external topic " << topicTypeName;
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
auto extXmlReader = m_externalXmlInformations.value(externalServiceName);
|
||||
if (!extXmlReader)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find service xml file for service '" << externalServiceName << "'";
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
|
||||
TopicTypeInformation tti = extXmlReader->getIdlStructInformation().value(topicTypeName);
|
||||
if (tti.isValid())
|
||||
{
|
||||
tti.name = externalServiceName + QLatin1String("::") + tti.name;
|
||||
m_externalTopicTypes += tti;
|
||||
m_usedServices[externalServiceName] = true;
|
||||
return tti;
|
||||
}
|
||||
WARNING_LOG(m_logger) << "Could not find topic " << topicTypeName
|
||||
<< " in external service definition for service "
|
||||
<< externalServiceName;
|
||||
return TopicTypeInformation();
|
||||
}
|
||||
|
||||
EnumInformation XmlReader::getExternalEnumeration(const QString &externalServiceName, const QString &enumName, bool verbose)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "externalServiceName: " << externalServiceName << ", topicTypeName: " << enumName;
|
||||
|
||||
if (!loadExternalService(externalServiceName))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find service '" << externalServiceName << "'"
|
||||
<< " referenced by external enumeration " << enumName;
|
||||
return EnumInformation();
|
||||
}
|
||||
auto extXmlReader = m_externalXmlInformations.value(externalServiceName);
|
||||
if (!extXmlReader)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not find service xml file for service '" << externalServiceName << "'";
|
||||
return EnumInformation();
|
||||
}
|
||||
|
||||
const QVector<EnumInformation> enums = extXmlReader->getEnumerations();
|
||||
for (const EnumInformation &ei : enums)
|
||||
{
|
||||
if (ei.enumName == enumName)
|
||||
{
|
||||
m_usedServices[externalServiceName] = true;
|
||||
return ei;
|
||||
}
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not find enumeration " << enumName
|
||||
<< " in external service definition for '"
|
||||
<< externalServiceName << "'";
|
||||
}
|
||||
return EnumInformation();
|
||||
}
|
||||
|
||||
|
||||
bool XmlReader::loadExternalService(const QString &serviceName)
|
||||
{
|
||||
if (serviceName == getServiceNamespace())
|
||||
return false;
|
||||
if (m_externalXmlInformations.contains(serviceName))
|
||||
return true;
|
||||
|
||||
QString fileName = xmlFileForService(serviceName);
|
||||
if (fileName.isEmpty())
|
||||
{
|
||||
const QVector<QString> dirs = NGL::directories(NGL::FileType::ConfigFile);
|
||||
for (const QString &dirname : dirs)
|
||||
{
|
||||
QDirIterator dirIt(dirname + QStringLiteral("/xml"), QDir::Files | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
while (dirIt.hasNext())
|
||||
{
|
||||
dirIt.next();
|
||||
if (!dirIt.fileName().endsWith(QLatin1String(".xml")))
|
||||
continue;
|
||||
|
||||
fileName = dirIt.filePath();
|
||||
const QString svcNamespace = serviceNamespaceFromFile(fileName);
|
||||
if (svcNamespace == serviceName)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(m_logger) << "xml file for " << serviceName << ": " << fileName;
|
||||
auto extXmlReader = QSharedPointer<XmlReader>(new XmlReader);
|
||||
if (!extXmlReader->readServiceFile(fileName, QString(), this))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Error reading service file " << fileName
|
||||
<< " for service " << serviceName;
|
||||
return false;
|
||||
}
|
||||
m_externalXmlInformations[serviceName] = extXmlReader;
|
||||
if (!m_usedServices.contains(serviceName))
|
||||
m_usedServices[serviceName] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void XmlReader::loadIdlInfofile(const QString &idlServiceInfoFile)
|
||||
{
|
||||
if (idlServiceInfoFile.isEmpty())
|
||||
return;
|
||||
QFile f(idlServiceInfoFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not read idl service info file " << idlServiceInfoFile;
|
||||
return;
|
||||
}
|
||||
const QList<QByteArray> files = f.readAll().split('\n');
|
||||
for (const QByteArray &filePath : files)
|
||||
{
|
||||
// comment
|
||||
if (filePath.startsWith("--") || filePath.trimmed().isEmpty())
|
||||
continue;
|
||||
const QString fileName = QString::fromLocal8Bit(filePath.trimmed());
|
||||
const QVector<QStringRef> parts = fileName.splitRef(QLatin1Char('/'));
|
||||
getServiceNameInfoFromFilePath(parts); // what/ever/ServiceFooBar/sfb_service.xml -> ServiceFooBar <-> sfb
|
||||
const auto fn = parts.last().trimmed();
|
||||
if (fn.endsWith(QLatin1String(".xml")))
|
||||
{
|
||||
const auto svcAbbreveation = fn.split(QLatin1Char('.')).at(0).split(QLatin1Char('_')).at(0);
|
||||
m_xmlFiles[svcAbbreveation.toString()] = fileName;
|
||||
DEBUG_LOG(m_logger) << "xml: " << svcAbbreveation.toString() << " = " << fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto svcAbbreveation = fn.split(QLatin1Char('.')).at(0).toString().toLower();
|
||||
if (svcAbbreveation.endsWith(QLatin1String("_enums")))
|
||||
continue;
|
||||
m_idlFiles[svcAbbreveation] = fileName;
|
||||
DEBUG_LOG(m_logger) << "idl: " << svcAbbreveation << " = " << fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString XmlReader::getIdlFileForService(const QMap<QString, QString> &data,
|
||||
const QString &serviceName) const
|
||||
{
|
||||
const QString serviceAbbr = serviceNameAbbreviation(serviceName);
|
||||
return data.value(serviceAbbr);
|
||||
}
|
||||
|
||||
|
||||
QString XmlReader::serviceNameAbbreviation(const QString &serviceName) const
|
||||
{
|
||||
return m_fullServiceName2Abbreviation.value(serviceName);
|
||||
}
|
||||
|
||||
void XmlReader::getServiceNameInfoFromFilePath(const QVector<QStringRef> &parts)
|
||||
{
|
||||
if (parts.size() < 2)
|
||||
return;
|
||||
|
||||
// foo_service.xml -> foo
|
||||
const QString abbreviation = parts.last().split(QLatin1Char('.')).first().split(QLatin1Char('_')).first().toString();
|
||||
const QString serviceName = parts.at(parts.size() - 2).toString();
|
||||
DEBUG_LOG(m_logger) << "serviceName: " << serviceName << " = " << abbreviation;
|
||||
m_fullServiceName2Abbreviation[serviceName] = abbreviation;
|
||||
}
|
||||
|
||||
ExerciseDependency XmlReader::string2ExerciseDependency(const QString &str)
|
||||
{
|
||||
if (str.isEmpty())
|
||||
return ExerciseDependency::Undefined;
|
||||
const QStringList sd = str.toLower().split(QLatin1Char(','));
|
||||
int ret = ExerciseDependency::Undefined;
|
||||
for (const QString &s : sd)
|
||||
{
|
||||
if (s == QLatin1String("global"))
|
||||
ret |= ExerciseDependency::Global;
|
||||
else if (s == QLatin1String("exercise"))
|
||||
ret |= ExerciseDependency::Exercise;
|
||||
else if (s == QLatin1String("globalandexercise"))
|
||||
ret |= ExerciseDependency::GlobalAndExercise;
|
||||
}
|
||||
return static_cast<ExerciseDependency>(ret);
|
||||
}
|
||||
|
||||
QString XmlReader::serviceNamespaceFromFile(const QString &fn)
|
||||
{
|
||||
QFile f(fn);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return QString();
|
||||
QXmlStreamReader sr(&f);
|
||||
while (!sr.atEnd())
|
||||
{
|
||||
sr.readNext();
|
||||
if (sr.isStartElement() && sr.name() == QLatin1String("service"))
|
||||
return (sr.attributes().value(QLatin1String("namespace"))).toString();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Read Xml service files
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include <dds/core/xtypes/EnumType.hpp>
|
||||
|
||||
#include "codegen_export.h"
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class INGLLogger;
|
||||
}
|
||||
class QDomElement;
|
||||
|
||||
namespace CodeGen
|
||||
{
|
||||
|
||||
enum ExerciseDependency // bitfield
|
||||
{
|
||||
Undefined = 0,
|
||||
Global = 0x1,
|
||||
Exercise = 0x2,
|
||||
GlobalAndExercise = 0x3
|
||||
};
|
||||
|
||||
struct EnumKeyValuePair
|
||||
{
|
||||
QString key;
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
struct EnumInformation
|
||||
{
|
||||
QString enumName;
|
||||
QString tableName;
|
||||
QString serviceName;
|
||||
QVector<EnumKeyValuePair> values;
|
||||
|
||||
bool isValid() const { return !enumName.isEmpty(); }
|
||||
};
|
||||
|
||||
struct ColumnInformation
|
||||
{
|
||||
QString columnName;
|
||||
QString datatype;
|
||||
QString comment;
|
||||
QString defaultValue;
|
||||
bool isPrimaryKey = false;
|
||||
bool isAssignmentForPrimaryTablePk = false;
|
||||
bool isForeignKey = false;
|
||||
bool generateSelectRemove = false; // generate db functions 'selectByFoo()' and 'removeByFoo()'
|
||||
bool canBeNull = true; // currently not passed through from EA / xml
|
||||
bool hasSequence = false;
|
||||
bool isOptional = false; // when optional, than the type is a QVariant (and QVariant::null is NULL)
|
||||
int sequenceStart = 0;
|
||||
int sequenceIncrement = 0;
|
||||
};
|
||||
|
||||
struct IdlColumnInformation
|
||||
{
|
||||
QString name;
|
||||
QString type; //!< the idl data type
|
||||
QString comment;
|
||||
bool isKey = false;
|
||||
bool isOptional = false;
|
||||
bool isTranslatable = false;
|
||||
};
|
||||
|
||||
|
||||
struct ForeignKeyInformation
|
||||
{
|
||||
struct Endpoint
|
||||
{
|
||||
QString service;
|
||||
QString serviceAbbr;
|
||||
QString schema;
|
||||
QString tableName;
|
||||
QString columnName;
|
||||
};
|
||||
|
||||
QString name;
|
||||
Endpoint source;
|
||||
Endpoint destination;
|
||||
enum class OnDeleteAction
|
||||
{
|
||||
NoAction,
|
||||
Cascade,
|
||||
Restrict,
|
||||
SetNull,
|
||||
SetDefault
|
||||
} deleteAction = OnDeleteAction::Cascade;
|
||||
};
|
||||
|
||||
struct CustomServiceFunctionInformation
|
||||
{
|
||||
QString methodName;
|
||||
QString returnValue;
|
||||
QString signature;
|
||||
bool isConst = false;
|
||||
QVector<QString> paramTypes;
|
||||
QVector<QString> paramNames;
|
||||
enum class Type
|
||||
{
|
||||
Db,
|
||||
DbNotify,
|
||||
Dtc
|
||||
} type = Type::Db;
|
||||
};
|
||||
|
||||
struct DbNotifcationInformation : public CustomServiceFunctionInformation
|
||||
{
|
||||
DbNotifcationInformation() = default;
|
||||
explicit DbNotifcationInformation(const CustomServiceFunctionInformation &d)
|
||||
: CustomServiceFunctionInformation(d)
|
||||
{}
|
||||
enum class NotificationType
|
||||
{
|
||||
BeforeInsert,
|
||||
AfterInsert,
|
||||
BeforeUpdate,
|
||||
AfterUpdate,
|
||||
BeforeDelete,
|
||||
AfterDelete
|
||||
};
|
||||
QVector<NotificationType> notificationType;
|
||||
};
|
||||
|
||||
struct ConstraintInformation
|
||||
{
|
||||
enum struct Type
|
||||
{
|
||||
unknown = 0x00,
|
||||
unique = 0x01,
|
||||
index = 0x02
|
||||
} type = Type::unknown;
|
||||
QString name;
|
||||
QStringList affectedColumns;
|
||||
};
|
||||
|
||||
struct TableInformation
|
||||
{
|
||||
QString name;
|
||||
QString structName;
|
||||
QString comment;
|
||||
QVector<ColumnInformation> plainColumns; // not yet processed - e.g. with datatype 'point_2d'
|
||||
QVector<QSharedPointer<ForeignKeyInformation> > foreignKeys;
|
||||
QVector<ConstraintInformation> constraints;
|
||||
ExerciseDependency exerciseDependency = ExerciseDependency::Undefined;
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> fkInformationForColumn(const QString &tableName,
|
||||
const QString &columnName) const
|
||||
{
|
||||
for (const QSharedPointer<ForeignKeyInformation> &fki : foreignKeys)
|
||||
{
|
||||
if (fki->source.columnName == columnName &&
|
||||
fki->source.tableName == tableName)
|
||||
return fki;
|
||||
}
|
||||
return QSharedPointer<ForeignKeyInformation>();
|
||||
}
|
||||
};
|
||||
|
||||
struct ViewInformation
|
||||
{
|
||||
QString name;
|
||||
QString comment;
|
||||
QString structName;
|
||||
QString baseTable;
|
||||
QString baseSchema;
|
||||
QString filter;
|
||||
ExerciseDependency exerciseDependency = ExerciseDependency::Undefined;
|
||||
};
|
||||
|
||||
struct ServiceStructInformation
|
||||
{
|
||||
QString name;
|
||||
QString primaryTable;
|
||||
bool hasStaticContent = false;
|
||||
|
||||
bool operator<(const ServiceStructInformation &o) const
|
||||
{
|
||||
if (hasStaticContent != o.hasStaticContent)
|
||||
return hasStaticContent < o.hasStaticContent;
|
||||
if (name != o.name)
|
||||
return name < o.name;
|
||||
return primaryTable < o.primaryTable;
|
||||
}
|
||||
QVector<DbNotifcationInformation> dbNotifications;
|
||||
};
|
||||
|
||||
struct TopicTypeInformationBase
|
||||
{
|
||||
TopicTypeInformationBase() = default;
|
||||
virtual ~TopicTypeInformationBase() = default;
|
||||
|
||||
QString name;
|
||||
QString baseValueType; // parent class
|
||||
QString comment;
|
||||
bool isDataObject = false; // can be used as DWO/DRO
|
||||
bool dtsAutogen = true; // automatically generate DTS Impl
|
||||
bool dtcAutogen = true; // automatically generate DTC Impl
|
||||
bool recordTopic = false; // record topic for replay?
|
||||
bool routeToClient = true; // route Topic from server to client?
|
||||
bool routeToServer = false; // route Topic from client to server?
|
||||
bool routeInReplay = true; // route Topic in replay from exercise to replay (or vice-versa)?
|
||||
bool autosubscribe = true; // automatically call enableFoo() in DTC::enableAll()
|
||||
|
||||
dds::core::xtypes::ExtensibilityKind extensibility = dds::core::xtypes::ExtensibilityKind::EXTENSIBLE;
|
||||
|
||||
virtual bool isValid() const { return !name.isEmpty(); }
|
||||
|
||||
bool operator<(const TopicTypeInformationBase &o) const
|
||||
{
|
||||
if (name != o.name)
|
||||
return name < o.name;
|
||||
return baseValueType < o.baseValueType;
|
||||
}
|
||||
};
|
||||
|
||||
struct TopicTypeInformation : public TopicTypeInformationBase
|
||||
{
|
||||
QVector<IdlColumnInformation> columns;
|
||||
};
|
||||
|
||||
struct FunctionTopic
|
||||
{
|
||||
QString name;
|
||||
QString requestTopicType;
|
||||
QString replyTopicType;
|
||||
QString requestTopicName;
|
||||
QString replyTopicName;
|
||||
bool routeInReplay = false;
|
||||
};
|
||||
|
||||
|
||||
class CODEGEN_BASE_EXPORT XmlReader final
|
||||
{
|
||||
public:
|
||||
XmlReader();
|
||||
|
||||
bool readServiceFile(const QString &svcFile,
|
||||
const QString &idlServiceInfoFile = QString(),
|
||||
const XmlReader *parent = nullptr);
|
||||
QString errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
QString getServiceNamespace() const { return m_svcNamespace; }
|
||||
QString getServiceAbbr() const { return m_svcAbbr; }
|
||||
QStringList getGroupNames() const { return m_groupNames; }
|
||||
int getPrio() const { return m_prio;}
|
||||
QStringList getProcNames() const { return m_svcProcNames; }
|
||||
bool hasCustomRecordReplayPlugin() const { return m_customRecordReplay; }
|
||||
bool getDevMode() const { return m_svcDevMode; }
|
||||
|
||||
bool isServiceExerciseIndependent() const { return m_exerciseDependency == ExerciseDependency::Global; }
|
||||
ExerciseDependency defaultExerciseDependency() const { return m_exerciseDependency; }
|
||||
|
||||
QMap<QString, QVector<QString> > getDbClass2TableMapping() const { return m_dbClassTables; }
|
||||
|
||||
// service structs
|
||||
QMap<QString, QString> getStruct2BaseClassRelations() const { return m_struct2BaseClass; }
|
||||
QVector<ServiceStructInformation> getStructToGenerate() const { return m_structsToGenerate; }
|
||||
|
||||
// idl structs
|
||||
QMap<QString, TopicTypeInformation > getIdlStructInformation() const { return m_idlStructsToGenerate; }
|
||||
QVector<TopicTypeInformation> getIdlStructToGenerate() const
|
||||
{
|
||||
QVector<TopicTypeInformation> res;
|
||||
res.reserve(m_idlStructsToGenerate.size());
|
||||
auto it = m_idlStructsToGenerate.constBegin();
|
||||
while (it != m_idlStructsToGenerate.constEnd())
|
||||
{
|
||||
res.append(it.value());
|
||||
++it;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// tables
|
||||
QMap<QString, QSharedPointer<TableInformation> > getTables() const
|
||||
{
|
||||
return m_tables;
|
||||
}
|
||||
QMap<QString, QSharedPointer<ViewInformation> > getViews() const
|
||||
{
|
||||
return m_views;
|
||||
}
|
||||
QSharedPointer<TableInformation> getTable(const QString &table) const
|
||||
{
|
||||
return m_tables.value(table);
|
||||
}
|
||||
QVector<EnumInformation> getEnumerations() const
|
||||
{
|
||||
return m_enumerations;
|
||||
}
|
||||
QVector<IdlColumnInformation> getIdlColumns(const QString &structName) const
|
||||
{
|
||||
return m_idlStructsToGenerate.value(structName).columns;
|
||||
}
|
||||
|
||||
QVector<FunctionTopic> getFunctionTopics() const
|
||||
{
|
||||
return m_functionTopics;
|
||||
}
|
||||
QVector<TopicTypeInformation> getExternalTopicTypes() const
|
||||
{
|
||||
return m_externalTopicTypes;
|
||||
}
|
||||
|
||||
QString idlFileForService(const QString &serviceName) const
|
||||
{
|
||||
return getIdlFileForService(m_idlFiles, serviceName);
|
||||
}
|
||||
|
||||
QString xmlFileForService(const QString &serviceName) const
|
||||
{
|
||||
return getIdlFileForService(m_xmlFiles, serviceName);
|
||||
}
|
||||
|
||||
QMap<QString, bool> usedServices() const
|
||||
{
|
||||
return m_usedServices;
|
||||
}
|
||||
|
||||
QVector<CustomServiceFunctionInformation> getCustomFunctions() const
|
||||
{
|
||||
return m_customFunctions;
|
||||
}
|
||||
|
||||
|
||||
TopicTypeInformation loadExternalTopicType(const QString &externalServiceName, const QString &topicTypeName);
|
||||
EnumInformation getExternalEnumeration(const QString &externalServiceName, const QString &enumName, bool verbose);
|
||||
|
||||
static ExerciseDependency string2ExerciseDependency(const QString &str);
|
||||
|
||||
XmlReader(const XmlReader &) = delete;
|
||||
XmlReader &operator=(const XmlReader &) = delete;
|
||||
|
||||
private:
|
||||
void parseDBSserviceStructs(const QDomElement &rootElement);
|
||||
void parseDBTables(const QDomElement &rootElement);
|
||||
void parseDBViews(const QDomElement &rootElement);
|
||||
void parseEnumerations(const QDomElement &rootElement);
|
||||
void parseTopicTypes(const QDomElement &rootElement);
|
||||
void parseFunctionTopics(const QDomElement &rootElement);
|
||||
void parseCustomDtcFunctions(const QDomElement &rootElement);
|
||||
|
||||
static QString getAttribute(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional = false);
|
||||
static bool getAttributeBool(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional, bool defaultValue);
|
||||
static int getAttributeInt(const QDomElement &element,
|
||||
const QString &attributeName,
|
||||
bool bOptional = false, int defaultValue = 0);
|
||||
|
||||
ColumnInformation parseTableColumn(const QDomElement &column, const QString &tableName) const;
|
||||
IdlColumnInformation parseIdlStructColumn(const QDomElement &column) const;
|
||||
|
||||
QSharedPointer<ForeignKeyInformation> parseForeignKey(const QDomElement &foreignKey) const;
|
||||
ForeignKeyInformation::Endpoint parseForeignKeyEndpoint(const QString &foreignKeyName,
|
||||
const QDomElement &endpoint) const;
|
||||
ConstraintInformation parseConstraint(const QDomElement &constraint) const;
|
||||
CustomServiceFunctionInformation parseCustomFunction(const QDomElement &customFunc, CustomServiceFunctionInformation::Type funcType) const;
|
||||
DbNotifcationInformation parseDbNotification(const QDomElement &customFunc) const;
|
||||
bool loadExternalService(const QString &serviceName);
|
||||
void loadIdlInfofile(const QString &idlServiceInfoFile);
|
||||
QString getIdlFileForService(const QMap<QString, QString> &data, const QString &serviceName) const;
|
||||
QString serviceNameAbbreviation(const QString &serviceName) const;
|
||||
void getServiceNameInfoFromFilePath(const QVector<QStringRef> &parts);
|
||||
static QString serviceNamespaceFromFile(const QString &fn);
|
||||
|
||||
// The service name from the parsed xml file;
|
||||
QString m_svcNamespace;
|
||||
// Abbreviation of service name (inside xml file)
|
||||
QString m_svcAbbr;
|
||||
// Names for associated processes with this service (a single name in most cases)
|
||||
QStringList m_svcProcNames;
|
||||
// Extent the default Record/Replay plugin with own functions
|
||||
bool m_customRecordReplay;
|
||||
|
||||
// depends this service on an exercise or is it a global on (or both)
|
||||
ExerciseDependency m_exerciseDependency{ExerciseDependency::Exercise};
|
||||
|
||||
// Mapping DBClass -> used tables
|
||||
QMap<QString, QVector<QString> > m_dbClassTables;
|
||||
|
||||
// structs to generate struct -> base class relation
|
||||
QMap<QString, QString> m_struct2BaseClass;
|
||||
QVector<ServiceStructInformation> m_structsToGenerate;
|
||||
|
||||
QMap<QString, TopicTypeInformation> m_idlStructsToGenerate;
|
||||
|
||||
QVector<FunctionTopic> m_functionTopics;
|
||||
QVector<TopicTypeInformation> m_externalTopicTypes;
|
||||
QVector<CustomServiceFunctionInformation> m_customFunctions;
|
||||
|
||||
|
||||
QMap<QString, QSharedPointer<TableInformation> > m_tables;
|
||||
QMap<QString, QSharedPointer<ViewInformation> > m_views;
|
||||
QVector<EnumInformation> m_enumerations;
|
||||
QString m_errorString;
|
||||
|
||||
|
||||
QMap<QString, QSharedPointer<XmlReader> > m_externalXmlInformations;
|
||||
QMap<QString, QString> m_idlFiles; // svcShortName, filename
|
||||
QMap<QString, QString> m_xmlFiles; // svcShortName, filename
|
||||
QMap<QString, bool> m_usedServices;
|
||||
QMap<QString, QString> m_fullServiceName2Abbreviation;
|
||||
|
||||
QStringList m_groupNames;
|
||||
int m_prio;
|
||||
bool m_svcDevMode{false};
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
} // namespace CodeGen
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef CODEGEN_BASE_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define CODEGEN_BASE_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_CODEGEN_BASE_LIB)
|
||||
# define CODEGEN_BASE_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define CODEGEN_BASE_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, stdout
|
||||
|
||||
# CodeGeneration Tool
|
||||
###########################################################
|
||||
|
||||
log4j.logger.CodeGen.main=WARN
|
||||
log4j.logger.CodeGen=INFO
|
||||
log4j.logger.CodeGen.Settings=INFO
|
||||
log4j.logger.CodeGen.FtsImpl=INFO
|
||||
log4j.logger.CodeGen.FtcImpl=INFO
|
||||
|
||||
# DTS/DTC, FTS/FTC
|
||||
log4j.logger.Generic.DTS=INFO
|
||||
log4j.logger.Generic.DTC=INFO
|
||||
log4j.logger.Generic.FTS.Function=INFO
|
||||
log4j.logger.Generic.FTC=INFO
|
||||
log4j.logger.DTC.Subscriber=INFO
|
||||
log4j.logger.DTC.SubscriberListener=INFO
|
||||
log4j.logger.FTS=INFO
|
||||
log4j.logger.FTC=WARN
|
||||
|
||||
# connext (request/reply feature)
|
||||
log4j.logger.connext.requester=WARN
|
||||
log4j.logger.connext.replier=WARN
|
||||
|
||||
# CodeGen
|
||||
log4j.logger.CodeGen.XmlReader=WARN
|
||||
|
||||
# SqlGenerator
|
||||
log4j.logger.CodeGen.SqlGenerator=WARN
|
||||
log4j.logger.CodeGen.StructBuilder=INFO
|
||||
|
||||
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_codeGen.log
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
+477
@@ -0,0 +1,477 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
|
||||
class FtData(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.namespace = ''
|
||||
self.requestTopicType = ''
|
||||
self.requestTopicName = ''
|
||||
self.replyTopicType = ''
|
||||
self.replyTopicName = ''
|
||||
|
||||
def fqnVar( self, name ):
|
||||
if name.find('::') < 0:
|
||||
name = self.namespace + '::' + name
|
||||
return name
|
||||
def stripNamespace( self, str ):
|
||||
return str.split('::')[-1]
|
||||
|
||||
def getReplyTopicName( self ):
|
||||
return 'LTS_' + self.stripNamespace( self.replyTopicName ).replace( '::', '_' )
|
||||
|
||||
def getReplyTopicNameType( self, withNamespace = True ):
|
||||
var = self.replyTopicName
|
||||
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
|
||||
|
||||
def getRequestTopicName( self ):
|
||||
return 'LTS_' + self.stripNamespace( self.requestTopicName ).replace( '::', '_' )
|
||||
|
||||
def getRequestTopicNameType( self, withNamespace = True ):
|
||||
var = self.requestTopicName
|
||||
return self.fqnVar( var ) if withNamespace else self.stripNamespace( var )
|
||||
|
||||
def getReplyTopicType( self ):
|
||||
return self.fqnVar( self.replyTopicType )
|
||||
def getRequestTopicType( self ):
|
||||
return self.fqnVar( self.requestTopicType )
|
||||
|
||||
def needReplyTopicTypedef( self ):
|
||||
return self.getReplyTopicNameType() != self.getReplyTopicType()
|
||||
def needRequestTopicTypedef( self ):
|
||||
return self.getRequestTopicNameType() != self.getRequestTopicType()
|
||||
|
||||
class GuiPluginRights(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.offset = 0
|
||||
self.groups = []
|
||||
class GuiPluginRightsGroup(object):
|
||||
def __init__( self ):
|
||||
self.name = ''
|
||||
self.desc = ''
|
||||
self.values = []
|
||||
|
||||
class FileParser(object):
|
||||
def __init__( self ):
|
||||
self.filename = ''
|
||||
self.service_abbr = ''
|
||||
self.module_name = ''
|
||||
self.struct_names = []
|
||||
self.ft_enums = []
|
||||
self.ft_replies = []
|
||||
self.ft_data = dict()
|
||||
self.op_right_offset = 0
|
||||
self.op_rights = []
|
||||
|
||||
def build(self, path):
|
||||
""" Parse the whole stuff ... """
|
||||
self.filename = path
|
||||
self.read_file_xml(self.filename)
|
||||
|
||||
def read_file_xml(self, filename):
|
||||
""" Read the given xml service file"""
|
||||
|
||||
"""print >> sys.stdout, 'Reading xml file %s' % filename"""
|
||||
xmlTree = ET.parse(filename)
|
||||
root = xmlTree.getroot()
|
||||
self.module_name = root.attrib['namespace']
|
||||
self.service_abbr = root.attrib['abbreviation'].lower()
|
||||
|
||||
for child in root.iter('topicType'):
|
||||
struct_name = child.attrib['name']
|
||||
if 'isDataObject' in child.attrib and int(child.attrib['isDataObject']) != 0:
|
||||
self.struct_names.append(struct_name)
|
||||
for child in root.iter('functionTopic'):
|
||||
ft_name = child.attrib['name']
|
||||
self.ft_enums.append(ft_name) # solange es noch entityModel.idl gibt ...
|
||||
|
||||
ft_data = FtData()
|
||||
ft_data.name = ft_name
|
||||
ft_data.namespace = self.module_name
|
||||
ft_data.requestTopicType = child.attrib['requestTopicType']
|
||||
ft_data.requestTopicName = child.attrib['requestTopicName']
|
||||
ft_data.replyTopicType = child.attrib['replyTopicType']
|
||||
ft_data.replyTopicName = child.attrib['replyTopicName']
|
||||
self.ft_data[ft_name] = ft_data
|
||||
|
||||
for child in root.iter('operatorRights'):
|
||||
self.op_right_offset = int(child.attrib['offset'])
|
||||
for pluginChild in child.iter('guiPlugin'):
|
||||
r = GuiPluginRights()
|
||||
r.name = pluginChild.attrib['name']
|
||||
r.offset = int(pluginChild.attrib['offset'])
|
||||
r.groups = [];
|
||||
for groups in pluginChild.iter('operatorRightGroup'):
|
||||
g = GuiPluginRightsGroup();
|
||||
g.name = groups.attrib['name']
|
||||
g.desc = groups.attrib['description'] if 'description' in groups.attrib else ''
|
||||
|
||||
for right in groups.iter('operatorRight'):
|
||||
desc = right.attrib['description'] if 'description' in right.attrib else ''
|
||||
g.values.append((right.attrib['right'], int(right.attrib['value']), desc))
|
||||
r.groups.append(g)
|
||||
self.op_rights.append(r)
|
||||
|
||||
|
||||
def outputHeader( outfile, parser, description, with_dds_include = True, with_pragma = True ):
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write('* %s definitions\n' % description)
|
||||
outfile.write('*/\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('// warning: this file is generated with command\n')
|
||||
outfile.write('// %s\n' % ( " ".join(sys.argv) ))
|
||||
outfile.write('// at %s\n' % time.strftime( '%c' ))
|
||||
outfile.write('// it will be overwritten by next run - do not modify!\n')
|
||||
outfile.write('\n')
|
||||
if with_pragma:
|
||||
outfile.write('#pragma once\n')
|
||||
outfile.write('\n')
|
||||
if with_dds_include:
|
||||
outfile.write('#include "%s.hpp"\n' % ( parser.service_abbr ))
|
||||
|
||||
class DtsGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'DTS' )
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write(' * Type definitions \n')
|
||||
outfile.write(' * => DataWriterObjects (DWOs)\n')
|
||||
outfile.write(' * => DataTopicServers (DTSs)\n')
|
||||
outfile.write(' */\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DDSGeneric\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataWriter;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' template<typename T> class GenericDts;\n')
|
||||
outfile.write(' template<typename T> class GenericDtsImpl;\n')
|
||||
outfile.write('\n')
|
||||
|
||||
for struct_name in sorted(parser.struct_names):
|
||||
# Add ProjectName (from idl file)
|
||||
topic_name = "%s::%s" % ( parser.module_name, struct_name )
|
||||
dwo_name = "Dwo%s" % ( struct_name )
|
||||
outfile.write(' // Topic %s\n' % ( topic_name ))
|
||||
outfile.write(' // Interface\n')
|
||||
outfile.write(' using %s = GenericDts<%s>;\n' % ( struct_name, topic_name ))
|
||||
outfile.write(' // Interface impl\n')
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataWriter<%s>;\n' % ( dwo_name, topic_name ))
|
||||
outfile.write(' using %sImpl = GenericDtsImpl<%s>;\n' % ( struct_name, dwo_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace DTS\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class DtcGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'DTC' )
|
||||
outfile.write('\n')
|
||||
outfile.write('/**\n')
|
||||
outfile.write(' * Type definitions \n')
|
||||
outfile.write(' * => DataTopicClients (DTCs)\n')
|
||||
outfile.write(' */\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DDSGeneric\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataReader;\n')
|
||||
outfile.write('template <typename T>\n')
|
||||
outfile.write('class GenericDataReaderContentFilter;\n')
|
||||
outfile.write('class DynamicDataReader;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace DTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' template<typename T> class GenericDtc;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcImpl;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcSampleInfo;\n')
|
||||
outfile.write(' template<typename T> class GenericDtcImplSampleInfo;\n')
|
||||
outfile.write('\n')
|
||||
|
||||
for struct_name in sorted(parser.struct_names):
|
||||
# Add ProjectName (from idl file)
|
||||
topic_name = "%s::%s" % ( parser.module_name, struct_name )
|
||||
dro_name = "Dro%s" % ( struct_name )
|
||||
dro_name_cf = "Dro%sCF" % ( struct_name )
|
||||
|
||||
outfile.write(' // Topic %s\n' % ( topic_name ))
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataReader<%s>;\n' % ( dro_name, topic_name ))
|
||||
outfile.write(' using %s = GenericDtc<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' using %sImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name ))
|
||||
|
||||
outfile.write(' using %s = DDSGeneric::GenericDataReaderContentFilter<%s>;\n' % ( dro_name_cf, topic_name ))
|
||||
outfile.write(' using %sCF = GenericDtc<%s>;\n' % ( struct_name, dro_name_cf ))
|
||||
outfile.write(' using %sCFImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name_cf ))
|
||||
|
||||
outfile.write(' namespace SampleInfo {\n')
|
||||
outfile.write(' using %s = GenericDtcSampleInfo<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' using %sImpl = GenericDtcImplSampleInfo<%s>;\n' % ( struct_name, dro_name ))
|
||||
outfile.write(' }\n')
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace DTC\n')
|
||||
outfile.write('\n')
|
||||
|
||||
def printFtTopicTypeNames( outfile, ft_data ):
|
||||
outfile.write(' template<> struct TopicNames<%s>' % ft_data.name)
|
||||
outfile.write(' {\n')
|
||||
outfile.write(' static constexpr const char *functionTopicName() { return "%s"; }\n' % ft_data.name)
|
||||
outfile.write(' static constexpr const char *replyTopicName() { return "%s"; }\n' % ft_data.getReplyTopicName())
|
||||
outfile.write(' static constexpr const char *replyTopicTypeName() { return "%s"; }\n' % ft_data.getReplyTopicNameType( True ))
|
||||
outfile.write(' static constexpr const char *requestTopicName() { return "%s"; }\n' % ft_data.getRequestTopicName())
|
||||
outfile.write(' static constexpr const char *requestTopicTypeName() { return "%s"; }\n' % ft_data.getRequestTopicNameType( True ))
|
||||
outfile.write(' };\n')
|
||||
|
||||
def printFtTypedefs( outfile, ft_data ):
|
||||
if ft_data.needRequestTopicTypedef():
|
||||
outfile.write(' using %s = %s;\n' % ( ft_data.getRequestTopicNameType( False ), ft_data.getRequestTopicType() ))
|
||||
if ft_data.needReplyTopicTypedef():
|
||||
outfile.write(' using %s = %s;\n' % ( ft_data.getReplyTopicNameType( False ), ft_data.getReplyTopicType() ))
|
||||
|
||||
class FtsGenerator(object):
|
||||
def generate( self, outfile, parser):
|
||||
outputHeader( outfile, parser, 'FTS' )
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtsImpl;\n')
|
||||
outfile.write('template<typename GENERIC_FTS> struct TopicNames;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
printFtTypedefs( outfile, parser.ft_data[ft_name] )
|
||||
|
||||
outfile.write('} // namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTS\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for GenericFtsImpl\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
ft_data = parser.ft_data[ft_name]
|
||||
|
||||
dummy = '%sTemplateHelperDummy' % ft_data.name;
|
||||
outfile.write(' class %s;\n' % dummy)
|
||||
outfile.write(' using %s = GenericFtsImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
|
||||
printFtTopicTypeNames( outfile, ft_data )
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace FTS\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class FtcGenerator(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'FTC' )
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write('template <typename REQ, typename REP, typename DUMMY> class GenericFtcImpl;\n')
|
||||
outfile.write('template<typename GENERIC_FTC> struct TopicNames;\n')
|
||||
outfile.write('}\n')
|
||||
outfile.write('namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
printFtTypedefs( outfile, parser.ft_data[ft_name] )
|
||||
|
||||
outfile.write('} // namespace %s\n' % ( parser.module_name ))
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('namespace FTC\n')
|
||||
outfile.write('{\n')
|
||||
outfile.write(' // TypeDefinitions for GenericFtcImpl\n')
|
||||
for ft_name in sorted(parser.ft_enums):
|
||||
ft_data = parser.ft_data[ft_name]
|
||||
|
||||
dummy = '%sTemplateHelperDummy' % ft_data.name;
|
||||
outfile.write(' class %s;\n' % dummy)
|
||||
outfile.write(' using %s = GenericFtcImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy))
|
||||
printFtTopicTypeNames( outfile, ft_data )
|
||||
outfile.write('\n')
|
||||
|
||||
outfile.write('} // namespace FTC\n')
|
||||
outfile.write('\n')
|
||||
|
||||
class OperatorRights(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'Operator Rights', False )
|
||||
outfile.write('namespace %s \n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
outfile.write(' static const int Offset = %s; \n' % parser.op_right_offset)
|
||||
outfile.write('}\n\n')
|
||||
|
||||
outfile.write('namespace OperatorRights\n')
|
||||
outfile.write('{\n')
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
for r in parser.op_rights:
|
||||
outfile.write('enum %s\n' % r.name)
|
||||
outfile.write('{\n')
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
for k,v,d in group.values:
|
||||
v += groupOffset
|
||||
outfile.write(' %s = %s,\n' % (k, hex(v)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('enum Groups_%s\n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
pattern = re.compile('[\W]+')
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
for group in r.groups:
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
name = pattern.sub('', group.name)
|
||||
outfile.write(' Group%s = %s,\n' % (name, hex(groupOffset)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('enum Plugins_%s\n' % parser.module_name)
|
||||
outfile.write('{\n')
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
name = pattern.sub('', r.name)
|
||||
outfile.write(' Plugin%s = %s,\n' % (name, hex(offsetPlugin)))
|
||||
outfile.write('};\n')
|
||||
|
||||
outfile.write('} // namespace OperatorRights\n')
|
||||
|
||||
class OperatorRightsCpp(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outputHeader( outfile, parser, 'Operator Rights (source)', False, False )
|
||||
outfile.write('#include "%s_operator_rights.h"\n' % parser.service_abbr)
|
||||
outfile.write('#include <QCoreApplication>\n\n\n')
|
||||
if len(parser.op_rights) == 0:
|
||||
return
|
||||
outfile.write('\nvoid doNothing()\n{\n const char * txt[] {\n')
|
||||
|
||||
disamb = 'OperatorRights'
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
if group.name != '':
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.name))
|
||||
if group.desc != '':
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.desc))
|
||||
for aclName, aclId, aclDescr in group.values:
|
||||
outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, aclDescr))
|
||||
outfile.write(' };\n Q_UNUSED(txt);\n}\n')
|
||||
|
||||
class OperatorRightsSql(object):
|
||||
def generate( self, outfile, parser ):
|
||||
outfile.write('BEGIN;\n')
|
||||
globalOffset = parser.op_right_offset << 24
|
||||
if globalOffset > 0:
|
||||
outfile.write('--- Offset: %s = %s\n' % (globalOffset, hex(globalOffset)))
|
||||
|
||||
groupId = globalOffset;
|
||||
|
||||
for r in parser.op_rights:
|
||||
offsetPlugin = globalOffset + (r.offset << 16)
|
||||
groupCount = -1
|
||||
for group in r.groups:
|
||||
groupCount = groupCount + 1
|
||||
groupOffset = offsetPlugin + (groupCount << 8)
|
||||
|
||||
outfile.write('\n--- %s - %s = %s\n' % (group.name, hex(groupOffset), groupOffset))
|
||||
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 4, false);\n"
|
||||
outfile.write(str % (groupOffset, group.name, group.desc))
|
||||
for aclName, aclId, aclDescr in group.values:
|
||||
aclId += groupOffset
|
||||
outfile.write('--- Base: %s, %s - %s = %s\n' % (groupOffset, aclName, aclId, hex(aclId)))
|
||||
str = "INSERT INTO opm.opm_access_control_level (id, name, description) VALUES (%s, '%s', '%s');\n";
|
||||
outfile.write(str % (aclId, aclName, aclDescr));
|
||||
str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 1, true);\n";
|
||||
outfile.write(str % (groupId, aclName, aclDescr));
|
||||
str = "INSERT INTO opm.opm_acl_allow (group_id, acl_id) VALUES (%s, %s); -- group_id is: %s = %s\n";
|
||||
outfile.write(str % (groupId, aclId, groupId, hex(groupId)));
|
||||
str = "INSERT INTO opm.opm_group_group (group_id, is_member_of_group_id) VALUES (%s, %s); -- %s\n"
|
||||
outfile.write(str % (groupOffset, groupId, group.name))
|
||||
groupId = groupId + 1
|
||||
outfile.write('\n')
|
||||
outfile.write('END;\n')
|
||||
|
||||
def generate( parser, generator, out_filename ):
|
||||
try:
|
||||
outfile = open(out_filename, 'w')
|
||||
except:
|
||||
print("Could not open %s for writing" % out_filename, file=sys.stderr)
|
||||
sys.exit(4)
|
||||
generator.generate(outfile, parser)
|
||||
outfile.close()
|
||||
|
||||
def usage( error ):
|
||||
print(error, file=sys.stderr)
|
||||
print("Usage: %s DTS|DTC|FTS|FTC|SQL <service_file.xml> <outfile> " % sys.argv[0], file=sys.stderr)
|
||||
print(" %s ALL <service_file.xml> <outdir> " % sys.argv[0], file=sys.stderr)
|
||||
print("i.e.: %s DTS exm_service.xml DtsTypeDefinitions.h" % sys.argv[0], file=sys.stderr)
|
||||
print("call: '%s'" % " ".join(sys.argv), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
usage("Invalid argument count")
|
||||
|
||||
option_str = sys.argv[1]
|
||||
xml_filename = sys.argv[2]
|
||||
|
||||
parser = FileParser()
|
||||
parser.build(xml_filename)
|
||||
|
||||
if option_str == "DTS":
|
||||
generate(parser, DtsGenerator(), sys.argv[3])
|
||||
elif option_str == "DTC":
|
||||
generate(parser, DtcGenerator(), sys.argv[3])
|
||||
elif option_str == "FTS":
|
||||
generate(parser, FtsGenerator(), sys.argv[3])
|
||||
elif option_str == "FTC":
|
||||
generate(parser, FtcGenerator(), sys.argv[3])
|
||||
elif option_str == "SQL":
|
||||
out_dir = sys.argv[3]
|
||||
generate(parser, OperatorRightsSql(), os.path.join(out_dir, parser.service_abbr + '_operator_rights.sql'))
|
||||
elif option_str == "ALL":
|
||||
out_dir = sys.argv[3]
|
||||
fn = parser.service_abbr + '_%s_types.h'
|
||||
generate(parser, DtsGenerator(), fn % 'dts')
|
||||
generate(parser, DtcGenerator(), fn % 'dtc')
|
||||
generate(parser, FtsGenerator(), fn % 'fts')
|
||||
generate(parser, FtcGenerator(), fn % 'ftc')
|
||||
generate(parser, OperatorRights(), parser.service_abbr + '_operator_rights.h')
|
||||
generate(parser, OperatorRightsCpp(), parser.service_abbr + '_operator_rights.cpp')
|
||||
else:
|
||||
usage("invalid option '%s'" % option_str)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* main for ExerciseManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
#include "DaoGeneratorGrantlee.h"
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
#include "SqlGenerator.h"
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <QDir>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(LtsCommandLineParser::LtsCommandLineParser::None)
|
||||
{
|
||||
addOption({ QStringList() << QStringLiteral("s") << QStringLiteral("servicefile"),
|
||||
QStringLiteral("full path to the service xml-file"),
|
||||
QStringLiteral("service xml-file"),
|
||||
QStringLiteral("/home")
|
||||
});
|
||||
|
||||
addOption({ QStringList() << QStringLiteral("a") << QStringLiteral("action"),
|
||||
QStringLiteral("the action to execute"),
|
||||
QStringLiteral("DATABASE|DATABASE_SERVER|IDL|DDS_TOPICS"),
|
||||
QStringLiteral("/0")
|
||||
});
|
||||
|
||||
addOption({ QStringList() << QStringLiteral("o") << QStringLiteral("outdir"),
|
||||
QStringLiteral("the output directory where to put the generated files"),
|
||||
QStringLiteral("output directory"),
|
||||
QStringLiteral("/home")
|
||||
});
|
||||
|
||||
addOption({ QStringList() << QStringLiteral("i") << QStringLiteral("idlinfo"),
|
||||
QStringLiteral("the info file with all available idl service files"),
|
||||
QStringLiteral("info file for idl"),
|
||||
QStringLiteral("/0")
|
||||
});
|
||||
}
|
||||
|
||||
bool init()
|
||||
{
|
||||
if (!LtsCommandLineParser::init())
|
||||
return false;
|
||||
|
||||
if (serviceFile().isEmpty() || action().isEmpty() || outDir().isEmpty())
|
||||
{
|
||||
showHelp();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString serviceFile() const { return value(QStringLiteral("s")); }
|
||||
QString action() const { return value(QStringLiteral("a")); }
|
||||
QString outDir() const { return value(QStringLiteral("o")); }
|
||||
QString idlInfoFile() const { return value(QStringLiteral("i")); }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("CodeGen", "codegen_log4cxx.props", true /* don't spam while compilation of the project */);
|
||||
|
||||
NGL::INGLLogger &m_logger = app.baseLogger();
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
QScopedPointer<CodeGen::XmlReader> reader(new CodeGen::XmlReader);
|
||||
|
||||
DEBUG_LOG(m_logger) << "ServiceFile: " << options.serviceFile();
|
||||
DEBUG_LOG(m_logger) << "IdlInfoFile: " << options.idlInfoFile();
|
||||
if (!reader->readServiceFile(options.serviceFile(), options.idlInfoFile()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error parsing service file '" << options.serviceFile()
|
||||
<< ": " << reader->errorString();
|
||||
return 2;
|
||||
}
|
||||
|
||||
QDir dir(options.outDir());
|
||||
DEBUG_LOG(m_logger) << "Directory: " << options.outDir();
|
||||
if (!dir.exists() && !dir.mkpath(options.outDir()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Directory '" << options.outDir()
|
||||
<< "' does not exist and can not be created!";
|
||||
return 3;
|
||||
}
|
||||
|
||||
QScopedPointer<CodeGen::StructBuilder> structBuilder(new CodeGen::StructBuilder(reader.data()));
|
||||
if (!structBuilder->buildStructures())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error building up structures";
|
||||
return 4;
|
||||
}
|
||||
|
||||
const QString action = options.action().toLower();
|
||||
//INFO_LOG(m_logger) << "action = " << action;
|
||||
|
||||
QScopedPointer<CodeGen::GeneratorGrantleeBase> generator;
|
||||
if (action == QStringLiteral("dao"))
|
||||
generator.reset(new CodeGen::DaoGeneratorGrantlee);
|
||||
else if (action == QStringLiteral("database"))
|
||||
generator.reset(new CodeGen::DatabaseGeneratorGrantlee(false));
|
||||
else if (action == QStringLiteral("database_server"))
|
||||
generator.reset(new CodeGen::DatabaseGeneratorGrantlee(true));
|
||||
else if (action == QStringLiteral("dds_topics"))
|
||||
generator.reset(new CodeGen::CppTopicGeneratorGrantlee);
|
||||
else if (action == QStringLiteral("sql"))
|
||||
{
|
||||
CodeGen::SqlGenerator sql(reader.data(), structBuilder.data());
|
||||
if (!sql.generateData(35))
|
||||
return 8;
|
||||
|
||||
// .sql will be appended in method
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (!sql.generateData(42))
|
||||
return 8;
|
||||
|
||||
// .sql will be appended in method
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Exercise))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
|
||||
// recreate data for exercise independent statements
|
||||
sql.generateData(0);
|
||||
if (!sql.writeSql(dir.absolutePath() + QLatin1Char('/'), CodeGen::ExerciseDependency::Global))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while writing sql information for service " << sql.getServiceAbbr();
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Invalid action '" << options.action() << "' given!";
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (!generator->init(reader.data(), structBuilder.data()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing generator!";
|
||||
return 6;
|
||||
}
|
||||
|
||||
//INFO_LOG(m_logger) << "init generator ";
|
||||
//INFO_LOG(m_logger) << "########## options.arguments.size(): " << options.arguments().size();
|
||||
|
||||
const auto posArgs = options.positionalArguments();
|
||||
for (const QString &file : posArgs)
|
||||
{
|
||||
//INFO_LOG(m_logger) << "GenerateData for " << file;
|
||||
if (!generator->generateData(file, dir.absolutePath()))
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Gui to edit grantlee templates
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "main_grantlee_gui.h"
|
||||
#include "ui_main_grantlee_gui.h"
|
||||
#include "StructBuilder.h"
|
||||
#include "XmlReader.h"
|
||||
#include "CppTopicGeneratorGrantlee.h"
|
||||
#include "DatabaseGeneratorGrantlee.h"
|
||||
|
||||
#include <nglapplication/nglapplication.h>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <grantlee/engine.h>
|
||||
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, m_xmlReader(nullptr)
|
||||
, m_structBuilder(nullptr)
|
||||
, m_generator(new CodeGen::CppTopicGeneratorGrantlee)
|
||||
, m_engine(new Grantlee::Engine)
|
||||
, m_ui(new Ui_MainGrantleeGui)
|
||||
{
|
||||
m_idlServiceInfoFile = QStringLiteral("/home/chehrlic/TDS/TDS-build-product-clang/service_idl_files.txt");
|
||||
m_ui->setupUi(this);
|
||||
connect(m_ui->actionExit, &QAction::triggered,
|
||||
this, &MainWindow::close);
|
||||
connect(m_ui->actionSelect_Data_Source, &QAction::triggered,
|
||||
this, &MainWindow::onSelectDataSource);
|
||||
connect(m_ui->actionOpen_Template, &QAction::triggered,
|
||||
this, &MainWindow::onOpenTemplate);
|
||||
connect(m_ui->actionSave_Template, &QAction::triggered,
|
||||
this, &MainWindow::onSaveTemplate);
|
||||
connect(m_ui->pbRefresh, &QPushButton::clicked,
|
||||
this, &MainWindow::onRefreshOutput);
|
||||
connect(m_ui->actionDatabaseGenerator, &QAction::triggered,
|
||||
this, &MainWindow::onGeneratorDb);
|
||||
connect(m_ui->actionDDS_Generator, &QAction::triggered,
|
||||
this, &MainWindow::onGeneratorDds);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete m_xmlReader;
|
||||
delete m_structBuilder;
|
||||
delete m_generator;
|
||||
delete m_engine;
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
static QLatin1String s_startDir("/home/chehrlic/TDS/TDS-source-product/Lts/");
|
||||
|
||||
void MainWindow::onSelectDataSource()
|
||||
{
|
||||
const QString dataSource = QFileDialog::getOpenFileName(this, tr("Select data source"), s_startDir, tr("Service Files (*.xml)"));
|
||||
if (dataSource.isEmpty())
|
||||
return;
|
||||
delete m_xmlReader;
|
||||
m_xmlReader = new CodeGen::XmlReader;
|
||||
if (!m_xmlReader->readServiceFile(dataSource, m_idlServiceInfoFile))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid data source"), tr("The selected data source is not valid: %1").arg(m_xmlReader->errorString()));
|
||||
return;
|
||||
}
|
||||
delete m_structBuilder;
|
||||
m_structBuilder = new CodeGen::StructBuilder(m_xmlReader);
|
||||
if (!m_structBuilder->buildStructures())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid data source"), tr("Error building structures from data"));
|
||||
return;
|
||||
}
|
||||
m_ui->teOuput->clear();
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
QMessageBox::information(this, tr("Data source"), tr("Successfully loaded data source"));
|
||||
}
|
||||
|
||||
void MainWindow::onOpenTemplate()
|
||||
{
|
||||
const QString templateFile = QFileDialog::getOpenFileName(this, tr("Select data source"), s_startDir, tr("Templates (*.grantlee)"));
|
||||
if (templateFile.isEmpty())
|
||||
return;
|
||||
QFile f(templateFile);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error reading template file"), tr("Can not read file: %1").arg(f.errorString()));
|
||||
return;
|
||||
}
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
m_ui->teInput->setText(content);
|
||||
m_templateFile = templateFile;
|
||||
}
|
||||
|
||||
void MainWindow::onSaveTemplate()
|
||||
{
|
||||
QFile f(m_templateFile);
|
||||
if (!f.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error saving template file"), tr("Can not save file: %1").arg(f.errorString()));
|
||||
return;
|
||||
}
|
||||
f.write(m_ui->teInput->toPlainText().toUtf8());
|
||||
f.close();
|
||||
QMessageBox::information(this, tr("Saving template file"), tr("Successfully saved template to %1").arg(m_templateFile));
|
||||
}
|
||||
|
||||
void MainWindow::onRefreshOutput()
|
||||
{
|
||||
const QString in = m_ui->teInput->toPlainText();
|
||||
if (!m_generator->setTemplate(QString(), in))
|
||||
{
|
||||
m_ui->teOuput->setText(m_generator->errorString());
|
||||
return;
|
||||
}
|
||||
m_ui->teOuput->setText(m_generator->render());
|
||||
}
|
||||
|
||||
void MainWindow::onGeneratorDb()
|
||||
{
|
||||
if (dynamic_cast<CodeGen::DatabaseGeneratorGrantlee *>(m_generator))
|
||||
return;
|
||||
delete m_generator;
|
||||
m_generator = new CodeGen::DatabaseGeneratorGrantlee(false);
|
||||
if (m_xmlReader && m_structBuilder)
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
}
|
||||
|
||||
void MainWindow::onGeneratorDds()
|
||||
{
|
||||
if (dynamic_cast<CodeGen::CppTopicGeneratorGrantlee *>(m_generator))
|
||||
return;
|
||||
delete m_generator;
|
||||
m_generator = new CodeGen::CppTopicGeneratorGrantlee;
|
||||
if (m_xmlReader && m_structBuilder)
|
||||
m_generator->init(m_xmlReader, m_structBuilder);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLApplication app(argc, argv);
|
||||
app.createLogger("CodeGen", "codegen_log4cxx.props");
|
||||
|
||||
NGL::INGLLogger &m_logger = app.baseLogger();
|
||||
STARTUP_LOG(m_logger);
|
||||
|
||||
int iRet = 0;
|
||||
{
|
||||
QScopedPointer<MainWindow> mw(new MainWindow);
|
||||
mw->show();
|
||||
iRet = app.exec();
|
||||
}
|
||||
|
||||
SHUTDOWN_LOG(m_logger);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
Loaded 100 of 18662 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user